You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/monster/util/freelist.d

148 lines
3.8 KiB
D

/*
Monster - an advanced game scripting language
Copyright (C) 2007, 2008 Nicolay Korslund
Email: <korslund@gmail.com>
WWW: http://monster.snaptoad.com/
This file (freelist.d) is part of the Monster script language
package.
Monster is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
module monster.util.freelist;
// TODO: Create unittests
import monster.util.list;
import monster.util.growarray;
// This had to be moved outside FreeList to work around some
// irritating DMD template problems. (Can you say Aaargh!)
struct __FreeNode(T)
{
_lstNode!(T) data;
int index;
}
// A list that uses a freelist for allocation. Based on
// LinkedList. Very basic, only functions that are actually in use in
// my own code are implemented.
struct FreeList(T)
{
alias LinkedList!(T, NoAlloc) TList;
alias TList.Node TNode;
private:
/*
static struct _FreeNode
{
TNode data;
int index;
}
*/
alias __FreeNode!(T) _FreeNode;
// This is the array that does all the actual allocations. It is
// used for quickly looking up indices.
static GrowArray!(_FreeNode) array;
// The freelist. This is shared between all template instances of
// the same type, as far as I know. DMD might have some strange
// behavior that I am not aware of, but the worst case is that we
// end up with multiple freelists, which is not the end of the world
// (although slightly inefficient.)
static TList freeList;
// The nodes belonging to THIS list
TList nodes;
public:
// Get a new node (move from freelist to node list)
T* getNew()
{
// Is the freelist empty?
if(freeList.length == 0)
{
// Create a bunch of nodes and shove them into the freelist.
const makeSize = 100;
// Grow the growarray
uint len = array.length;
array.length = len + makeSize;
// Loop through the new nodes, number them, and insert them
// into freeList
for(int i=0; i < makeSize; i++)
{
_FreeNode *fn = array.getPtr(i+len);
fn.index = i + len;
freeList.insertNode(&fn.data);
}
}
// Move the first element from the freelist into the node list.
auto node = freeList.getHead;
freeList.removeNode(node);
nodes.insertNodeFirst(node);
// Return the value pointer. Since the value is always at the
// begining of the Node struct, this is the same
// pointer. LinkedList lets us choose if we want to use T* or
// Node*.
return &node.value;
}
// Get the node corresponding to an index
static T* getNode(int index)
{
return &array.getPtr(index).data.value;
}
// Get the index from a node
static int getIndex(T *node)
{
return ( cast(_FreeNode*)node ).index;
}
// Move a node back to the freelist ("delete" it)
void remove(T* node)
{
nodes.removeNode(node);
freeList.insertNodeFirst(node);
}
uint length() { return nodes.length; }
static uint totLength() { return array.length; }
// Move the given node to another list
T* moveTo(ref FreeList fl, T* node)
{
nodes.removeNode(node);
fl.nodes.insertNodeFirst(node);
return node;
}
// Get the first element in the list
T* getHead() { return &nodes.getHead().value; }
// Loop through the structs in this list
int opApply(int delegate(ref T) dg)
{
return nodes.opApply(dg);
}
}