mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2026-03-20 09:00:25 +01:00
Initial commit
This commit is contained in:
115
neo/idlib/containers/Array.h
Normal file
115
neo/idlib/containers/Array.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __ARRAY_H__
|
||||
#define __ARRAY_H__
|
||||
|
||||
/*
|
||||
================================================
|
||||
idArray is a replacement for a normal C array.
|
||||
|
||||
int myArray[ARRAY_SIZE];
|
||||
|
||||
becomes:
|
||||
|
||||
idArray<int,ARRAY_SIZE> myArray;
|
||||
|
||||
Has no performance overhead in release builds, but
|
||||
does index range checking in debug builds.
|
||||
|
||||
Unlike idTempArray, the memory is allocated inline with the
|
||||
object, rather than on the heap.
|
||||
|
||||
Unlike idStaticList, there are no fields other than the
|
||||
actual raw data, and the size is fixed.
|
||||
================================================
|
||||
*/
|
||||
template<class T_, int numElements > class idArray {
|
||||
public:
|
||||
// returns number of elements in list
|
||||
int Num() const { return numElements; }
|
||||
|
||||
// returns the number of bytes the array takes up
|
||||
int ByteSize() const { return sizeof( ptr ); }
|
||||
|
||||
// memset the entire array to zero
|
||||
void Zero() { memset( ptr, 0, sizeof( ptr ) ); }
|
||||
|
||||
// memset the entire array to a specific value
|
||||
void Memset( const char fill ) { memset( ptr, fill, numElements * sizeof( *ptr ) ); }
|
||||
|
||||
// array operators
|
||||
const T_ & operator[]( int index ) const { assert( (unsigned)index < (unsigned)numElements ); return ptr[index]; }
|
||||
T_ & operator[]( int index ) { assert( (unsigned)index < (unsigned)numElements ); return ptr[index]; }
|
||||
|
||||
// returns a pointer to the list
|
||||
const T_ * Ptr() const { return ptr; }
|
||||
T_ * Ptr() { return ptr; }
|
||||
|
||||
private:
|
||||
T_ ptr[numElements];
|
||||
};
|
||||
|
||||
#define ARRAY_COUNT( arrayName ) ( sizeof( arrayName )/sizeof( arrayName[0] ) )
|
||||
#define ARRAY_DEF( arrayName ) arrayName, ARRAY_COUNT( arrayName )
|
||||
|
||||
|
||||
/*
|
||||
================================================
|
||||
id2DArray is essentially a typedef (as close as we can
|
||||
get for templates before C++11 anyway) to make
|
||||
declaring two-dimensional idArrays easier.
|
||||
|
||||
Usage:
|
||||
id2DArray< int, 5, 10 >::type someArray;
|
||||
|
||||
================================================
|
||||
*/
|
||||
template<class _type_, int _dim1_, int _dim2_ >
|
||||
struct id2DArray {
|
||||
typedef idArray< idArray< _type_, _dim2_ >, _dim1_ > type;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
================================================
|
||||
idTupleSize
|
||||
Generic way to get the size of a tuple-like type.
|
||||
Add specializations as needed.
|
||||
This is modeled after std::tuple_size from C++11,
|
||||
which works for std::arrays also.
|
||||
================================================
|
||||
*/
|
||||
template< class _type_ >
|
||||
struct idTupleSize;
|
||||
|
||||
template< class _type_, int _num_ >
|
||||
struct idTupleSize< idArray< _type_, _num_ > > {
|
||||
enum { value = _num_ };
|
||||
};
|
||||
|
||||
#endif // !__ARRAY_H__
|
||||
573
neo/idlib/containers/BTree.h
Normal file
573
neo/idlib/containers/BTree.h
Normal file
@@ -0,0 +1,573 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __BTREE_H__
|
||||
#define __BTREE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Balanced Search Tree
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
//#define BTREE_CHECK
|
||||
|
||||
template< class objType, class keyType >
|
||||
class idBTreeNode {
|
||||
public:
|
||||
keyType key; // key used for sorting
|
||||
objType * object; // if != NULL pointer to object stored in leaf node
|
||||
idBTreeNode * parent; // parent node
|
||||
idBTreeNode * next; // next sibling
|
||||
idBTreeNode * prev; // prev sibling
|
||||
int numChildren; // number of children
|
||||
idBTreeNode * firstChild; // first child
|
||||
idBTreeNode * lastChild; // last child
|
||||
};
|
||||
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
class idBTree {
|
||||
public:
|
||||
idBTree();
|
||||
~idBTree();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
idBTreeNode<objType,keyType> * Add( objType *object, keyType key ); // add an object to the tree
|
||||
void Remove( idBTreeNode<objType,keyType> *node ); // remove an object node from the tree
|
||||
|
||||
idBTreeNode<objType,keyType> * NodeFind( keyType key ) const; // find an object using the given key
|
||||
idBTreeNode<objType,keyType> * NodeFindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key
|
||||
idBTreeNode<objType,keyType> * NodeFindLargestSmallerEqual( keyType key ) const; // find an object with the largest key smaller equal the given key
|
||||
|
||||
objType * Find( keyType key ) const; // find an object using the given key
|
||||
objType * FindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key
|
||||
objType * FindLargestSmallerEqual( keyType key ) const; // find an object with the largest key smaller equal the given key
|
||||
|
||||
idBTreeNode<objType,keyType> * GetRoot() const; // returns the root node of the tree
|
||||
int GetNodeCount() const; // returns the total number of nodes in the tree
|
||||
idBTreeNode<objType,keyType> * GetNext( idBTreeNode<objType,keyType> *node ) const; // goes through all nodes of the tree
|
||||
idBTreeNode<objType,keyType> * GetNextLeaf( idBTreeNode<objType,keyType> *node ) const; // goes through all leaf nodes of the tree
|
||||
|
||||
private:
|
||||
idBTreeNode<objType,keyType> * root;
|
||||
idBlockAlloc<idBTreeNode<objType,keyType>,128> nodeAllocator;
|
||||
|
||||
idBTreeNode<objType,keyType> * AllocNode();
|
||||
void FreeNode( idBTreeNode<objType,keyType> *node );
|
||||
void SplitNode( idBTreeNode<objType,keyType> *node );
|
||||
idBTreeNode<objType,keyType> * MergeNodes( idBTreeNode<objType,keyType> *node1, idBTreeNode<objType,keyType> *node2 );
|
||||
|
||||
void CheckTree_r( idBTreeNode<objType,keyType> *node, int &numNodes ) const;
|
||||
void CheckTree() const;
|
||||
};
|
||||
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTree<objType,keyType,maxChildrenPerNode>::idBTree() {
|
||||
assert( maxChildrenPerNode >= 4 );
|
||||
root = NULL;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTree<objType,keyType,maxChildrenPerNode>::~idBTree() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Init() {
|
||||
root = AllocNode();
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Shutdown() {
|
||||
nodeAllocator.Shutdown();
|
||||
root = NULL;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::Add( objType *object, keyType key ) {
|
||||
idBTreeNode<objType,keyType> *node, *child, *newNode;
|
||||
|
||||
if ( root == NULL ) {
|
||||
root = AllocNode();
|
||||
}
|
||||
|
||||
if ( root->numChildren >= maxChildrenPerNode ) {
|
||||
newNode = AllocNode();
|
||||
newNode->key = root->key;
|
||||
newNode->firstChild = root;
|
||||
newNode->lastChild = root;
|
||||
newNode->numChildren = 1;
|
||||
root->parent = newNode;
|
||||
SplitNode( root );
|
||||
root = newNode;
|
||||
}
|
||||
|
||||
newNode = AllocNode();
|
||||
newNode->key = key;
|
||||
newNode->object = object;
|
||||
|
||||
for ( node = root; node->firstChild != NULL; node = child ) {
|
||||
|
||||
if ( key > node->key ) {
|
||||
node->key = key;
|
||||
}
|
||||
|
||||
// find the first child with a key larger equal to the key of the new node
|
||||
for( child = node->firstChild; child->next; child = child->next ) {
|
||||
if ( key <= child->key ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( child->object ) {
|
||||
|
||||
if ( key <= child->key ) {
|
||||
// insert new node before child
|
||||
if ( child->prev ) {
|
||||
child->prev->next = newNode;
|
||||
} else {
|
||||
node->firstChild = newNode;
|
||||
}
|
||||
newNode->prev = child->prev;
|
||||
newNode->next = child;
|
||||
child->prev = newNode;
|
||||
} else {
|
||||
// insert new node after child
|
||||
if ( child->next ) {
|
||||
child->next->prev = newNode;
|
||||
} else {
|
||||
node->lastChild = newNode;
|
||||
}
|
||||
newNode->prev = child;
|
||||
newNode->next = child->next;
|
||||
child->next = newNode;
|
||||
}
|
||||
|
||||
newNode->parent = node;
|
||||
node->numChildren++;
|
||||
|
||||
#ifdef BTREE_CHECK
|
||||
CheckTree();
|
||||
#endif
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
// make sure the child has room to store another node
|
||||
if ( child->numChildren >= maxChildrenPerNode ) {
|
||||
SplitNode( child );
|
||||
if ( key <= child->prev->key ) {
|
||||
child = child->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we only end up here if the root node is empty
|
||||
newNode->parent = root;
|
||||
root->key = key;
|
||||
root->firstChild = newNode;
|
||||
root->lastChild = newNode;
|
||||
root->numChildren++;
|
||||
|
||||
#ifdef BTREE_CHECK
|
||||
CheckTree();
|
||||
#endif
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::Remove( idBTreeNode<objType,keyType> *node ) {
|
||||
idBTreeNode<objType,keyType> *parent;
|
||||
|
||||
assert( node->object != NULL );
|
||||
|
||||
// unlink the node from it's parent
|
||||
if ( node->prev ) {
|
||||
node->prev->next = node->next;
|
||||
} else {
|
||||
node->parent->firstChild = node->next;
|
||||
}
|
||||
if ( node->next ) {
|
||||
node->next->prev = node->prev;
|
||||
} else {
|
||||
node->parent->lastChild = node->prev;
|
||||
}
|
||||
node->parent->numChildren--;
|
||||
|
||||
// make sure there are no parent nodes with a single child
|
||||
for ( parent = node->parent; parent != root && parent->numChildren <= 1; parent = parent->parent ) {
|
||||
|
||||
if ( parent->next ) {
|
||||
parent = MergeNodes( parent, parent->next );
|
||||
} else if ( parent->prev ) {
|
||||
parent = MergeNodes( parent->prev, parent );
|
||||
}
|
||||
|
||||
// a parent may not use a key higher than the key of it's last child
|
||||
if ( parent->key > parent->lastChild->key ) {
|
||||
parent->key = parent->lastChild->key;
|
||||
}
|
||||
|
||||
if ( parent->numChildren > maxChildrenPerNode ) {
|
||||
SplitNode( parent );
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ( ; parent != NULL && parent->lastChild != NULL; parent = parent->parent ) {
|
||||
// a parent may not use a key higher than the key of it's last child
|
||||
if ( parent->key > parent->lastChild->key ) {
|
||||
parent->key = parent->lastChild->key;
|
||||
}
|
||||
}
|
||||
|
||||
// free the node
|
||||
FreeNode( node );
|
||||
|
||||
// remove the root node if it has a single internal node as child
|
||||
if ( root->numChildren == 1 && root->firstChild->object == NULL ) {
|
||||
idBTreeNode<objType,keyType> *oldRoot = root;
|
||||
root->firstChild->parent = NULL;
|
||||
root = root->firstChild;
|
||||
FreeNode( oldRoot );
|
||||
}
|
||||
|
||||
#ifdef BTREE_CHECK
|
||||
CheckTree();
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFind( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> *node;
|
||||
|
||||
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
|
||||
while( node->next ) {
|
||||
if ( node->key >= key ) {
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
if ( node->object ) {
|
||||
if ( node->key == key ) {
|
||||
return node;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFindSmallestLargerEqual( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> *node;
|
||||
|
||||
if ( root == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
|
||||
while( node->next ) {
|
||||
if ( node->key >= key ) {
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
if ( node->object ) {
|
||||
if ( node->key >= key ) {
|
||||
return node;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> * idBTree<objType,keyType,maxChildrenPerNode>::NodeFindLargestSmallerEqual( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> *node;
|
||||
|
||||
if ( root == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idBTreeNode<objType,keyType> * smaller = NULL;
|
||||
for ( node = root->firstChild; node != NULL; node = node->firstChild ) {
|
||||
while( node->next ) {
|
||||
if ( node->key >= key ) {
|
||||
break;
|
||||
}
|
||||
smaller = node;
|
||||
node = node->next;
|
||||
}
|
||||
if ( node->object ) {
|
||||
if ( node->key <= key ) {
|
||||
return node;
|
||||
} else if ( smaller == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
node = smaller;
|
||||
if ( node->object ) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::Find( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> * node = NodeFind( key );
|
||||
if ( node == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
return node->object;
|
||||
}
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::FindSmallestLargerEqual( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> * node = NodeFindSmallestLargerEqual( key );
|
||||
if ( node == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
return node->object;
|
||||
}
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE objType *idBTree<objType,keyType,maxChildrenPerNode>::FindLargestSmallerEqual( keyType key ) const {
|
||||
idBTreeNode<objType,keyType> * node = NodeFindLargestSmallerEqual( key );
|
||||
if ( node == NULL ) {
|
||||
return NULL;
|
||||
} else {
|
||||
return node->object;
|
||||
}
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetRoot() const {
|
||||
return root;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE int idBTree<objType,keyType,maxChildrenPerNode>::GetNodeCount() const {
|
||||
return nodeAllocator.GetAllocCount();
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetNext( idBTreeNode<objType,keyType> *node ) const {
|
||||
if ( node->firstChild ) {
|
||||
return node->firstChild;
|
||||
} else {
|
||||
while( node && node->next == NULL ) {
|
||||
node = node->parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::GetNextLeaf( idBTreeNode<objType,keyType> *node ) const {
|
||||
if ( node->firstChild ) {
|
||||
while ( node->firstChild ) {
|
||||
node = node->firstChild;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
while( node && node->next == NULL ) {
|
||||
node = node->parent;
|
||||
}
|
||||
if ( node ) {
|
||||
node = node->next;
|
||||
while ( node->firstChild ) {
|
||||
node = node->firstChild;
|
||||
}
|
||||
return node;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::AllocNode() {
|
||||
idBTreeNode<objType,keyType> *node = nodeAllocator.Alloc();
|
||||
node->key = 0;
|
||||
node->parent = NULL;
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
node->numChildren = 0;
|
||||
node->firstChild = NULL;
|
||||
node->lastChild = NULL;
|
||||
node->object = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::FreeNode( idBTreeNode<objType,keyType> *node ) {
|
||||
nodeAllocator.Free( node );
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::SplitNode( idBTreeNode<objType,keyType> *node ) {
|
||||
int i;
|
||||
idBTreeNode<objType,keyType> *child, *newNode;
|
||||
|
||||
// allocate a new node
|
||||
newNode = AllocNode();
|
||||
newNode->parent = node->parent;
|
||||
|
||||
// divide the children over the two nodes
|
||||
child = node->firstChild;
|
||||
child->parent = newNode;
|
||||
for ( i = 3; i < node->numChildren; i += 2 ) {
|
||||
child = child->next;
|
||||
child->parent = newNode;
|
||||
}
|
||||
|
||||
newNode->key = child->key;
|
||||
newNode->numChildren = node->numChildren / 2;
|
||||
newNode->firstChild = node->firstChild;
|
||||
newNode->lastChild = child;
|
||||
|
||||
node->numChildren -= newNode->numChildren;
|
||||
node->firstChild = child->next;
|
||||
|
||||
child->next->prev = NULL;
|
||||
child->next = NULL;
|
||||
|
||||
// add the new child to the parent before the split node
|
||||
assert( node->parent->numChildren < maxChildrenPerNode );
|
||||
|
||||
if ( node->prev ) {
|
||||
node->prev->next = newNode;
|
||||
} else {
|
||||
node->parent->firstChild = newNode;
|
||||
}
|
||||
newNode->prev = node->prev;
|
||||
newNode->next = node;
|
||||
node->prev = newNode;
|
||||
|
||||
node->parent->numChildren++;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE idBTreeNode<objType,keyType> *idBTree<objType,keyType,maxChildrenPerNode>::MergeNodes( idBTreeNode<objType,keyType> *node1, idBTreeNode<objType,keyType> *node2 ) {
|
||||
idBTreeNode<objType,keyType> *child;
|
||||
|
||||
assert( node1->parent == node2->parent );
|
||||
assert( node1->next == node2 && node2->prev == node1 );
|
||||
assert( node1->object == NULL && node2->object == NULL );
|
||||
assert( node1->numChildren >= 1 && node2->numChildren >= 1 );
|
||||
|
||||
for ( child = node1->firstChild; child->next; child = child->next ) {
|
||||
child->parent = node2;
|
||||
}
|
||||
child->parent = node2;
|
||||
child->next = node2->firstChild;
|
||||
node2->firstChild->prev = child;
|
||||
node2->firstChild = node1->firstChild;
|
||||
node2->numChildren += node1->numChildren;
|
||||
|
||||
// unlink the first node from the parent
|
||||
if ( node1->prev ) {
|
||||
node1->prev->next = node2;
|
||||
} else {
|
||||
node1->parent->firstChild = node2;
|
||||
}
|
||||
node2->prev = node1->prev;
|
||||
node2->parent->numChildren--;
|
||||
|
||||
FreeNode( node1 );
|
||||
|
||||
return node2;
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::CheckTree_r( idBTreeNode<objType,keyType> *node, int &numNodes ) const {
|
||||
int numChildren;
|
||||
idBTreeNode<objType,keyType> *child;
|
||||
|
||||
numNodes++;
|
||||
|
||||
// the root node may have zero children and leaf nodes always have zero children, all other nodes should have at least 2 and at most maxChildrenPerNode children
|
||||
assert( ( node == root ) || ( node->object != NULL && node->numChildren == 0 ) || ( node->numChildren >= 2 && node->numChildren <= maxChildrenPerNode ) );
|
||||
// the key of a node may never be larger than the key of it's last child
|
||||
assert( ( node->lastChild == NULL ) || ( node->key <= node->lastChild->key ) );
|
||||
|
||||
numChildren = 0;
|
||||
for ( child = node->firstChild; child; child = child->next ) {
|
||||
numChildren++;
|
||||
// make sure the children are properly linked
|
||||
if ( child->prev == NULL ) {
|
||||
assert( node->firstChild == child );
|
||||
} else {
|
||||
assert( child->prev->next == child );
|
||||
}
|
||||
if ( child->next == NULL ) {
|
||||
assert( node->lastChild == child );
|
||||
} else {
|
||||
assert( child->next->prev == child );
|
||||
}
|
||||
// recurse down the tree
|
||||
CheckTree_r( child, numNodes );
|
||||
}
|
||||
// the number of children should equal the number of linked children
|
||||
assert( numChildren == node->numChildren );
|
||||
}
|
||||
|
||||
template< class objType, class keyType, int maxChildrenPerNode >
|
||||
ID_INLINE void idBTree<objType,keyType,maxChildrenPerNode>::CheckTree() const {
|
||||
int numNodes = 0;
|
||||
idBTreeNode<objType,keyType> *node, *lastNode;
|
||||
|
||||
CheckTree_r( root, numNodes );
|
||||
|
||||
// the number of nodes in the tree should equal the number of allocated nodes
|
||||
assert( numNodes == nodeAllocator.GetAllocCount() );
|
||||
|
||||
// all the leaf nodes should be ordered
|
||||
lastNode = GetNextLeaf( GetRoot() );
|
||||
if ( lastNode ) {
|
||||
for ( node = GetNextLeaf( lastNode ); node; lastNode = node, node = GetNextLeaf( node ) ) {
|
||||
assert( lastNode->key <= node->key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__BTREE_H__ */
|
||||
138
neo/idlib/containers/BinSearch.h
Normal file
138
neo/idlib/containers/BinSearch.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __BINSEARCH_H__
|
||||
#define __BINSEARCH_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Binary Search templates
|
||||
|
||||
The array elements have to be ordered in increasing order.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
====================
|
||||
idBinSearch_GreaterEqual
|
||||
|
||||
Finds the last array element which is smaller than the given value.
|
||||
====================
|
||||
*/
|
||||
template< class type >
|
||||
ID_INLINE int idBinSearch_Less( const type *array, const int arraySize, const type &value ) {
|
||||
int len = arraySize;
|
||||
int mid = len;
|
||||
int offset = 0;
|
||||
while( mid > 0 ) {
|
||||
mid = len >> 1;
|
||||
if ( array[offset+mid] < value ) {
|
||||
offset += mid;
|
||||
}
|
||||
len -= mid;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idBinSearch_GreaterEqual
|
||||
|
||||
Finds the last array element which is smaller than or equal to the given value.
|
||||
====================
|
||||
*/
|
||||
template< class type >
|
||||
ID_INLINE int idBinSearch_LessEqual( const type *array, const int arraySize, const type &value ) {
|
||||
int len = arraySize;
|
||||
int mid = len;
|
||||
int offset = 0;
|
||||
while( mid > 0 ) {
|
||||
mid = len >> 1;
|
||||
if ( array[offset+mid] <= value ) {
|
||||
offset += mid;
|
||||
}
|
||||
len -= mid;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idBinSearch_Greater
|
||||
|
||||
Finds the first array element which is greater than the given value.
|
||||
====================
|
||||
*/
|
||||
template< class type >
|
||||
ID_INLINE int idBinSearch_Greater( const type *array, const int arraySize, const type &value ) {
|
||||
int len = arraySize;
|
||||
int mid = len;
|
||||
int offset = 0;
|
||||
int res = 0;
|
||||
while( mid > 0 ) {
|
||||
mid = len >> 1;
|
||||
if ( array[offset+mid] > value ) {
|
||||
res = 0;
|
||||
} else {
|
||||
offset += mid;
|
||||
res = 1;
|
||||
}
|
||||
len -= mid;
|
||||
}
|
||||
return offset+res;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idBinSearch_GreaterEqual
|
||||
|
||||
Finds the first array element which is greater than or equal to the given value.
|
||||
====================
|
||||
*/
|
||||
template< class type >
|
||||
ID_INLINE int idBinSearch_GreaterEqual( const type *array, const int arraySize, const type &value ) {
|
||||
int len = arraySize;
|
||||
int mid = len;
|
||||
int offset = 0;
|
||||
int res = 0;
|
||||
while( mid > 0 ) {
|
||||
mid = len >> 1;
|
||||
if ( array[offset+mid] >= value ) {
|
||||
res = 0;
|
||||
} else {
|
||||
offset += mid;
|
||||
res = 1;
|
||||
}
|
||||
len -= mid;
|
||||
}
|
||||
return offset+res;
|
||||
}
|
||||
|
||||
#endif /* !__BINSEARCH_H__ */
|
||||
155
neo/idlib/containers/HashIndex.cpp
Normal file
155
neo/idlib/containers/HashIndex.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../precompiled.h"
|
||||
|
||||
int idHashIndex::INVALID_INDEX[1] = { -1 };
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Init
|
||||
================
|
||||
*/
|
||||
void idHashIndex::Init( const int initialHashSize, const int initialIndexSize ) {
|
||||
assert( idMath::IsPowerOfTwo( initialHashSize ) );
|
||||
|
||||
hashSize = initialHashSize;
|
||||
hash = INVALID_INDEX;
|
||||
indexSize = initialIndexSize;
|
||||
indexChain = INVALID_INDEX;
|
||||
granularity = DEFAULT_HASH_GRANULARITY;
|
||||
hashMask = hashSize - 1;
|
||||
lookupMask = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Allocate
|
||||
================
|
||||
*/
|
||||
void idHashIndex::Allocate( const int newHashSize, const int newIndexSize ) {
|
||||
assert( idMath::IsPowerOfTwo( newHashSize ) );
|
||||
|
||||
Free();
|
||||
hashSize = newHashSize;
|
||||
hash = new (TAG_IDLIB_HASH) int[hashSize];
|
||||
memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
|
||||
indexSize = newIndexSize;
|
||||
indexChain = new (TAG_IDLIB_HASH) int[indexSize];
|
||||
memset( indexChain, 0xff, indexSize * sizeof( indexChain[0] ) );
|
||||
hashMask = hashSize - 1;
|
||||
lookupMask = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Free
|
||||
================
|
||||
*/
|
||||
void idHashIndex::Free() {
|
||||
if ( hash != INVALID_INDEX ) {
|
||||
delete[] hash;
|
||||
hash = INVALID_INDEX;
|
||||
}
|
||||
if ( indexChain != INVALID_INDEX ) {
|
||||
delete[] indexChain;
|
||||
indexChain = INVALID_INDEX;
|
||||
}
|
||||
lookupMask = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::ResizeIndex
|
||||
================
|
||||
*/
|
||||
void idHashIndex::ResizeIndex( const int newIndexSize ) {
|
||||
int *oldIndexChain, mod, newSize;
|
||||
|
||||
if ( newIndexSize <= indexSize ) {
|
||||
return;
|
||||
}
|
||||
|
||||
mod = newIndexSize % granularity;
|
||||
if ( !mod ) {
|
||||
newSize = newIndexSize;
|
||||
} else {
|
||||
newSize = newIndexSize + granularity - mod;
|
||||
}
|
||||
|
||||
if ( indexChain == INVALID_INDEX ) {
|
||||
indexSize = newSize;
|
||||
return;
|
||||
}
|
||||
|
||||
oldIndexChain = indexChain;
|
||||
indexChain = new (TAG_IDLIB_HASH) int[newSize];
|
||||
memcpy( indexChain, oldIndexChain, indexSize * sizeof(int) );
|
||||
memset( indexChain + indexSize, 0xff, (newSize - indexSize) * sizeof(int) );
|
||||
delete[] oldIndexChain;
|
||||
indexSize = newSize;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GetSpread
|
||||
================
|
||||
*/
|
||||
int idHashIndex::GetSpread() const {
|
||||
int i, index, totalItems, *numHashItems, average, error, e;
|
||||
|
||||
if ( hash == INVALID_INDEX ) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
totalItems = 0;
|
||||
numHashItems = new (TAG_IDLIB_HASH) int[hashSize];
|
||||
for ( i = 0; i < hashSize; i++ ) {
|
||||
numHashItems[i] = 0;
|
||||
for ( index = hash[i]; index >= 0; index = indexChain[index] ) {
|
||||
numHashItems[i]++;
|
||||
}
|
||||
totalItems += numHashItems[i];
|
||||
}
|
||||
// if no items in hash
|
||||
if ( totalItems <= 1 ) {
|
||||
delete[] numHashItems;
|
||||
return 100;
|
||||
}
|
||||
average = totalItems / hashSize;
|
||||
error = 0;
|
||||
for ( i = 0; i < hashSize; i++ ) {
|
||||
e = abs( numHashItems[i] - average );
|
||||
if ( e > 1 ) {
|
||||
error += e - 1;
|
||||
}
|
||||
}
|
||||
delete[] numHashItems;
|
||||
return 100 - (error * 100 / totalItems);
|
||||
}
|
||||
422
neo/idlib/containers/HashIndex.h
Normal file
422
neo/idlib/containers/HashIndex.h
Normal file
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HASHINDEX_H__
|
||||
#define __HASHINDEX_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Fast hash table for indexes and arrays.
|
||||
Does not allocate memory until the first key/index pair is added.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define DEFAULT_HASH_SIZE 1024
|
||||
#define DEFAULT_HASH_GRANULARITY 1024
|
||||
|
||||
class idHashIndex {
|
||||
public:
|
||||
static const int NULL_INDEX = -1;
|
||||
idHashIndex();
|
||||
idHashIndex( const int initialHashSize, const int initialIndexSize );
|
||||
~idHashIndex();
|
||||
|
||||
// returns total size of allocated memory
|
||||
size_t Allocated() const;
|
||||
// returns total size of allocated memory including size of hash index type
|
||||
size_t Size() const;
|
||||
|
||||
idHashIndex & operator=( const idHashIndex &other );
|
||||
// add an index to the hash, assumes the index has not yet been added to the hash
|
||||
void Add( const int key, const int index );
|
||||
// remove an index from the hash
|
||||
void Remove( const int key, const int index );
|
||||
// get the first index from the hash, returns -1 if empty hash entry
|
||||
int First( const int key ) const;
|
||||
// get the next index from the hash, returns -1 if at the end of the hash chain
|
||||
int Next( const int index ) const;
|
||||
|
||||
// For porting purposes...
|
||||
int GetFirst( const int key ) const { return First( key ); }
|
||||
int GetNext( const int index ) const { return Next( index ); }
|
||||
|
||||
// insert an entry into the index and add it to the hash, increasing all indexes >= index
|
||||
void InsertIndex( const int key, const int index );
|
||||
// remove an entry from the index and remove it from the hash, decreasing all indexes >= index
|
||||
void RemoveIndex( const int key, const int index );
|
||||
// clear the hash
|
||||
void Clear();
|
||||
// clear and resize
|
||||
void Clear( const int newHashSize, const int newIndexSize );
|
||||
// free allocated memory
|
||||
void Free();
|
||||
// get size of hash table
|
||||
int GetHashSize() const;
|
||||
// get size of the index
|
||||
int GetIndexSize() const;
|
||||
// set granularity
|
||||
void SetGranularity( const int newGranularity );
|
||||
// force resizing the index, current hash table stays intact
|
||||
void ResizeIndex( const int newIndexSize );
|
||||
// returns number in the range [0-100] representing the spread over the hash table
|
||||
int GetSpread() const;
|
||||
// returns a key for a string
|
||||
int GenerateKey( const char *string, bool caseSensitive = true ) const;
|
||||
// returns a key for a vector
|
||||
int GenerateKey( const idVec3 &v ) const;
|
||||
// returns a key for two integers
|
||||
int GenerateKey( const int n1, const int n2 ) const;
|
||||
// returns a key for a single integer
|
||||
int GenerateKey( const int n ) const;
|
||||
|
||||
private:
|
||||
int hashSize;
|
||||
int * hash;
|
||||
int indexSize;
|
||||
int * indexChain;
|
||||
int granularity;
|
||||
int hashMask;
|
||||
int lookupMask;
|
||||
|
||||
static int INVALID_INDEX[1];
|
||||
|
||||
void Init( const int initialHashSize, const int initialIndexSize );
|
||||
void Allocate( const int newHashSize, const int newIndexSize );
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::idHashIndex
|
||||
================
|
||||
*/
|
||||
ID_INLINE idHashIndex::idHashIndex() {
|
||||
Init( DEFAULT_HASH_SIZE, DEFAULT_HASH_SIZE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::idHashIndex
|
||||
================
|
||||
*/
|
||||
ID_INLINE idHashIndex::idHashIndex( const int initialHashSize, const int initialIndexSize ) {
|
||||
Init( initialHashSize, initialIndexSize );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::~idHashIndex
|
||||
================
|
||||
*/
|
||||
ID_INLINE idHashIndex::~idHashIndex() {
|
||||
Free();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Allocated
|
||||
================
|
||||
*/
|
||||
ID_INLINE size_t idHashIndex::Allocated() const {
|
||||
return hashSize * sizeof( int ) + indexSize * sizeof( int );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Size
|
||||
================
|
||||
*/
|
||||
ID_INLINE size_t idHashIndex::Size() const {
|
||||
return sizeof( *this ) + Allocated();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::operator=
|
||||
================
|
||||
*/
|
||||
ID_INLINE idHashIndex &idHashIndex::operator=( const idHashIndex &other ) {
|
||||
granularity = other.granularity;
|
||||
hashMask = other.hashMask;
|
||||
lookupMask = other.lookupMask;
|
||||
|
||||
if ( other.lookupMask == 0 ) {
|
||||
hashSize = other.hashSize;
|
||||
indexSize = other.indexSize;
|
||||
Free();
|
||||
}
|
||||
else {
|
||||
if ( other.hashSize != hashSize || hash == INVALID_INDEX ) {
|
||||
if ( hash != INVALID_INDEX ) {
|
||||
delete[] hash;
|
||||
}
|
||||
hashSize = other.hashSize;
|
||||
hash = new (TAG_IDLIB_HASH) int[hashSize];
|
||||
}
|
||||
if ( other.indexSize != indexSize || indexChain == INVALID_INDEX ) {
|
||||
if ( indexChain != INVALID_INDEX ) {
|
||||
delete[] indexChain;
|
||||
}
|
||||
indexSize = other.indexSize;
|
||||
indexChain = new (TAG_IDLIB_HASH) int[indexSize];
|
||||
}
|
||||
memcpy( hash, other.hash, hashSize * sizeof( hash[0] ) );
|
||||
memcpy( indexChain, other.indexChain, indexSize * sizeof( indexChain[0] ) );
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Add
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::Add( const int key, const int index ) {
|
||||
int h;
|
||||
|
||||
assert( index >= 0 );
|
||||
if ( hash == INVALID_INDEX ) {
|
||||
Allocate( hashSize, index >= indexSize ? index + 1 : indexSize );
|
||||
}
|
||||
else if ( index >= indexSize ) {
|
||||
ResizeIndex( index + 1 );
|
||||
}
|
||||
h = key & hashMask;
|
||||
indexChain[index] = hash[h];
|
||||
hash[h] = index;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Remove
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::Remove( const int key, const int index ) {
|
||||
int k = key & hashMask;
|
||||
|
||||
if ( hash == INVALID_INDEX ) {
|
||||
return;
|
||||
}
|
||||
if ( hash[k] == index ) {
|
||||
hash[k] = indexChain[index];
|
||||
}
|
||||
else {
|
||||
for ( int i = hash[k]; i != -1; i = indexChain[i] ) {
|
||||
if ( indexChain[i] == index ) {
|
||||
indexChain[i] = indexChain[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
indexChain[index] = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::First
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::First( const int key ) const {
|
||||
return hash[key & hashMask & lookupMask];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Next
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::Next( const int index ) const {
|
||||
assert( index >= 0 && index < indexSize );
|
||||
return indexChain[index & lookupMask];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::InsertIndex
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::InsertIndex( const int key, const int index ) {
|
||||
int i, max;
|
||||
|
||||
if ( hash != INVALID_INDEX ) {
|
||||
max = index;
|
||||
for ( i = 0; i < hashSize; i++ ) {
|
||||
if ( hash[i] >= index ) {
|
||||
hash[i]++;
|
||||
if ( hash[i] > max ) {
|
||||
max = hash[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( i = 0; i < indexSize; i++ ) {
|
||||
if ( indexChain[i] >= index ) {
|
||||
indexChain[i]++;
|
||||
if ( indexChain[i] > max ) {
|
||||
max = indexChain[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( max >= indexSize ) {
|
||||
ResizeIndex( max + 1 );
|
||||
}
|
||||
for ( i = max; i > index; i-- ) {
|
||||
indexChain[i] = indexChain[i-1];
|
||||
}
|
||||
indexChain[index] = -1;
|
||||
}
|
||||
Add( key, index );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::RemoveIndex
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::RemoveIndex( const int key, const int index ) {
|
||||
int i, max;
|
||||
|
||||
Remove( key, index );
|
||||
if ( hash != INVALID_INDEX ) {
|
||||
max = index;
|
||||
for ( i = 0; i < hashSize; i++ ) {
|
||||
if ( hash[i] >= index ) {
|
||||
if ( hash[i] > max ) {
|
||||
max = hash[i];
|
||||
}
|
||||
hash[i]--;
|
||||
}
|
||||
}
|
||||
for ( i = 0; i < indexSize; i++ ) {
|
||||
if ( indexChain[i] >= index ) {
|
||||
if ( indexChain[i] > max ) {
|
||||
max = indexChain[i];
|
||||
}
|
||||
indexChain[i]--;
|
||||
}
|
||||
}
|
||||
for ( i = index; i < max; i++ ) {
|
||||
indexChain[i] = indexChain[i+1];
|
||||
}
|
||||
indexChain[max] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Clear
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::Clear() {
|
||||
// only clear the hash table because clearing the indexChain is not really needed
|
||||
if ( hash != INVALID_INDEX ) {
|
||||
memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::Clear
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::Clear( const int newHashSize, const int newIndexSize ) {
|
||||
Free();
|
||||
hashSize = newHashSize;
|
||||
indexSize = newIndexSize;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GetHashSize
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GetHashSize() const {
|
||||
return hashSize;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GetIndexSize
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GetIndexSize() const {
|
||||
return indexSize;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::SetGranularity
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idHashIndex::SetGranularity( const int newGranularity ) {
|
||||
assert( newGranularity > 0 );
|
||||
granularity = newGranularity;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GenerateKey
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GenerateKey( const char *string, bool caseSensitive ) const {
|
||||
if ( caseSensitive ) {
|
||||
return ( idStr::Hash( string ) & hashMask );
|
||||
} else {
|
||||
return ( idStr::IHash( string ) & hashMask );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GenerateKey
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GenerateKey( const idVec3 &v ) const {
|
||||
return ( (((int) v[0]) + ((int) v[1]) + ((int) v[2])) & hashMask );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GenerateKey
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GenerateKey( const int n1, const int n2 ) const {
|
||||
return ( ( n1 + n2 ) & hashMask );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashIndex::GenerateKey
|
||||
================
|
||||
*/
|
||||
ID_INLINE int idHashIndex::GenerateKey( const int n ) const {
|
||||
return n & hashMask;
|
||||
}
|
||||
|
||||
#endif /* !__HASHINDEX_H__ */
|
||||
897
neo/idlib/containers/HashTable.h
Normal file
897
neo/idlib/containers/HashTable.h
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HASHTABLE_H__
|
||||
#define __HASHTABLE_H__
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
idHashNodeT is a generic node for a HashTable. It is specialized by the
|
||||
StringHashNode and CStringHashNode template classes.
|
||||
================================================================================================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
class idHashNodeT {
|
||||
public:
|
||||
idHashNodeT()
|
||||
: next( NULL ) {
|
||||
}
|
||||
|
||||
idHashNodeT( const _key_ & key, const _value_ & value, idHashNodeT * next )
|
||||
: key( key ),
|
||||
value( value ),
|
||||
next( next ) {
|
||||
}
|
||||
|
||||
static int GetHash( const _key_ & key, const int tableMask ) {
|
||||
return key & tableMask;
|
||||
}
|
||||
|
||||
static int Compare( const _key_ & key1, const _key_ & key2 ) {
|
||||
if ( key1 < key2 ) {
|
||||
return -1;
|
||||
} else if ( key1 > key2 ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
_key_ key;
|
||||
_value_ value;
|
||||
idHashNodeT< _key_, _value_ > * next;
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idHashNodeT is a HashNode that provides for partial
|
||||
specialization for the HashTable, allowing the String class's Cmp function to be used
|
||||
for inserting values in sorted order.
|
||||
================================================
|
||||
*/
|
||||
template< class _value_ >
|
||||
class idHashNodeT< idStr, _value_ > {
|
||||
public:
|
||||
idHashNodeT( const idStr & key, const _value_ & value, idHashNodeT * next )
|
||||
: key( key ),
|
||||
value( value ),
|
||||
next( next ) {
|
||||
}
|
||||
|
||||
static int GetHash( const idStr & key, const int tableMask ) {
|
||||
return ( idStr::Hash( key ) & tableMask );
|
||||
}
|
||||
|
||||
static int Compare( const idStr & key1, const idStr & key2 ) {
|
||||
return idStr::Icmp( key1, key2 );
|
||||
}
|
||||
|
||||
public:
|
||||
idStr key;
|
||||
_value_ value;
|
||||
idHashNodeT< idStr, _value_ > * next;
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idHashNodeT is a HashNode that provides for a partial specialization
|
||||
for the HashTable, allowing the String class's Cmp function to
|
||||
be used for inserting values in sorted order. It also ensures that a copy of the the key is
|
||||
stored in a String (to more closely model the original implementation of the HashTable).
|
||||
================================================
|
||||
*/
|
||||
template< class _value_ >
|
||||
class idHashNodeT< const char*, _value_ > {
|
||||
public:
|
||||
idHashNodeT( const char* const & key, const _value_ & value, idHashNodeT * next )
|
||||
: key( key ),
|
||||
value( value ),
|
||||
next( next ) {
|
||||
}
|
||||
|
||||
static int GetHash( const char* const & key, const int tableMask ) {
|
||||
return ( idStr::Hash( key ) & tableMask );
|
||||
}
|
||||
|
||||
static int Compare( const char* const & key1, const char* const & key2 ) {
|
||||
return idStr::Icmp( key1, key2 );
|
||||
}
|
||||
|
||||
public:
|
||||
idStr key; // char * keys must still get stored in an idStr
|
||||
_value_ value;
|
||||
idHashNodeT< const char *, _value_ > * next;
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idHashTableT is a general implementation of a hash table data type. It is
|
||||
slower than the HashIndex, but it can also be used for LinkedLists and other data structures,
|
||||
rather than just indexes and arrays.
|
||||
|
||||
It uses an arbitrary key type. For String keys, use the StringHashTable template
|
||||
specialization.
|
||||
================================================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
class idHashTableT {
|
||||
public:
|
||||
idHashTableT( const int tableSize = 256 );
|
||||
idHashTableT( const idHashTableT & other );
|
||||
~idHashTableT();
|
||||
|
||||
size_t Allocated() const;
|
||||
size_t Size() const;
|
||||
|
||||
_value_ & Set( const _key_ & key, const _value_ & value );
|
||||
|
||||
bool Get( const _key_ & key, _value_ ** value = NULL );
|
||||
bool Get( const _key_ & key, const _value_ ** value = NULL ) const;
|
||||
|
||||
bool Remove( const _key_ & key );
|
||||
|
||||
void Clear();
|
||||
void DeleteContents();
|
||||
|
||||
int Num() const;
|
||||
_value_ * GetIndex( const int index ) const;
|
||||
bool GetIndexKey( const int index, _key_ & key ) const;
|
||||
|
||||
int GetSpread() const;
|
||||
|
||||
idHashTableT & operator=( const idHashTableT & other );
|
||||
|
||||
protected:
|
||||
void Copy( const idHashTableT & other );
|
||||
|
||||
private:
|
||||
typedef idHashNodeT< _key_, _value_ > hashnode_t;
|
||||
|
||||
hashnode_t ** heads;
|
||||
|
||||
int tableSize;
|
||||
int numEntries;
|
||||
int tableSizeMask;
|
||||
};
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::idHashTableT
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const int tableSize ) {
|
||||
assert( idMath::IsPowerOfTwo( tableSize ) );
|
||||
|
||||
this->tableSize = tableSize;
|
||||
|
||||
heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ];
|
||||
memset( heads, 0, sizeof( hashnode_t * ) * tableSize );
|
||||
|
||||
numEntries = 0;
|
||||
tableSizeMask = tableSize - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::idHashTableT
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const idHashTableT & other ) {
|
||||
Copy( other );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::~idHashTableT
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE idHashTableT<_key_,_value_>::~idHashTableT() {
|
||||
Clear();
|
||||
delete [] heads;
|
||||
heads = NULL;
|
||||
tableSize = 0;
|
||||
tableSizeMask = 0;
|
||||
numEntries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Allocated
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE size_t idHashTableT<_key_,_value_>::Allocated() const {
|
||||
return sizeof( heads ) * tableSize + sizeof( hashnode_t* ) * numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Size
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE size_t idHashTableT<_key_,_value_>::Size() const {
|
||||
return sizeof( idHashTableT ) + sizeof( heads )* tableSize + sizeof( hashnode_t* ) * numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Set
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE _value_ & idHashTableT<_key_,_value_>::Set( const _key_ & key, const _value_ & value ) {
|
||||
// insert sorted
|
||||
int hash = hashnode_t::GetHash( key, tableSizeMask );
|
||||
hashnode_t ** nextPtr = &(heads[ hash ] );
|
||||
hashnode_t * node = * nextPtr;
|
||||
for ( ;
|
||||
node != NULL;
|
||||
nextPtr = &(node->next), node = *nextPtr ) {
|
||||
int s = node->Compare( node->key, key );
|
||||
if ( s == 0 ) {
|
||||
// return existing hashed item
|
||||
node->value = value;
|
||||
return node->value;
|
||||
}
|
||||
if ( s > 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
numEntries++;
|
||||
|
||||
*nextPtr = new (TAG_IDLIB_HASH) hashnode_t( key, value, heads[ hash ] );
|
||||
(*nextPtr)->next = node;
|
||||
return (*nextPtr)->value;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Get
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, _value_ ** value ) {
|
||||
int hash = hashnode_t::GetHash( key, tableSizeMask );
|
||||
hashnode_t * node = heads[ hash ];
|
||||
for ( ; node != NULL; node = node->next ) {
|
||||
int s = node->Compare( node->key, key );
|
||||
if ( s == 0 ) {
|
||||
if ( value ) {
|
||||
*value = &node->value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ( s > 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( value ) {
|
||||
*value = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Get
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, const _value_ ** value ) const {
|
||||
int hash = hashnode_t::GetHash( key, tableSizeMask );
|
||||
hashnode_t * node = heads[ hash ];
|
||||
for ( ; node != NULL; node = node->next ) {
|
||||
int s = node->Compare( node->key, key );
|
||||
if ( s == 0 ) {
|
||||
if ( value ) {
|
||||
*value = &node->value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ( s > 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( value ) {
|
||||
*value = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::GetIndex
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE _value_ * idHashTableT<_key_,_value_>::GetIndex( const int index ) const {
|
||||
if ( index < 0 || index > numEntries ) {
|
||||
assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
|
||||
if ( count == index ) {
|
||||
return &node->value;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::GetIndexKey
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE bool idHashTableT<_key_,_value_>::GetIndexKey( const int index, _key_ & key ) const {
|
||||
if ( index < 0 || index > numEntries ) {
|
||||
assert( 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
|
||||
if ( count == index ) {
|
||||
key = node->key;
|
||||
return true;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Remove
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE bool idHashTableT<_key_,_value_>::Remove( const _key_ & key ) {
|
||||
int hash = hashnode_t::GetHash( key, tableSizeMask );
|
||||
hashnode_t ** head = &heads[ hash ];
|
||||
if ( *head ) {
|
||||
hashnode_t * prev = NULL;
|
||||
hashnode_t * node = *head;
|
||||
for ( ; node != NULL; prev = node, node = node->next ) {
|
||||
if ( node->key == key ) {
|
||||
if ( prev ) {
|
||||
prev->next = node->next;
|
||||
} else {
|
||||
*head = node->next;
|
||||
}
|
||||
|
||||
delete node;
|
||||
numEntries--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Clear
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE void idHashTableT<_key_,_value_>::Clear() {
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
hashnode_t * next = heads[ i ];
|
||||
while ( next != NULL ) {
|
||||
hashnode_t * node = next;
|
||||
next = next->next;
|
||||
delete node;
|
||||
}
|
||||
heads[ i ] = NULL;
|
||||
}
|
||||
numEntries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::DeleteContents
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE void idHashTableT<_key_,_value_>::DeleteContents() {
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
hashnode_t * next = heads[ i ];
|
||||
while ( next != NULL ) {
|
||||
hashnode_t * node = next;
|
||||
next = next->next;
|
||||
delete node->value;
|
||||
delete node;
|
||||
}
|
||||
heads[ i ] = NULL;
|
||||
}
|
||||
numEntries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Num
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE int idHashTableT<_key_,_value_>::Num() const {
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::GetSpread
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE int idHashTableT<_key_,_value_>::GetSpread() const {
|
||||
if ( !numEntries ) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
int average = numEntries / tableSize;
|
||||
int error = 0;
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
int numItems = 0;
|
||||
for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) {
|
||||
numItems++;
|
||||
}
|
||||
int e = abs( numItems - average );
|
||||
if ( e > 1 ) {
|
||||
error += e - 1;
|
||||
}
|
||||
}
|
||||
return 100 - ( error * 100 / numEntries );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::operator=
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE idHashTableT< _key_, _value_ > & idHashTableT<_key_,_value_>::operator=( const idHashTableT & other ) {
|
||||
Copy( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idHashTableT<_key_,_value_>::Copy
|
||||
========================
|
||||
*/
|
||||
template< typename _key_, class _value_ >
|
||||
ID_INLINE void idHashTableT<_key_,_value_>::Copy( const idHashTableT & other ) {
|
||||
if ( &other == this ) {
|
||||
return;
|
||||
}
|
||||
assert( other.tableSize > 0 );
|
||||
|
||||
tableSize = other.tableSize;
|
||||
heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ];
|
||||
numEntries = other.numEntries;
|
||||
tableSizeMask = other.tableSizeMask;
|
||||
|
||||
for ( int i = 0; i < tableSize; i++ ) {
|
||||
if ( !other.heads[ i ] ) {
|
||||
heads[ i ] = NULL;
|
||||
continue;
|
||||
}
|
||||
hashnode_t ** prev = & heads[ i ];
|
||||
for ( hashnode_t * node = other.heads[ i ]; node != NULL; node = node->next ) {
|
||||
*prev = new (TAG_IDLIB_HASH) hashnode_t( node->key, node->value, NULL );
|
||||
prev = &( *prev )->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
General hash table. Slower than idHashIndex but it can also be used for
|
||||
linked lists and other data structures than just indexes or arrays.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
template< class Type >
|
||||
class idHashTable {
|
||||
public:
|
||||
idHashTable( int newtablesize = 256 );
|
||||
idHashTable( const idHashTable<Type> &map );
|
||||
~idHashTable();
|
||||
|
||||
// returns total size of allocated memory
|
||||
size_t Allocated() const;
|
||||
// returns total size of allocated memory including size of hash table type
|
||||
size_t Size() const;
|
||||
|
||||
void Set( const char *key, Type &value );
|
||||
bool Get( const char *key, Type **value = NULL ) const;
|
||||
bool Remove( const char *key );
|
||||
|
||||
void Clear();
|
||||
void DeleteContents();
|
||||
|
||||
// the entire contents can be itterated over, but note that the
|
||||
// exact index for a given element may change when new elements are added
|
||||
int Num() const;
|
||||
Type * GetIndex( int index ) const;
|
||||
|
||||
int GetSpread() const;
|
||||
|
||||
private:
|
||||
struct hashnode_s {
|
||||
idStr key;
|
||||
Type value;
|
||||
hashnode_s *next;
|
||||
|
||||
hashnode_s( const idStr &k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {};
|
||||
hashnode_s( const char *k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {};
|
||||
};
|
||||
|
||||
hashnode_s ** heads;
|
||||
|
||||
int tablesize;
|
||||
int numentries;
|
||||
int tablesizemask;
|
||||
|
||||
int GetHash( const char *key ) const;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::idHashTable
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE idHashTable<Type>::idHashTable( int newtablesize ) {
|
||||
|
||||
assert( idMath::IsPowerOfTwo( newtablesize ) );
|
||||
|
||||
tablesize = newtablesize;
|
||||
assert( tablesize > 0 );
|
||||
|
||||
heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ];
|
||||
memset( heads, 0, sizeof( *heads ) * tablesize );
|
||||
|
||||
numentries = 0;
|
||||
|
||||
tablesizemask = tablesize - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::idHashTable
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE idHashTable<Type>::idHashTable( const idHashTable<Type> &map ) {
|
||||
int i;
|
||||
hashnode_s *node;
|
||||
hashnode_s **prev;
|
||||
|
||||
assert( map.tablesize > 0 );
|
||||
|
||||
tablesize = map.tablesize;
|
||||
heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ];
|
||||
numentries = map.numentries;
|
||||
tablesizemask = map.tablesizemask;
|
||||
|
||||
for( i = 0; i < tablesize; i++ ) {
|
||||
if ( !map.heads[ i ] ) {
|
||||
heads[ i ] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
prev = &heads[ i ];
|
||||
for( node = map.heads[ i ]; node != NULL; node = node->next ) {
|
||||
*prev = new (TAG_IDLIB_HASH) hashnode_s( node->key, node->value, NULL );
|
||||
prev = &( *prev )->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::~idHashTable<Type>
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE idHashTable<Type>::~idHashTable() {
|
||||
Clear();
|
||||
delete[] heads;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Allocated
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE size_t idHashTable<Type>::Allocated() const {
|
||||
return sizeof( heads ) * tablesize + sizeof( *heads ) * numentries;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Size
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE size_t idHashTable<Type>::Size() const {
|
||||
return sizeof( idHashTable<Type> ) + sizeof( heads ) * tablesize + sizeof( *heads ) * numentries;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::GetHash
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE int idHashTable<Type>::GetHash( const char *key ) const {
|
||||
return ( idStr::Hash( key ) & tablesizemask );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Set
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE void idHashTable<Type>::Set( const char *key, Type &value ) {
|
||||
hashnode_s *node, **nextPtr;
|
||||
int hash, s;
|
||||
|
||||
hash = GetHash( key );
|
||||
for( nextPtr = &(heads[hash]), node = *nextPtr; node != NULL; nextPtr = &(node->next), node = *nextPtr ) {
|
||||
s = node->key.Cmp( key );
|
||||
if ( s == 0 ) {
|
||||
node->value = value;
|
||||
return;
|
||||
}
|
||||
if ( s > 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
numentries++;
|
||||
|
||||
*nextPtr = new (TAG_IDLIB_HASH) hashnode_s( key, value, heads[ hash ] );
|
||||
(*nextPtr)->next = node;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Get
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE bool idHashTable<Type>::Get( const char *key, Type **value ) const {
|
||||
hashnode_s *node;
|
||||
int hash, s;
|
||||
|
||||
hash = GetHash( key );
|
||||
for( node = heads[ hash ]; node != NULL; node = node->next ) {
|
||||
s = node->key.Cmp( key );
|
||||
if ( s == 0 ) {
|
||||
if ( value ) {
|
||||
*value = &node->value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ( s > 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( value ) {
|
||||
*value = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::GetIndex
|
||||
|
||||
the entire contents can be itterated over, but note that the
|
||||
exact index for a given element may change when new elements are added
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE Type *idHashTable<Type>::GetIndex( int index ) const {
|
||||
hashnode_s *node;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
if ( ( index < 0 ) || ( index > numentries ) ) {
|
||||
assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for( i = 0; i < tablesize; i++ ) {
|
||||
for( node = heads[ i ]; node != NULL; node = node->next ) {
|
||||
if ( count == index ) {
|
||||
return &node->value;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Remove
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE bool idHashTable<Type>::Remove( const char *key ) {
|
||||
hashnode_s **head;
|
||||
hashnode_s *node;
|
||||
hashnode_s *prev;
|
||||
int hash;
|
||||
|
||||
hash = GetHash( key );
|
||||
head = &heads[ hash ];
|
||||
if ( *head ) {
|
||||
for( prev = NULL, node = *head; node != NULL; prev = node, node = node->next ) {
|
||||
if ( node->key == key ) {
|
||||
if ( prev ) {
|
||||
prev->next = node->next;
|
||||
} else {
|
||||
*head = node->next;
|
||||
}
|
||||
|
||||
delete node;
|
||||
numentries--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Clear
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE void idHashTable<Type>::Clear() {
|
||||
int i;
|
||||
hashnode_s *node;
|
||||
hashnode_s *next;
|
||||
|
||||
for( i = 0; i < tablesize; i++ ) {
|
||||
next = heads[ i ];
|
||||
while( next != NULL ) {
|
||||
node = next;
|
||||
next = next->next;
|
||||
delete node;
|
||||
}
|
||||
|
||||
heads[ i ] = NULL;
|
||||
}
|
||||
|
||||
numentries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::DeleteContents
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE void idHashTable<Type>::DeleteContents() {
|
||||
int i;
|
||||
hashnode_s *node;
|
||||
hashnode_s *next;
|
||||
|
||||
for( i = 0; i < tablesize; i++ ) {
|
||||
next = heads[ i ];
|
||||
while( next != NULL ) {
|
||||
node = next;
|
||||
next = next->next;
|
||||
delete node->value;
|
||||
delete node;
|
||||
}
|
||||
|
||||
heads[ i ] = NULL;
|
||||
}
|
||||
|
||||
numentries = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::Num
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
ID_INLINE int idHashTable<Type>::Num() const {
|
||||
return numentries;
|
||||
}
|
||||
|
||||
#if defined(ID_TYPEINFO)
|
||||
#define __GNUC__ 99
|
||||
#endif
|
||||
|
||||
#if !defined(__GNUC__) || __GNUC__ < 4
|
||||
/*
|
||||
================
|
||||
idHashTable<Type>::GetSpread
|
||||
================
|
||||
*/
|
||||
template< class Type >
|
||||
int idHashTable<Type>::GetSpread() const {
|
||||
int i, average, error, e;
|
||||
hashnode_s *node;
|
||||
|
||||
// if no items in hash
|
||||
if ( !numentries ) {
|
||||
return 100;
|
||||
}
|
||||
average = numentries / tablesize;
|
||||
error = 0;
|
||||
for ( i = 0; i < tablesize; i++ ) {
|
||||
numItems = 0;
|
||||
for( node = heads[ i ]; node != NULL; node = node->next ) {
|
||||
numItems++;
|
||||
}
|
||||
e = abs( numItems - average );
|
||||
if ( e > 1 ) {
|
||||
error += e - 1;
|
||||
}
|
||||
}
|
||||
return 100 - (error * 100 / numentries);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ID_TYPEINFO)
|
||||
#undef __GNUC__
|
||||
#endif
|
||||
|
||||
#endif /* !__HASHTABLE_H__ */
|
||||
362
neo/idlib/containers/Hierarchy.h
Normal file
362
neo/idlib/containers/Hierarchy.h
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HIERARCHY_H__
|
||||
#define __HIERARCHY_H__
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
idHierarchy
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
template< class type >
|
||||
class idHierarchy {
|
||||
public:
|
||||
|
||||
idHierarchy();
|
||||
~idHierarchy();
|
||||
|
||||
void SetOwner( type *object );
|
||||
type * Owner() const;
|
||||
void ParentTo( idHierarchy &node );
|
||||
void MakeSiblingAfter( idHierarchy &node );
|
||||
bool ParentedBy( const idHierarchy &node ) const;
|
||||
void RemoveFromParent();
|
||||
void RemoveFromHierarchy();
|
||||
|
||||
type * GetParent() const; // parent of this node
|
||||
type * GetChild() const; // first child of this node
|
||||
type * GetSibling() const; // next node with the same parent
|
||||
type * GetPriorSibling() const; // previous node with the same parent
|
||||
type * GetNext() const; // goes through all nodes of the hierarchy
|
||||
type * GetNextLeaf() const; // goes through all leaf nodes of the hierarchy
|
||||
|
||||
private:
|
||||
idHierarchy * parent;
|
||||
idHierarchy * sibling;
|
||||
idHierarchy * child;
|
||||
type * owner;
|
||||
|
||||
idHierarchy<type> *GetPriorSiblingNode() const; // previous node with the same parent
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::idHierarchy
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idHierarchy<type>::idHierarchy() {
|
||||
owner = NULL;
|
||||
parent = NULL;
|
||||
sibling = NULL;
|
||||
child = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::~idHierarchy
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idHierarchy<type>::~idHierarchy() {
|
||||
RemoveFromHierarchy();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::Owner
|
||||
|
||||
Gets the object that is associated with this node.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::Owner() const {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::SetOwner
|
||||
|
||||
Sets the object that this node is associated with.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idHierarchy<type>::SetOwner( type *object ) {
|
||||
owner = object;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::ParentedBy
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
bool idHierarchy<type>::ParentedBy( const idHierarchy &node ) const {
|
||||
if ( parent == &node ) {
|
||||
return true;
|
||||
} else if ( parent ) {
|
||||
return parent->ParentedBy( node );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::ParentTo
|
||||
|
||||
Makes the given node the parent.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idHierarchy<type>::ParentTo( idHierarchy &node ) {
|
||||
RemoveFromParent();
|
||||
|
||||
parent = &node;
|
||||
sibling = node.child;
|
||||
node.child = this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::MakeSiblingAfter
|
||||
|
||||
Makes the given node a sibling after the passed in node.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idHierarchy<type>::MakeSiblingAfter( idHierarchy &node ) {
|
||||
RemoveFromParent();
|
||||
parent = node.parent;
|
||||
sibling = node.sibling;
|
||||
node.sibling = this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::RemoveFromParent
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idHierarchy<type>::RemoveFromParent() {
|
||||
idHierarchy<type> *prev;
|
||||
|
||||
if ( parent ) {
|
||||
prev = GetPriorSiblingNode();
|
||||
if ( prev ) {
|
||||
prev->sibling = sibling;
|
||||
} else {
|
||||
parent->child = sibling;
|
||||
}
|
||||
}
|
||||
|
||||
parent = NULL;
|
||||
sibling = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::RemoveFromHierarchy
|
||||
|
||||
Removes the node from the hierarchy and adds it's children to the parent.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idHierarchy<type>::RemoveFromHierarchy() {
|
||||
idHierarchy<type> *parentNode;
|
||||
idHierarchy<type> *node;
|
||||
|
||||
parentNode = parent;
|
||||
RemoveFromParent();
|
||||
|
||||
if ( parentNode ) {
|
||||
while( child ) {
|
||||
node = child;
|
||||
node->RemoveFromParent();
|
||||
node->ParentTo( *parentNode );
|
||||
}
|
||||
} else {
|
||||
while( child ) {
|
||||
child->RemoveFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetParent
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetParent() const {
|
||||
if ( parent ) {
|
||||
return parent->owner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetChild
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetChild() const {
|
||||
if ( child ) {
|
||||
return child->owner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetSibling
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetSibling() const {
|
||||
if ( sibling ) {
|
||||
return sibling->owner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetPriorSiblingNode
|
||||
|
||||
Returns NULL if no parent, or if it is the first child.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idHierarchy<type> *idHierarchy<type>::GetPriorSiblingNode() const {
|
||||
if ( !parent || ( parent->child == this ) ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idHierarchy<type> *prev;
|
||||
idHierarchy<type> *node;
|
||||
|
||||
node = parent->child;
|
||||
prev = NULL;
|
||||
while( ( node != this ) && ( node != NULL ) ) {
|
||||
prev = node;
|
||||
node = node->sibling;
|
||||
}
|
||||
|
||||
if ( node != this ) {
|
||||
idLib::Error( "idHierarchy::GetPriorSibling: could not find node in parent's list of children" );
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetPriorSibling
|
||||
|
||||
Returns NULL if no parent, or if it is the first child.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetPriorSibling() const {
|
||||
idHierarchy<type> *prior;
|
||||
|
||||
prior = GetPriorSiblingNode();
|
||||
if ( prior ) {
|
||||
return prior->owner;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetNext
|
||||
|
||||
Goes through all nodes of the hierarchy.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetNext() const {
|
||||
const idHierarchy<type> *node;
|
||||
|
||||
if ( child ) {
|
||||
return child->owner;
|
||||
} else {
|
||||
node = this;
|
||||
while( node && node->sibling == NULL ) {
|
||||
node = node->parent;
|
||||
}
|
||||
if ( node ) {
|
||||
return node->sibling->owner;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idHierarchy<type>::GetNextLeaf
|
||||
|
||||
Goes through all leaf nodes of the hierarchy.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idHierarchy<type>::GetNextLeaf() const {
|
||||
const idHierarchy<type> *node;
|
||||
|
||||
if ( child ) {
|
||||
node = child;
|
||||
while ( node->child ) {
|
||||
node = node->child;
|
||||
}
|
||||
return node->owner;
|
||||
} else {
|
||||
node = this;
|
||||
while( node && node->sibling == NULL ) {
|
||||
node = node->parent;
|
||||
}
|
||||
if ( node ) {
|
||||
node = node->sibling;
|
||||
while ( node->child ) {
|
||||
node = node->child;
|
||||
}
|
||||
return node->owner;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__HIERARCHY_H__ */
|
||||
343
neo/idlib/containers/LinkList.h
Normal file
343
neo/idlib/containers/LinkList.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __LINKLIST_H__
|
||||
#define __LINKLIST_H__
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
idLinkList
|
||||
|
||||
Circular linked list template
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
template< class type >
|
||||
class idLinkList {
|
||||
public:
|
||||
idLinkList();
|
||||
~idLinkList();
|
||||
|
||||
bool IsListEmpty() const;
|
||||
bool InList() const;
|
||||
int Num() const;
|
||||
void Clear();
|
||||
|
||||
void InsertBefore( idLinkList &node );
|
||||
void InsertAfter( idLinkList &node );
|
||||
void AddToEnd( idLinkList &node );
|
||||
void AddToFront( idLinkList &node );
|
||||
|
||||
void Remove();
|
||||
|
||||
type * Next() const;
|
||||
type * Prev() const;
|
||||
|
||||
type * Owner() const;
|
||||
void SetOwner( type *object );
|
||||
|
||||
idLinkList * ListHead() const;
|
||||
idLinkList * NextNode() const;
|
||||
idLinkList * PrevNode() const;
|
||||
|
||||
private:
|
||||
idLinkList * head;
|
||||
idLinkList * next;
|
||||
idLinkList * prev;
|
||||
type * owner;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::idLinkList
|
||||
|
||||
Node is initialized to be the head of an empty list
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idLinkList<type>::idLinkList() {
|
||||
owner = NULL;
|
||||
head = this;
|
||||
next = this;
|
||||
prev = this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::~idLinkList
|
||||
|
||||
Removes the node from the list, or if it's the head of a list, removes
|
||||
all the nodes from the list.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idLinkList<type>::~idLinkList() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::IsListEmpty
|
||||
|
||||
Returns true if the list is empty.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
bool idLinkList<type>::IsListEmpty() const {
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::InList
|
||||
|
||||
Returns true if the node is in a list. If called on the head of a list, will always return false.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
bool idLinkList<type>::InList() const {
|
||||
return head != this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Num
|
||||
|
||||
Returns the number of nodes in the list.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
int idLinkList<type>::Num() const {
|
||||
idLinkList<type> *node;
|
||||
int num;
|
||||
|
||||
num = 0;
|
||||
for( node = head->next; node != head; node = node->next ) {
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Clear
|
||||
|
||||
If node is the head of the list, clears the list. Otherwise it just removes the node from the list.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::Clear() {
|
||||
if ( head == this ) {
|
||||
while( next != this ) {
|
||||
next->Remove();
|
||||
}
|
||||
} else {
|
||||
Remove();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Remove
|
||||
|
||||
Removes node from list
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::Remove() {
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
|
||||
next = this;
|
||||
prev = this;
|
||||
head = this;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::InsertBefore
|
||||
|
||||
Places the node before the existing node in the list. If the existing node is the head,
|
||||
then the new node is placed at the end of the list.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::InsertBefore( idLinkList &node ) {
|
||||
Remove();
|
||||
|
||||
next = &node;
|
||||
prev = node.prev;
|
||||
node.prev = this;
|
||||
prev->next = this;
|
||||
head = node.head;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::InsertAfter
|
||||
|
||||
Places the node after the existing node in the list. If the existing node is the head,
|
||||
then the new node is placed at the beginning of the list.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::InsertAfter( idLinkList &node ) {
|
||||
Remove();
|
||||
|
||||
prev = &node;
|
||||
next = node.next;
|
||||
node.next = this;
|
||||
next->prev = this;
|
||||
head = node.head;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::AddToEnd
|
||||
|
||||
Adds node at the end of the list
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::AddToEnd( idLinkList &node ) {
|
||||
InsertBefore( *node.head );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::AddToFront
|
||||
|
||||
Adds node at the beginning of the list
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::AddToFront( idLinkList &node ) {
|
||||
InsertAfter( *node.head );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::ListHead
|
||||
|
||||
Returns the head of the list. If the node isn't in a list, it returns
|
||||
a pointer to itself.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idLinkList<type> *idLinkList<type>::ListHead() const {
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Next
|
||||
|
||||
Returns the next object in the list, or NULL if at the end.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idLinkList<type>::Next() const {
|
||||
if ( !next || ( next == head ) ) {
|
||||
return NULL;
|
||||
}
|
||||
return next->owner;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Prev
|
||||
|
||||
Returns the previous object in the list, or NULL if at the beginning.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idLinkList<type>::Prev() const {
|
||||
if ( !prev || ( prev == head ) ) {
|
||||
return NULL;
|
||||
}
|
||||
return prev->owner;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::NextNode
|
||||
|
||||
Returns the next node in the list, or NULL if at the end.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idLinkList<type> *idLinkList<type>::NextNode() const {
|
||||
if ( next == head ) {
|
||||
return NULL;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::PrevNode
|
||||
|
||||
Returns the previous node in the list, or NULL if at the beginning.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
idLinkList<type> *idLinkList<type>::PrevNode() const {
|
||||
if ( prev == head ) {
|
||||
return NULL;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::Owner
|
||||
|
||||
Gets the object that is associated with this node.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
type *idLinkList<type>::Owner() const {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idLinkList<type>::SetOwner
|
||||
|
||||
Sets the object that this node is associated with.
|
||||
================
|
||||
*/
|
||||
template< class type >
|
||||
void idLinkList<type>::SetOwner( type *object ) {
|
||||
owner = object;
|
||||
}
|
||||
|
||||
#endif /* !__LINKLIST_H__ */
|
||||
1037
neo/idlib/containers/List.h
Normal file
1037
neo/idlib/containers/List.h
Normal file
File diff suppressed because it is too large
Load Diff
81
neo/idlib/containers/PlaneSet.h
Normal file
81
neo/idlib/containers/PlaneSet.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __PLANESET_H__
|
||||
#define __PLANESET_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Plane Set
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idPlaneSet : public idList<idPlane> {
|
||||
public:
|
||||
|
||||
void Clear() { idList<idPlane>::Clear(); hash.Free(); }
|
||||
|
||||
int FindPlane( const idPlane &plane, const float normalEps, const float distEps );
|
||||
|
||||
private:
|
||||
idHashIndex hash;
|
||||
};
|
||||
|
||||
ID_INLINE int idPlaneSet::FindPlane( const idPlane &plane, const float normalEps, const float distEps ) {
|
||||
int i, border, hashKey;
|
||||
|
||||
assert( distEps <= 0.125f );
|
||||
|
||||
hashKey = (int)( idMath::Fabs( plane.Dist() ) * 0.125f );
|
||||
for ( border = -1; border <= 1; border++ ) {
|
||||
for ( i = hash.First( hashKey + border ); i >= 0; i = hash.Next( i ) ) {
|
||||
if ( (*this)[i].Compare( plane, normalEps, distEps ) ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( plane.Type() >= PLANETYPE_NEGX && plane.Type() < PLANETYPE_TRUEAXIAL ) {
|
||||
Append( -plane );
|
||||
hash.Add( hashKey, Num()-1 );
|
||||
Append( plane );
|
||||
hash.Add( hashKey, Num()-1 );
|
||||
return ( Num() - 1 );
|
||||
}
|
||||
else {
|
||||
Append( plane );
|
||||
hash.Add( hashKey, Num()-1 );
|
||||
Append( -plane );
|
||||
hash.Add( hashKey, Num()-1 );
|
||||
return ( Num() - 2 );
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__PLANESET_H__ */
|
||||
211
neo/idlib/containers/Queue.h
Normal file
211
neo/idlib/containers/Queue.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __QUEUE_H__
|
||||
#define __QUEUE_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Queue template
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
template< class type, int nextOffset >
|
||||
class idQueueTemplate {
|
||||
public:
|
||||
idQueueTemplate();
|
||||
|
||||
void Add( type *element );
|
||||
type * Get();
|
||||
|
||||
private:
|
||||
type * first;
|
||||
type * last;
|
||||
};
|
||||
|
||||
#define QUEUE_NEXT_PTR( element ) (*((type**)(((byte*)element)+nextOffset)))
|
||||
|
||||
template< class type, int nextOffset >
|
||||
idQueueTemplate<type,nextOffset>::idQueueTemplate() {
|
||||
first = last = NULL;
|
||||
}
|
||||
|
||||
template< class type, int nextOffset >
|
||||
void idQueueTemplate<type,nextOffset>::Add( type *element ) {
|
||||
QUEUE_NEXT_PTR(element) = NULL;
|
||||
if ( last ) {
|
||||
QUEUE_NEXT_PTR(last) = element;
|
||||
} else {
|
||||
first = element;
|
||||
}
|
||||
last = element;
|
||||
}
|
||||
|
||||
template< class type, int nextOffset >
|
||||
type *idQueueTemplate<type,nextOffset>::Get() {
|
||||
type *element;
|
||||
|
||||
element = first;
|
||||
if ( element ) {
|
||||
first = QUEUE_NEXT_PTR(first);
|
||||
if ( last == element ) {
|
||||
last = NULL;
|
||||
}
|
||||
QUEUE_NEXT_PTR(element) = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/*
|
||||
================================================
|
||||
A node of a Queue
|
||||
================================================
|
||||
*/
|
||||
template< typename type >
|
||||
class idQueueNode {
|
||||
public:
|
||||
idQueueNode() { next = NULL; }
|
||||
|
||||
type * GetNext() const { return next; }
|
||||
void SetNext( type *next ) { this->next = next; }
|
||||
|
||||
private:
|
||||
type * next;
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
A Queue, idQueue, is a template Container class implementing the Queue abstract data
|
||||
type.
|
||||
================================================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
class idQueue {
|
||||
public:
|
||||
idQueue();
|
||||
|
||||
void Add( type *element );
|
||||
type * RemoveFirst();
|
||||
type * Peek() const;
|
||||
bool IsEmpty();
|
||||
|
||||
static void Test();
|
||||
|
||||
private:
|
||||
type * first;
|
||||
type * last;
|
||||
};
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::idQueue
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
idQueue<type,nodePtr>::idQueue() {
|
||||
first = last = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::Add
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
void idQueue<type,nodePtr>::Add( type *element ) {
|
||||
(element->*nodePtr).SetNext( NULL );
|
||||
if ( last ) {
|
||||
(last->*nodePtr).SetNext( element );
|
||||
} else {
|
||||
first = element;
|
||||
}
|
||||
last = element;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::RemoveFirst
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
type *idQueue<type,nodePtr>::RemoveFirst() {
|
||||
type *element;
|
||||
|
||||
element = first;
|
||||
if ( element ) {
|
||||
first = (first->*nodePtr).GetNext();
|
||||
if ( last == element ) {
|
||||
last = NULL;
|
||||
}
|
||||
(element->*nodePtr).SetNext( NULL );
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::Peek
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
type *idQueue<type,nodePtr>::Peek() const {
|
||||
return first;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::IsEmpty
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
bool idQueue<type,nodePtr>::IsEmpty() {
|
||||
return ( first == NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idQueue<type,nodePtr>::Test
|
||||
========================
|
||||
*/
|
||||
template< typename type, idQueueNode<type> type::*nodePtr >
|
||||
void idQueue<type,nodePtr>::Test() {
|
||||
|
||||
class idMyType {
|
||||
public:
|
||||
idQueueNode<idMyType> queueNode;
|
||||
};
|
||||
|
||||
idQueue<idMyType,&idMyType::queueNode> myQueue;
|
||||
|
||||
idMyType *element = new (TAG_IDLIB) idMyType;
|
||||
myQueue.Add( element );
|
||||
element = myQueue.RemoveFirst();
|
||||
delete element;
|
||||
}
|
||||
|
||||
#endif // !__QUEUE_H__
|
||||
338
neo/idlib/containers/Sort.h
Normal file
338
neo/idlib/containers/Sort.h
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
#ifndef __SORT_H__
|
||||
#define __SORT_H__
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
Contains the generic templated sort algorithms for quick-sort, heap-sort and insertion-sort.
|
||||
|
||||
The sort algorithms do not use class operators or overloaded functions to compare
|
||||
objects because it is often desireable to sort the same objects in different ways
|
||||
based on different keys (not just ascending and descending but sometimes based on
|
||||
name and other times based on say priority). So instead, for each different sort a
|
||||
separate class is implemented with a Compare() function.
|
||||
|
||||
This class is derived from one of the classes that implements a sort algorithm.
|
||||
The Compare() member function does not only define how objects are sorted, the class
|
||||
can also store additional data that can be used by the Compare() function. This, for
|
||||
instance, allows a list of indices to be sorted where the indices point to objects
|
||||
in an array. The base pointer of the array with objects can be stored on the class
|
||||
that implements the Compare() function such that the Compare() function can use keys
|
||||
that are stored on the objects.
|
||||
|
||||
The Compare() function is not virtual because this would incur significant overhead.
|
||||
Do NOT make the Compare() function virtual on the derived class!
|
||||
The sort implementations also explicitely call the Compare() function of the derived
|
||||
class. This is to avoid various compiler bugs with using overloaded compare functions
|
||||
and the inability of various compilers to find the right overloaded compare function.
|
||||
|
||||
To sort an array, an idList or an idStaticList, a new sort class, typically derived from
|
||||
idSort_Quick, is implemented as follows:
|
||||
|
||||
class idSort_MySort : public idSort_Quick< idMyObject, idSort_MySort > {
|
||||
public:
|
||||
int Compare( const idMyObject & a, const idMyObject & b ) const {
|
||||
if ( a should come before b ) {
|
||||
return -1; // or any negative integer
|
||||
} if ( a should come after b ) {
|
||||
return 1; // or any positive integer
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
To sort an array:
|
||||
|
||||
idMyObject array[100];
|
||||
idSort_MySort().Sort( array, 100 );
|
||||
|
||||
To sort an idList:
|
||||
|
||||
idList< idMyObject > list;
|
||||
list.Sort( idSort_MySort() );
|
||||
|
||||
The sort implementations never create temporaries of the template type. Only the
|
||||
'SwapValues' template is used to move data around. This 'SwapValues' template can be
|
||||
specialized to implement fast swapping of data. For instance, when sorting a list with
|
||||
objects of some string class it is important to implement a specialized 'SwapValues' for
|
||||
this string class to avoid excessive re-allocation and copying of strings.
|
||||
|
||||
================================================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
========================
|
||||
SwapValues
|
||||
========================
|
||||
*/
|
||||
template< typename _type_ >
|
||||
ID_INLINE void SwapValues( _type_ & a, _type_ & b ) {
|
||||
_type_ c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
|
||||
/*
|
||||
================================================
|
||||
idSort is an abstract template class for sorting an array of objects of the specified data type.
|
||||
The array of objects is sorted such that: Compare( array[i], array[i+1] ) <= 0 for all i
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_ >
|
||||
class idSort {
|
||||
public:
|
||||
virtual ~idSort() {}
|
||||
virtual void Sort( _type_ * base, unsigned int num ) const = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idSort_Quick is a sort template that implements the
|
||||
quick-sort algorithm on an array of objects of the specified data type.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_, typename _derived_ >
|
||||
class idSort_Quick : public idSort< _type_ > {
|
||||
public:
|
||||
virtual void Sort( _type_ * base, unsigned int num ) const {
|
||||
if ( num <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64 MAX_LEVELS = 128;
|
||||
int64 lo[MAX_LEVELS], hi[MAX_LEVELS];
|
||||
|
||||
// 'lo' is the lower index, 'hi' is the upper index
|
||||
// of the region of the array that is being sorted.
|
||||
lo[0] = 0;
|
||||
hi[0] = num - 1;
|
||||
|
||||
for ( int64 level = 0; level >= 0; ) {
|
||||
int64 i = lo[level];
|
||||
int64 j = hi[level];
|
||||
|
||||
// Only use quick-sort when there are 4 or more elements in this region and we are below MAX_LEVELS.
|
||||
// Otherwise fall back to an insertion-sort.
|
||||
if ( ( ( j - i ) >= 4 ) && ( level < ( MAX_LEVELS - 1 ) ) ) {
|
||||
|
||||
// Use the center element as the pivot.
|
||||
// The median of a multi point sample could be used
|
||||
// but simply taking the center works quite well.
|
||||
int64 pi = ( i + j ) / 2;
|
||||
|
||||
// Move the pivot element to the end of the region.
|
||||
SwapValues( base[j], base[pi] );
|
||||
|
||||
// Get a reference to the pivot element.
|
||||
_type_ & pivot = base[j--];
|
||||
|
||||
// Partition the region.
|
||||
do {
|
||||
while( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) < 0 ) { if ( ++i >= j ) break; }
|
||||
while( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) > 0 ) { if ( --j <= i ) break; }
|
||||
if ( i >= j ) break;
|
||||
SwapValues( base[i], base[j] );
|
||||
} while( ++i < --j );
|
||||
|
||||
// Without these iterations sorting of arrays with many duplicates may
|
||||
// become really slow because the partitioning can be very unbalanced.
|
||||
// However, these iterations are unnecessary if all elements are unique.
|
||||
while ( static_cast< const _derived_ * >( this )->Compare( base[i], pivot ) <= 0 && i < hi[level] ) { i++; }
|
||||
while ( static_cast< const _derived_ * >( this )->Compare( base[j], pivot ) >= 0 && lo[level] < j ) { j--; }
|
||||
|
||||
// Move the pivot element in place.
|
||||
SwapValues( pivot, base[i] );
|
||||
|
||||
assert( level < MAX_LEVELS - 1 );
|
||||
lo[level+1] = i;
|
||||
hi[level+1] = hi[level];
|
||||
hi[level] = j;
|
||||
level++;
|
||||
|
||||
} else {
|
||||
|
||||
// Insertion-sort of the remaining elements.
|
||||
for( ; i < j; j-- ) {
|
||||
int64 m = i;
|
||||
for ( int64 k = i + 1; k <= j; k++ ) {
|
||||
if ( static_cast< const _derived_ * >( this )->Compare( base[k], base[m] ) > 0 ) {
|
||||
m = k;
|
||||
}
|
||||
}
|
||||
SwapValues( base[m], base[j] );
|
||||
}
|
||||
level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
Default quick-sort comparison function that can
|
||||
be used to sort scalars from small to large.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_ >
|
||||
class idSort_QuickDefault : public idSort_Quick< _type_, idSort_QuickDefault< _type_ > > {
|
||||
public:
|
||||
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
Specialization for floating point values to avoid an float-to-int
|
||||
conversion for every comparison.
|
||||
================================================
|
||||
*/
|
||||
template<>
|
||||
class idSort_QuickDefault< float > : public idSort_Quick< float, idSort_QuickDefault< float > > {
|
||||
public:
|
||||
int Compare( const float & a, const float & b ) const {
|
||||
if ( a < b ) {
|
||||
return -1;
|
||||
}
|
||||
if ( a > b ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idSort_Heap is a sort template class that implements the
|
||||
heap-sort algorithm on an array of objects of the specified data type.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_, typename _derived_ >
|
||||
class idSort_Heap : public idSort< _type_ > {
|
||||
public:
|
||||
virtual void Sort( _type_ * base, unsigned int num ) const {
|
||||
// get all elements in heap order
|
||||
#if 1
|
||||
// O( n )
|
||||
for ( unsigned int i = num / 2; i > 0; i-- ) {
|
||||
// sift down
|
||||
unsigned int parent = i - 1;
|
||||
for ( unsigned int child = parent * 2 + 1; child < num; child = parent * 2 + 1 ) {
|
||||
if ( child + 1 < num && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
|
||||
child++;
|
||||
}
|
||||
if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
|
||||
break;
|
||||
}
|
||||
SwapValues( base[parent], base[child] );
|
||||
parent = child;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// O(n log n)
|
||||
for ( unsigned int i = 1; i < num; i++ ) {
|
||||
// sift up
|
||||
for ( unsigned int child = i; child > 0; ) {
|
||||
unsigned int parent = ( child - 1 ) / 2;
|
||||
if ( static_cast< const _derived_ * >( this )->Compare( base[parent], base[child] ) > 0 ) {
|
||||
break;
|
||||
}
|
||||
SwapValues( base[child], base[parent] );
|
||||
child = parent;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// get sorted elements while maintaining heap order
|
||||
for ( unsigned int i = num - 1; i > 0; i-- ) {
|
||||
SwapValues( base[0], base[i] );
|
||||
// sift down
|
||||
unsigned int parent = 0;
|
||||
for ( unsigned int child = parent * 2 + 1; child < i; child = parent * 2 + 1 ) {
|
||||
if ( child + 1 < i && static_cast< const _derived_ * >( this )->Compare( base[child + 1], base[child] ) > 0 ) {
|
||||
child++;
|
||||
}
|
||||
if ( static_cast< const _derived_ * >( this )->Compare( base[child], base[parent] ) <= 0 ) {
|
||||
break;
|
||||
}
|
||||
SwapValues( base[parent], base[child] );
|
||||
parent = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
Default heap-sort comparison function that can
|
||||
be used to sort scalars from small to large.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_ >
|
||||
class idSort_HeapDefault : public idSort_Heap< _type_, idSort_HeapDefault< _type_ > > {
|
||||
public:
|
||||
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
idSort_Insertion is a sort template class that implements the
|
||||
insertion-sort algorithm on an array of objects of the specified data type.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_, typename _derived_ >
|
||||
class idSort_Insertion : public idSort< _type_ > {
|
||||
public:
|
||||
virtual void Sort( _type_ * base, unsigned int num ) const {
|
||||
_type_ * lo = base;
|
||||
_type_ * hi = base + ( num - 1 );
|
||||
while( hi > lo ) {
|
||||
_type_ * max = lo;
|
||||
for ( _type_ * p = lo + 1; p <= hi; p++ ) {
|
||||
if ( static_cast< const _derived_ * >( this )->Compare( (*p), (*max) ) > 0 ) {
|
||||
max = p;
|
||||
}
|
||||
}
|
||||
SwapValues( *max, *hi );
|
||||
hi--;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
================================================
|
||||
Default insertion-sort comparison function that can
|
||||
be used to sort scalars from small to large.
|
||||
================================================
|
||||
*/
|
||||
template< typename _type_ >
|
||||
class idSort_InsertionDefault : public idSort_Insertion< _type_, idSort_InsertionDefault< _type_ > > {
|
||||
public:
|
||||
int Compare( const _type_ & a, const _type_ & b ) const { return a - b; }
|
||||
};
|
||||
|
||||
#endif // !__SORT_H__
|
||||
86
neo/idlib/containers/Stack.h
Normal file
86
neo/idlib/containers/Stack.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __STACK_H__
|
||||
#define __STACK_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Stack template
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
#define idStack( type, next ) idStackTemplate<type, (int)&(((type*)NULL)->next)>
|
||||
|
||||
template< class type, int nextOffset >
|
||||
class idStackTemplate {
|
||||
public:
|
||||
idStackTemplate();
|
||||
|
||||
void Add( type *element );
|
||||
type * Get();
|
||||
|
||||
private:
|
||||
type * top;
|
||||
type * bottom;
|
||||
};
|
||||
|
||||
#define STACK_NEXT_PTR( element ) (*(type**)(((byte*)element)+nextOffset))
|
||||
|
||||
template< class type, int nextOffset >
|
||||
idStackTemplate<type,nextOffset>::idStackTemplate() {
|
||||
top = bottom = NULL;
|
||||
}
|
||||
|
||||
template< class type, int nextOffset >
|
||||
void idStackTemplate<type,nextOffset>::Add( type *element ) {
|
||||
STACK_NEXT_PTR(element) = top;
|
||||
top = element;
|
||||
if ( !bottom ) {
|
||||
bottom = element;
|
||||
}
|
||||
}
|
||||
|
||||
template< class type, int nextOffset >
|
||||
type *idStackTemplate<type,nextOffset>::Get() {
|
||||
type *element;
|
||||
|
||||
element = top;
|
||||
if ( element ) {
|
||||
top = STACK_NEXT_PTR(top);
|
||||
if ( bottom == element ) {
|
||||
bottom = NULL;
|
||||
}
|
||||
STACK_NEXT_PTR(element) = NULL;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
#endif /* !__STACK_H__ */
|
||||
656
neo/idlib/containers/StaticList.h
Normal file
656
neo/idlib/containers/StaticList.h
Normal file
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __STATICLIST_H__
|
||||
#define __STATICLIST_H__
|
||||
|
||||
#include "List.h"
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Static list template
|
||||
A non-growing, memset-able list using no memory allocation.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
template<class type,int size>
|
||||
class idStaticList {
|
||||
public:
|
||||
|
||||
idStaticList();
|
||||
idStaticList( const idStaticList<type,size> &other );
|
||||
~idStaticList<type,size>();
|
||||
|
||||
void Clear(); // marks the list as empty. does not deallocate or intialize data.
|
||||
int Num() const; // returns number of elements in list
|
||||
int Max() const; // returns the maximum number of elements in the list
|
||||
void SetNum( int newnum ); // set number of elements in list
|
||||
|
||||
// sets the number of elements in list and initializes any newly allocated elements to the given value
|
||||
void SetNum( int newNum, const type & initValue );
|
||||
|
||||
size_t Allocated() const; // returns total size of allocated memory
|
||||
size_t Size() const; // returns total size of allocated memory including size of list type
|
||||
size_t MemoryUsed() const; // returns size of the used elements in the list
|
||||
|
||||
const type & operator[]( int index ) const;
|
||||
type & operator[]( int index );
|
||||
|
||||
type * Ptr(); // returns a pointer to the list
|
||||
const type * Ptr() const; // returns a pointer to the list
|
||||
type * Alloc(); // returns reference to a new data element at the end of the list. returns NULL when full.
|
||||
int Append( const type & obj ); // append element
|
||||
int Append( const idStaticList<type,size> &other ); // append list
|
||||
int AddUnique( const type & obj ); // add unique element
|
||||
int Insert( const type & obj, int index = 0 ); // insert the element at the given index
|
||||
int FindIndex( const type & obj ) const; // find the index for the given element
|
||||
type * Find( type const & obj ) const; // find pointer to the given element
|
||||
int FindNull() const; // find the index for the first NULL pointer in the list
|
||||
int IndexOf( const type *obj ) const; // returns the index for the pointer to an element in the list
|
||||
bool RemoveIndex( int index ); // remove the element at the given index
|
||||
bool RemoveIndexFast( int index ); // remove the element at the given index
|
||||
bool Remove( const type & obj ); // remove the element
|
||||
void Swap( idStaticList<type,size> &other ); // swap the contents of the lists
|
||||
void DeleteContents( bool clear ); // delete the contents of the list
|
||||
|
||||
void Sort( const idSort<type> & sort = idSort_QuickDefault<type>() );
|
||||
|
||||
private:
|
||||
int num;
|
||||
type list[ size ];
|
||||
|
||||
private:
|
||||
// resizes list to the given number of elements
|
||||
void Resize( int newsize );
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::idStaticList()
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE idStaticList<type,size>::idStaticList() {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::idStaticList( const idStaticList<type,size> &other )
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE idStaticList<type,size>::idStaticList( const idStaticList<type,size> &other ) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::~idStaticList<type,size>
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE idStaticList<type,size>::~idStaticList() {
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Clear
|
||||
|
||||
Sets the number of elements in the list to 0. Assumes that type automatically handles freeing up memory.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE void idStaticList<type,size>::Clear() {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idList<_type_,_tag_>::Sort
|
||||
|
||||
Performs a QuickSort on the list using the supplied sort algorithm.
|
||||
|
||||
Note: The data is merely moved around the list, so any pointers to data within the list may
|
||||
no longer be valid.
|
||||
========================
|
||||
*/
|
||||
template< class type,int size >
|
||||
ID_INLINE void idStaticList<type,size>::Sort( const idSort<type> & sort ) {
|
||||
if ( list == NULL ) {
|
||||
return;
|
||||
}
|
||||
sort.Sort( Ptr(), Num() );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::DeleteContents
|
||||
|
||||
Calls the destructor of all elements in the list. Conditionally frees up memory used by the list.
|
||||
Note that this only works on lists containing pointers to objects and will cause a compiler error
|
||||
if called with non-pointers. Since the list was not responsible for allocating the object, it has
|
||||
no information on whether the object still exists or not, so care must be taken to ensure that
|
||||
the pointers are still valid when this function is called. Function will set all pointers in the
|
||||
list to NULL.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE void idStaticList<type,size>::DeleteContents( bool clear ) {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < num; i++ ) {
|
||||
delete list[ i ];
|
||||
list[ i ] = NULL;
|
||||
}
|
||||
|
||||
if ( clear ) {
|
||||
Clear();
|
||||
} else {
|
||||
memset( list, 0, sizeof( list ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Num
|
||||
|
||||
Returns the number of elements currently contained in the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::Num() const {
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Num
|
||||
|
||||
Returns the maximum number of elements in the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::Max() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type>::Allocated
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE size_t idStaticList<type,size>::Allocated() const {
|
||||
return size * sizeof( type );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type>::Size
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE size_t idStaticList<type,size>::Size() const {
|
||||
return sizeof( idStaticList<type,size> ) + Allocated();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Num
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE size_t idStaticList<type,size>::MemoryUsed() const {
|
||||
return num * sizeof( list[ 0 ] );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::SetNum
|
||||
|
||||
Set number of elements in list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE void idStaticList<type,size>::SetNum( int newnum ) {
|
||||
assert( newnum >= 0 );
|
||||
assert( newnum <= size );
|
||||
num = newnum;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idStaticList<_type_,_tag_>::SetNum
|
||||
========================
|
||||
*/
|
||||
template< class type,int size >
|
||||
ID_INLINE void idStaticList<type,size>::SetNum( int newNum, const type &initValue ) {
|
||||
assert( newNum >= 0 );
|
||||
newNum = Min( newNum, size );
|
||||
assert( newNum <= size );
|
||||
for ( int i = num; i < newNum; i++ ) {
|
||||
list[i] = initValue;
|
||||
}
|
||||
num = newNum;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::operator[] const
|
||||
|
||||
Access operator. Index must be within range or an assert will be issued in debug builds.
|
||||
Release builds do no range checking.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE const type &idStaticList<type,size>::operator[]( int index ) const {
|
||||
assert( index >= 0 );
|
||||
assert( index < num );
|
||||
|
||||
return list[ index ];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::operator[]
|
||||
|
||||
Access operator. Index must be within range or an assert will be issued in debug builds.
|
||||
Release builds do no range checking.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE type &idStaticList<type,size>::operator[]( int index ) {
|
||||
assert( index >= 0 );
|
||||
assert( index < num );
|
||||
|
||||
return list[ index ];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Ptr
|
||||
|
||||
Returns a pointer to the begining of the array. Useful for iterating through the list in loops.
|
||||
|
||||
Note: may return NULL if the list is empty.
|
||||
|
||||
FIXME: Create an iterator template for this kind of thing.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE type *idStaticList<type,size>::Ptr() {
|
||||
return &list[ 0 ];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Ptr
|
||||
|
||||
Returns a pointer to the begining of the array. Useful for iterating through the list in loops.
|
||||
|
||||
Note: may return NULL if the list is empty.
|
||||
|
||||
FIXME: Create an iterator template for this kind of thing.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE const type *idStaticList<type,size>::Ptr() const {
|
||||
return &list[ 0 ];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Alloc
|
||||
|
||||
Returns a pointer to a new data element at the end of the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE type *idStaticList<type,size>::Alloc() {
|
||||
if ( num >= size ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &list[ num++ ];
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Append
|
||||
|
||||
Increases the size of the list by one element and copies the supplied data into it.
|
||||
|
||||
Returns the index of the new element, or -1 when list is full.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::Append( type const & obj ) {
|
||||
assert( num < size );
|
||||
if ( num < size ) {
|
||||
list[ num ] = obj;
|
||||
num++;
|
||||
return num - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Insert
|
||||
|
||||
Increases the size of the list by at leat one element if necessary
|
||||
and inserts the supplied data into it.
|
||||
|
||||
Returns the index of the new element, or -1 when list is full.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::Insert( type const & obj, int index ) {
|
||||
int i;
|
||||
|
||||
assert( num < size );
|
||||
if ( num >= size ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert( index >= 0 );
|
||||
if ( index < 0 ) {
|
||||
index = 0;
|
||||
} else if ( index > num ) {
|
||||
index = num;
|
||||
}
|
||||
|
||||
for( i = num; i > index; --i ) {
|
||||
list[i] = list[i-1];
|
||||
}
|
||||
|
||||
num++;
|
||||
list[index] = obj;
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Append
|
||||
|
||||
adds the other list to this one
|
||||
|
||||
Returns the size of the new combined list
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::Append( const idStaticList<type,size> &other ) {
|
||||
int i;
|
||||
int n = other.Num();
|
||||
|
||||
if ( num + n > size ) {
|
||||
n = size - num;
|
||||
}
|
||||
for( i = 0; i < n; i++ ) {
|
||||
list[i + num] = other.list[i];
|
||||
}
|
||||
num += n;
|
||||
return Num();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::AddUnique
|
||||
|
||||
Adds the data to the list if it doesn't already exist. Returns the index of the data in the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::AddUnique( type const & obj ) {
|
||||
int index;
|
||||
|
||||
index = FindIndex( obj );
|
||||
if ( index < 0 ) {
|
||||
index = Append( obj );
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::FindIndex
|
||||
|
||||
Searches for the specified data in the list and returns it's index. Returns -1 if the data is not found.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::FindIndex( type const & obj ) const {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < num; i++ ) {
|
||||
if ( list[ i ] == obj ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Find
|
||||
|
||||
Searches for the specified data in the list and returns it's address. Returns NULL if the data is not found.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE type *idStaticList<type,size>::Find( type const & obj ) const {
|
||||
int i;
|
||||
|
||||
i = FindIndex( obj );
|
||||
if ( i >= 0 ) {
|
||||
return (type *) &list[ i ];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::FindNull
|
||||
|
||||
Searches for a NULL pointer in the list. Returns -1 if NULL is not found.
|
||||
|
||||
NOTE: This function can only be called on lists containing pointers. Calling it
|
||||
on non-pointer lists will cause a compiler error.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::FindNull() const {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < num; i++ ) {
|
||||
if ( list[ i ] == NULL ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::IndexOf
|
||||
|
||||
Takes a pointer to an element in the list and returns the index of the element.
|
||||
This is NOT a guarantee that the object is really in the list.
|
||||
Function will assert in debug builds if pointer is outside the bounds of the list,
|
||||
but remains silent in release builds.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE int idStaticList<type,size>::IndexOf( type const *objptr ) const {
|
||||
int index;
|
||||
|
||||
index = objptr - list;
|
||||
|
||||
assert( index >= 0 );
|
||||
assert( index < num );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::RemoveIndex
|
||||
|
||||
Removes the element at the specified index and moves all data following the element down to fill in the gap.
|
||||
The number of elements in the list is reduced by one. Returns false if the index is outside the bounds of the list.
|
||||
Note that the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE bool idStaticList<type,size>::RemoveIndex( int index ) {
|
||||
int i;
|
||||
|
||||
assert( index >= 0 );
|
||||
assert( index < num );
|
||||
|
||||
if ( ( index < 0 ) || ( index >= num ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num--;
|
||||
for( i = index; i < num; i++ ) {
|
||||
list[ i ] = list[ i + 1 ];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
idList<_type_,_tag_>::RemoveIndexFast
|
||||
|
||||
Removes the element at the specified index and moves the last element into its spot, rather
|
||||
than moving the whole array down by one. Of course, this doesn't maintain the order of
|
||||
elements! The number of elements in the list is reduced by one.
|
||||
|
||||
return: bool - false if the data is not found in the list.
|
||||
|
||||
NOTE: The element is not destroyed, so any memory used by it may not be freed until the
|
||||
destruction of the list.
|
||||
========================
|
||||
*/
|
||||
template< typename _type_,int size >
|
||||
ID_INLINE bool idStaticList<_type_,size>::RemoveIndexFast( int index ) {
|
||||
|
||||
if ( ( index < 0 ) || ( index >= num ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num--;
|
||||
if ( index != num ) {
|
||||
list[ index ] = list[ num ];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Remove
|
||||
|
||||
Removes the element if it is found within the list and moves all data following the element down to fill in the gap.
|
||||
The number of elements in the list is reduced by one. Returns false if the data is not found in the list. Note that
|
||||
the element is not destroyed, so any memory used by it may not be freed until the destruction of the list.
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE bool idStaticList<type,size>::Remove( type const & obj ) {
|
||||
int index;
|
||||
|
||||
index = FindIndex( obj );
|
||||
if ( index >= 0 ) {
|
||||
return RemoveIndex( index );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStaticList<type,size>::Swap
|
||||
|
||||
Swaps the contents of two lists
|
||||
================
|
||||
*/
|
||||
template<class type,int size>
|
||||
ID_INLINE void idStaticList<type,size>::Swap( idStaticList<type,size> &other ) {
|
||||
idStaticList<type,size> temp = *this;
|
||||
*this = other;
|
||||
other = temp;
|
||||
}
|
||||
|
||||
// debug tool to find uses of idlist that are dynamically growing
|
||||
// Ideally, most lists on shipping titles will explicitly set their size correctly
|
||||
// instead of relying on allocate-on-add
|
||||
void BreakOnListGrowth();
|
||||
void BreakOnListDefault();
|
||||
|
||||
/*
|
||||
========================
|
||||
idList<_type_,_tag_>::Resize
|
||||
|
||||
Allocates memory for the amount of elements requested while keeping the contents intact.
|
||||
Contents are copied using their = operator so that data is correctly instantiated.
|
||||
========================
|
||||
*/
|
||||
template< class type,int size >
|
||||
ID_INLINE void idStaticList<type,size>::Resize( int newsize ) {
|
||||
|
||||
assert( newsize >= 0 );
|
||||
|
||||
// free up the list if no data is being reserved
|
||||
if ( newsize <= 0 ) {
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( newsize == size ) {
|
||||
// not changing the size, so just exit
|
||||
return;
|
||||
}
|
||||
|
||||
assert( newsize < size );
|
||||
return;
|
||||
}
|
||||
#endif /* !__STATICLIST_H__ */
|
||||
204
neo/idlib/containers/StrList.h
Normal file
204
neo/idlib/containers/StrList.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __STRLIST_H__
|
||||
#define __STRLIST_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idStrList
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
typedef idList<idStr> idStrList;
|
||||
typedef idList<idStr*> idStrPtrList;
|
||||
typedef idStr *idStrPtr;
|
||||
|
||||
///*
|
||||
//================
|
||||
//idListSortCompare<idStrPtr>
|
||||
//
|
||||
//Compares two pointers to strings. Used to sort a list of string pointers alphabetically in idList<idStr>::Sort.
|
||||
//================
|
||||
//*/
|
||||
//template<>
|
||||
//ID_INLINE int idListSortCompare<idStrPtr, memTag_t _tag_ >( const idStrPtr *a, const idStrPtr *b ) {
|
||||
// return ( *a )->Icmp( **b );
|
||||
//}
|
||||
|
||||
///*
|
||||
//================
|
||||
//idStrList::Sort
|
||||
//
|
||||
//Sorts the list of strings alphabetically. Creates a list of pointers to the actual strings and sorts the
|
||||
//pointer list. Then copies the strings into another list using the ordered list of pointers.
|
||||
//================
|
||||
//*/
|
||||
//template<>
|
||||
//ID_INLINE void idStrList::Sort( cmp_t *compare ) {
|
||||
// int i;
|
||||
//
|
||||
// if ( !num ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// idList<idStr> other;
|
||||
// idList<idStrPtr> pointerList;
|
||||
//
|
||||
// pointerList.SetNum( num );
|
||||
// for( i = 0; i < num; i++ ) {
|
||||
// pointerList[ i ] = &( *this )[ i ];
|
||||
// }
|
||||
//
|
||||
// pointerList.Sort();
|
||||
//
|
||||
// other.SetNum( num );
|
||||
// other.SetGranularity( granularity );
|
||||
// for( i = 0; i < other.Num(); i++ ) {
|
||||
// other[ i ] = *pointerList[ i ];
|
||||
// }
|
||||
//
|
||||
// this->Swap( other );
|
||||
//}
|
||||
|
||||
///*
|
||||
//================
|
||||
//idStrList::SortSubSection
|
||||
//
|
||||
//Sorts a subsection of the list of strings alphabetically.
|
||||
//================
|
||||
//*/
|
||||
//template<>
|
||||
//ID_INLINE void idStrList::SortSubSection( int startIndex, int endIndex, cmp_t *compare ) {
|
||||
// int i, s;
|
||||
//
|
||||
// if ( !num ) {
|
||||
// return;
|
||||
// }
|
||||
// if ( startIndex < 0 ) {
|
||||
// startIndex = 0;
|
||||
// }
|
||||
// if ( endIndex >= num ) {
|
||||
// endIndex = num - 1;
|
||||
// }
|
||||
// if ( startIndex >= endIndex ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// idList<idStr> other;
|
||||
// idList<idStrPtr> pointerList;
|
||||
//
|
||||
// s = endIndex - startIndex + 1;
|
||||
// other.SetNum( s );
|
||||
// pointerList.SetNum( s );
|
||||
// for( i = 0; i < s; i++ ) {
|
||||
// other[ i ] = ( *this )[ startIndex + i ];
|
||||
// pointerList[ i ] = &other[ i ];
|
||||
// }
|
||||
//
|
||||
// pointerList.Sort();
|
||||
//
|
||||
// for( i = 0; i < s; i++ ) {
|
||||
// (*this)[ startIndex + i ] = *pointerList[ i ];
|
||||
// }
|
||||
//}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrList::Size
|
||||
================
|
||||
*/
|
||||
template<>
|
||||
ID_INLINE size_t idStrList::Size() const {
|
||||
size_t s;
|
||||
int i;
|
||||
|
||||
s = sizeof( *this );
|
||||
for( i = 0; i < Num(); i++ ) {
|
||||
s += ( *this )[ i ].Size();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idStrList path sorting
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
//
|
||||
///*
|
||||
//================
|
||||
//idListSortComparePaths
|
||||
//
|
||||
//Compares two pointers to strings. Used to sort a list of string pointers alphabetically in idList<idStr>::Sort.
|
||||
//================
|
||||
//*/
|
||||
//template<class idStrPtr>
|
||||
//ID_INLINE int idListSortComparePaths( const idStrPtr *a, const idStrPtr *b ) {
|
||||
// return ( *a )->IcmpPath( **b );
|
||||
//}
|
||||
|
||||
///*
|
||||
//================
|
||||
//idStrListSortPaths
|
||||
//
|
||||
//Sorts the list of path strings alphabetically and makes sure folders come first.
|
||||
//================
|
||||
//*/
|
||||
//ID_INLINE void idStrListSortPaths( idStrList &list ) {
|
||||
// int i;
|
||||
//
|
||||
// if ( !list.Num() ) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// idList<idStr> other;
|
||||
// idList<idStrPtr> pointerList;
|
||||
//
|
||||
// pointerList.SetNum( list.Num() );
|
||||
// for( i = 0; i < list.Num(); i++ ) {
|
||||
// pointerList[ i ] = &list[ i ];
|
||||
// }
|
||||
//
|
||||
// pointerList.Sort( idListSortComparePaths<idStrPtr> );
|
||||
//
|
||||
// other.SetNum( list.Num() );
|
||||
// other.SetGranularity( list.GetGranularity() );
|
||||
// for( i = 0; i < other.Num(); i++ ) {
|
||||
// other[ i ] = *pointerList[ i ];
|
||||
// }
|
||||
//
|
||||
// list.Swap( other );
|
||||
//}
|
||||
|
||||
#endif /* !__STRLIST_H__ */
|
||||
228
neo/idlib/containers/StrPool.h
Normal file
228
neo/idlib/containers/StrPool.h
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __STRPOOL_H__
|
||||
#define __STRPOOL_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
idStrPool
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class idStrPool;
|
||||
|
||||
class idPoolStr : public idStr {
|
||||
friend class idStrPool;
|
||||
|
||||
public:
|
||||
idPoolStr() { numUsers = 0; }
|
||||
~idPoolStr() { assert( numUsers == 0 ); }
|
||||
|
||||
// returns total size of allocated memory
|
||||
size_t Allocated() const { return idStr::Allocated(); }
|
||||
// returns total size of allocated memory including size of string pool type
|
||||
size_t Size() const { return sizeof( *this ) + Allocated(); }
|
||||
// returns a pointer to the pool this string was allocated from
|
||||
const idStrPool * GetPool() const { return pool; }
|
||||
|
||||
private:
|
||||
idStrPool * pool;
|
||||
mutable int numUsers;
|
||||
};
|
||||
|
||||
class idStrPool {
|
||||
public:
|
||||
idStrPool() { caseSensitive = true; }
|
||||
|
||||
void SetCaseSensitive( bool caseSensitive );
|
||||
|
||||
int Num() const { return pool.Num(); }
|
||||
size_t Allocated() const;
|
||||
size_t Size() const;
|
||||
|
||||
const idPoolStr * operator[]( int index ) const { return pool[index]; }
|
||||
|
||||
const idPoolStr * AllocString( const char *string );
|
||||
void FreeString( const idPoolStr *poolStr );
|
||||
const idPoolStr * CopyString( const idPoolStr *poolStr );
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
bool caseSensitive;
|
||||
idList<idPoolStr *> pool;
|
||||
idHashIndex poolHash;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::SetCaseSensitive
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idStrPool::SetCaseSensitive( bool caseSensitive ) {
|
||||
this->caseSensitive = caseSensitive;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::AllocString
|
||||
================
|
||||
*/
|
||||
ID_INLINE const idPoolStr *idStrPool::AllocString( const char *string ) {
|
||||
int i, hash;
|
||||
idPoolStr *poolStr;
|
||||
|
||||
hash = poolHash.GenerateKey( string, caseSensitive );
|
||||
if ( caseSensitive ) {
|
||||
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
|
||||
if ( pool[i]->Cmp( string ) == 0 ) {
|
||||
pool[i]->numUsers++;
|
||||
return pool[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
|
||||
if ( pool[i]->Icmp( string ) == 0 ) {
|
||||
pool[i]->numUsers++;
|
||||
return pool[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
poolStr = new (TAG_IDLIB_STRING) idPoolStr;
|
||||
*static_cast<idStr *>(poolStr) = string;
|
||||
poolStr->pool = this;
|
||||
poolStr->numUsers = 1;
|
||||
poolHash.Add( hash, pool.Append( poolStr ) );
|
||||
return poolStr;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::FreeString
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idStrPool::FreeString( const idPoolStr *poolStr ) {
|
||||
int i, hash;
|
||||
|
||||
assert( poolStr->numUsers >= 1 );
|
||||
assert( poolStr->pool == this );
|
||||
|
||||
poolStr->numUsers--;
|
||||
if ( poolStr->numUsers <= 0 ) {
|
||||
hash = poolHash.GenerateKey( poolStr->c_str(), caseSensitive );
|
||||
if ( caseSensitive ) {
|
||||
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
|
||||
if ( pool[i]->Cmp( poolStr->c_str() ) == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( i = poolHash.First( hash ); i != -1; i = poolHash.Next( i ) ) {
|
||||
if ( pool[i]->Icmp( poolStr->c_str() ) == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( i != -1 );
|
||||
assert( pool[i] == poolStr );
|
||||
delete pool[i];
|
||||
pool.RemoveIndex( i );
|
||||
poolHash.RemoveIndex( hash, i );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::CopyString
|
||||
================
|
||||
*/
|
||||
ID_INLINE const idPoolStr *idStrPool::CopyString( const idPoolStr *poolStr ) {
|
||||
|
||||
assert( poolStr->numUsers >= 1 );
|
||||
|
||||
if ( poolStr->pool == this ) {
|
||||
// the string is from this pool so just increase the user count
|
||||
poolStr->numUsers++;
|
||||
return poolStr;
|
||||
} else {
|
||||
// the string is from another pool so it needs to be re-allocated from this pool.
|
||||
return AllocString( poolStr->c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::Clear
|
||||
================
|
||||
*/
|
||||
ID_INLINE void idStrPool::Clear() {
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < pool.Num(); i++ ) {
|
||||
pool[i]->numUsers = 0;
|
||||
}
|
||||
pool.DeleteContents( true );
|
||||
poolHash.Free();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::Allocated
|
||||
================
|
||||
*/
|
||||
ID_INLINE size_t idStrPool::Allocated() const {
|
||||
int i;
|
||||
size_t size;
|
||||
|
||||
size = pool.Allocated() + poolHash.Allocated();
|
||||
for ( i = 0; i < pool.Num(); i++ ) {
|
||||
size += pool[i]->Allocated();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idStrPool::Size
|
||||
================
|
||||
*/
|
||||
ID_INLINE size_t idStrPool::Size() const {
|
||||
int i;
|
||||
size_t size;
|
||||
|
||||
size = pool.Size() + poolHash.Size();
|
||||
for ( i = 0; i < pool.Num(); i++ ) {
|
||||
size += pool[i]->Size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif /* !__STRPOOL_H__ */
|
||||
270
neo/idlib/containers/VectorSet.h
Normal file
270
neo/idlib/containers/VectorSet.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition Source Code 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
|
||||
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __VECTORSET_H__
|
||||
#define __VECTORSET_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Vector Set
|
||||
|
||||
Creates a set of vectors without duplicates.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
template< class type, int dimension >
|
||||
class idVectorSet : public idList<type> {
|
||||
public:
|
||||
idVectorSet();
|
||||
idVectorSet( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
|
||||
|
||||
// returns total size of allocated memory
|
||||
size_t Allocated() const { return idList<type>::Allocated() + hash.Allocated(); }
|
||||
// returns total size of allocated memory including size of type
|
||||
size_t Size() const { return sizeof( *this ) + Allocated(); }
|
||||
|
||||
void Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
|
||||
void ResizeIndex( const int newSize );
|
||||
void Clear();
|
||||
|
||||
int FindVector( const type &v, const float epsilon );
|
||||
|
||||
private:
|
||||
idHashIndex hash;
|
||||
type mins;
|
||||
type maxs;
|
||||
int boxHashSize;
|
||||
float boxInvSize[dimension];
|
||||
float boxHalfSize[dimension];
|
||||
};
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE idVectorSet<type,dimension>::idVectorSet() {
|
||||
hash.Clear( idMath::IPow( boxHashSize, dimension ), 128 );
|
||||
boxHashSize = 16;
|
||||
memset( boxInvSize, 0, dimension * sizeof( boxInvSize[0] ) );
|
||||
memset( boxHalfSize, 0, dimension * sizeof( boxHalfSize[0] ) );
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE idVectorSet<type,dimension>::idVectorSet( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
|
||||
Init( mins, maxs, boxHashSize, initialSize );
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE void idVectorSet<type,dimension>::Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
|
||||
int i;
|
||||
float boxSize;
|
||||
|
||||
idList<type>::AssureSize( initialSize );
|
||||
idList<type>::SetNum( 0, false );
|
||||
|
||||
hash.Clear( idMath::IPow( boxHashSize, dimension ), initialSize );
|
||||
|
||||
this->mins = mins;
|
||||
this->maxs = maxs;
|
||||
this->boxHashSize = boxHashSize;
|
||||
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
boxSize = ( maxs[i] - mins[i] ) / (float) boxHashSize;
|
||||
boxInvSize[i] = 1.0f / boxSize;
|
||||
boxHalfSize[i] = boxSize * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE void idVectorSet<type,dimension>::ResizeIndex( const int newSize ) {
|
||||
idList<type>::Resize( newSize );
|
||||
hash.ResizeIndex( newSize );
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE void idVectorSet<type,dimension>::Clear() {
|
||||
idList<type>::Clear();
|
||||
hash.Clear();
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE int idVectorSet<type,dimension>::FindVector( const type &v, const float epsilon ) {
|
||||
int i, j, k, hashKey, partialHashKey[dimension];
|
||||
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
assert( epsilon <= boxHalfSize[i] );
|
||||
partialHashKey[i] = (int) ( ( v[i] - mins[i] - boxHalfSize[i] ) * boxInvSize[i] );
|
||||
}
|
||||
|
||||
for ( i = 0; i < ( 1 << dimension ); i++ ) {
|
||||
|
||||
hashKey = 0;
|
||||
for ( j = 0; j < dimension; j++ ) {
|
||||
hashKey *= boxHashSize;
|
||||
hashKey += partialHashKey[j] + ( ( i >> j ) & 1 );
|
||||
}
|
||||
|
||||
for ( j = hash.First( hashKey ); j >= 0; j = hash.Next( j ) ) {
|
||||
const type &lv = (*this)[j];
|
||||
for ( k = 0; k < dimension; k++ ) {
|
||||
if ( idMath::Fabs( lv[k] - v[k] ) > epsilon ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k >= dimension ) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hashKey = 0;
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
hashKey *= boxHashSize;
|
||||
hashKey += (int) ( ( v[i] - mins[i] ) * boxInvSize[i] );
|
||||
}
|
||||
|
||||
hash.Add( hashKey, idList<type>::Num() );
|
||||
Append( v );
|
||||
return idList<type>::Num()-1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Vector Subset
|
||||
|
||||
Creates a subset without duplicates from an existing list with vectors.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
template< class type, int dimension >
|
||||
class idVectorSubset {
|
||||
public:
|
||||
idVectorSubset();
|
||||
idVectorSubset( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
|
||||
|
||||
// returns total size of allocated memory
|
||||
size_t Allocated() const { return idList<type>::Allocated() + hash.Allocated(); }
|
||||
// returns total size of allocated memory including size of type
|
||||
size_t Size() const { return sizeof( *this ) + Allocated(); }
|
||||
|
||||
void Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize );
|
||||
void Clear();
|
||||
|
||||
// returns either vectorNum or an index to a previously found vector
|
||||
int FindVector( const type *vectorList, const int vectorNum, const float epsilon );
|
||||
|
||||
private:
|
||||
idHashIndex hash;
|
||||
type mins;
|
||||
type maxs;
|
||||
int boxHashSize;
|
||||
float boxInvSize[dimension];
|
||||
float boxHalfSize[dimension];
|
||||
};
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE idVectorSubset<type,dimension>::idVectorSubset() {
|
||||
hash.Clear( idMath::IPow( boxHashSize, dimension ), 128 );
|
||||
boxHashSize = 16;
|
||||
memset( boxInvSize, 0, dimension * sizeof( boxInvSize[0] ) );
|
||||
memset( boxHalfSize, 0, dimension * sizeof( boxHalfSize[0] ) );
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE idVectorSubset<type,dimension>::idVectorSubset( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
|
||||
Init( mins, maxs, boxHashSize, initialSize );
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE void idVectorSubset<type,dimension>::Init( const type &mins, const type &maxs, const int boxHashSize, const int initialSize ) {
|
||||
int i;
|
||||
float boxSize;
|
||||
|
||||
hash.Clear( idMath::IPow( boxHashSize, dimension ), initialSize );
|
||||
|
||||
this->mins = mins;
|
||||
this->maxs = maxs;
|
||||
this->boxHashSize = boxHashSize;
|
||||
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
boxSize = ( maxs[i] - mins[i] ) / (float) boxHashSize;
|
||||
boxInvSize[i] = 1.0f / boxSize;
|
||||
boxHalfSize[i] = boxSize * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE void idVectorSubset<type,dimension>::Clear() {
|
||||
idList<type>::Clear();
|
||||
hash.Clear();
|
||||
}
|
||||
|
||||
template< class type, int dimension >
|
||||
ID_INLINE int idVectorSubset<type,dimension>::FindVector( const type *vectorList, const int vectorNum, const float epsilon ) {
|
||||
int i, j, k, hashKey, partialHashKey[dimension];
|
||||
const type &v = vectorList[vectorNum];
|
||||
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
assert( epsilon <= boxHalfSize[i] );
|
||||
partialHashKey[i] = (int) ( ( v[i] - mins[i] - boxHalfSize[i] ) * boxInvSize[i] );
|
||||
}
|
||||
|
||||
for ( i = 0; i < ( 1 << dimension ); i++ ) {
|
||||
|
||||
hashKey = 0;
|
||||
for ( j = 0; j < dimension; j++ ) {
|
||||
hashKey *= boxHashSize;
|
||||
hashKey += partialHashKey[j] + ( ( i >> j ) & 1 );
|
||||
}
|
||||
|
||||
for ( j = hash.First( hashKey ); j >= 0; j = hash.Next( j ) ) {
|
||||
const type &lv = vectorList[j];
|
||||
for ( k = 0; k < dimension; k++ ) {
|
||||
if ( idMath::Fabs( lv[k] - v[k] ) > epsilon ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( k >= dimension ) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hashKey = 0;
|
||||
for ( i = 0; i < dimension; i++ ) {
|
||||
hashKey *= boxHashSize;
|
||||
hashKey += (int) ( ( v[i] - mins[i] ) * boxInvSize[i] );
|
||||
}
|
||||
|
||||
hash.Add( hashKey, vectorNum );
|
||||
return vectorNum;
|
||||
}
|
||||
|
||||
#endif /* !__VECTORSET_H__ */
|
||||
Reference in New Issue
Block a user