Initial commit

This commit is contained in:
Brian Harris
2012-11-26 12:58:24 -06:00
parent a5214f79ef
commit 5016f605b8
1115 changed files with 587266 additions and 0 deletions

View 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__

View 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__ */

View 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__ */

View 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);
}

View 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__ */

View 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__ */

View 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__ */

View 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

File diff suppressed because it is too large Load Diff

View 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__ */

View 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
View 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__

View 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__ */

View 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__ */

View 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__ */

View 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__ */

View 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__ */