/* =========================================================================== 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 . 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* Add( objType* object, keyType key ); // add an object to the tree void Remove( idBTreeNode* node ); // remove an object node from the tree idBTreeNode* NodeFind( keyType key ) const; // find an object using the given key idBTreeNode* NodeFindSmallestLargerEqual( keyType key ) const; // find an object with the smallest key larger equal the given key idBTreeNode* 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* GetRoot() const; // returns the root node of the tree int GetNodeCount() const; // returns the total number of nodes in the tree idBTreeNode* GetNext( idBTreeNode* node ) const; // goes through all nodes of the tree idBTreeNode* GetNextLeaf( idBTreeNode* node ) const; // goes through all leaf nodes of the tree private: idBTreeNode* root; idBlockAlloc, 128> nodeAllocator; idBTreeNode* AllocNode(); void FreeNode( idBTreeNode* node ); void SplitNode( idBTreeNode* node ); idBTreeNode* MergeNodes( idBTreeNode* node1, idBTreeNode* node2 ); void CheckTree_r( idBTreeNode* node, int& numNodes ) const; void CheckTree() const; }; template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTree::idBTree() { assert( maxChildrenPerNode >= 4 ); root = NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTree::~idBTree() { Shutdown(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::Init() { root = AllocNode(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::Shutdown() { nodeAllocator.Shutdown(); root = NULL; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode* idBTree::Add( objType* object, keyType key ) { idBTreeNode* 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::Remove( idBTreeNode* node ) { idBTreeNode* 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* 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* idBTree::NodeFind( keyType key ) const { idBTreeNode* 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* idBTree::NodeFindSmallestLargerEqual( keyType key ) const { idBTreeNode* 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* idBTree::NodeFindLargestSmallerEqual( keyType key ) const { idBTreeNode* node; if( root == NULL ) { return NULL; } idBTreeNode* 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::Find( keyType key ) const { idBTreeNode* node = NodeFind( key ); if( node == NULL ) { return NULL; } else { return node->object; } } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE objType* idBTree::FindSmallestLargerEqual( keyType key ) const { idBTreeNode* node = NodeFindSmallestLargerEqual( key ); if( node == NULL ) { return NULL; } else { return node->object; } } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE objType* idBTree::FindLargestSmallerEqual( keyType key ) const { idBTreeNode* node = NodeFindLargestSmallerEqual( key ); if( node == NULL ) { return NULL; } else { return node->object; } } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode* idBTree::GetRoot() const { return root; } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE int idBTree::GetNodeCount() const { return nodeAllocator.GetAllocCount(); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE idBTreeNode* idBTree::GetNext( idBTreeNode* 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* idBTree::GetNextLeaf( idBTreeNode* 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* idBTree::AllocNode() { idBTreeNode* 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::FreeNode( idBTreeNode* node ) { nodeAllocator.Free( node ); } template< class objType, class keyType, int maxChildrenPerNode > ID_INLINE void idBTree::SplitNode( idBTreeNode* node ) { int i; idBTreeNode* 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* idBTree::MergeNodes( idBTreeNode* node1, idBTreeNode* node2 ) { idBTreeNode* 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::CheckTree_r( idBTreeNode* node, int& numNodes ) const { int numChildren; idBTreeNode* 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::CheckTree() const { int numNodes = 0; idBTreeNode* 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__ */