//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== // // The copyright to the contents herein is the property of Valve, L.L.C. // The contents may be used and/or copied only with the written permission of // Valve, L.L.C., or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: // // $Header: $ // $NoKeywords: $ //============================================================================= #ifndef UTLRBTREE_H #define UTLRBTREE_H //#include #include "utlmemory.h" //----------------------------------------------------------------------------- // Tool to generate a default compare function for any type that implements // operator<, including all simple types //----------------------------------------------------------------------------- template class CDefOps { public: static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); } }; #define DefLessFunc( type ) CDefOps::LessFunc //------------------------------------- inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { return ( strcmp( lhs, rhs) < 0 ); } inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { return ( _stricmp( lhs, rhs) < 0 ); } //------------------------------------- // inline these two templates to stop multiple definitions of the same code template <> inline bool CDefOps::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); } template <> inline bool CDefOps::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); } //------------------------------------- template void SetDefLessFunc( RBTREE_T &RBTree ) { #ifdef _WIN32 RBTree.SetLessFunc( DefLessFunc( RBTREE_T::KeyType_t ) ); #elif _LINUX RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); #endif } //----------------------------------------------------------------------------- // A red-black binary search tree //----------------------------------------------------------------------------- template class CUtlRBTree { public: // Less func typedef // Returns true if the first parameter is "less" than the second typedef bool (*LessFunc_t)( T const &, T const & ); typedef T KeyType_t; typedef T ElemType_t; typedef I IndexType_t; // constructor, destructor // Left at growSize = 0, the memory will first allocate 1 element and double in size // at each increment. // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below CUtlRBTree( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ); ~CUtlRBTree( ); // gets particular elements T& Element( I i ); T const &Element( I i ) const; T& operator[]( I i ); T const &operator[]( I i ) const; // Gets the root I Root() const; // Num elements unsigned int Count() const; // Max "size" of the vector I MaxElement() const; // Gets the children I Parent( I i ) const; I LeftChild( I i ) const; I RightChild( I i ) const; // Tests if a node is a left or right child bool IsLeftChild( I i ) const; bool IsRightChild( I i ) const; // Tests if root or leaf bool IsRoot( I i ) const; bool IsLeaf( I i ) const; // Checks if a node is valid and in the tree bool IsValidIndex( I i ) const; // Checks if the tree as a whole is valid bool IsValid() const; // Invalid index static I InvalidIndex(); // returns the tree depth (not a very fast operation) int Depth( I node ) const; int Depth() const; // Sets the less func void SetLessFunc( LessFunc_t func ); // Allocation method I NewNode(); // Insert method (inserts in order) I Insert( T const &insert ); void Insert( const T *pArray, int nItems ); // Find method I Find( T const &search ) const; // Remove methods void RemoveAt( I i ); bool Remove( T const &remove ); void RemoveAll( ); // Allocation, deletion void FreeNode( I i ); // Iteration I FirstInorder() const; I NextInorder( I i ) const; I PrevInorder( I i ) const; I LastInorder() const; I FirstPreorder() const; I NextPreorder( I i ) const; I PrevPreorder( I i ) const; I LastPreorder( ) const; I FirstPostorder() const; I NextPostorder( I i ) const; // If you change the search key, this can be used to reinsert the // element into the tree. void Reinsert( I elem ); protected: enum NodeColor_t { RED = 0, BLACK }; struct Links_t { I m_Left; I m_Right; I m_Parent; I m_Tag; }; struct Node_t : public Links_t { T m_Data; }; // Sets the children void SetParent( I i, I parent ); void SetLeftChild( I i, I child ); void SetRightChild( I i, I child ); void LinkToParent( I i, I parent, bool isLeft ); // Gets at the links Links_t const &Links( I i ) const; Links_t &Links( I i ); // Checks if a link is red or black bool IsRed( I i ) const; bool IsBlack( I i ) const; // Sets/gets node color NodeColor_t Color( I i ) const; void SetColor( I i, NodeColor_t c ); // operations required to preserve tree balance void RotateLeft(I i); void RotateRight(I i); void InsertRebalance(I i); void RemoveRebalance(I i); // Insertion, removal I InsertAt( I parent, bool leftchild ); // copy constructors not allowed CUtlRBTree( CUtlRBTree const &tree ); // Inserts a node into the tree, doesn't copy the data in. void FindInsertionPosition( T const &insert, I &parent, bool &leftchild ); // Remove and add back an element in the tree. void Unlink( I elem ); void Link( I elem ); // Used for sorting. LessFunc_t m_LessFunc; CUtlMemory m_Elements; I m_Root; I m_NumElements; I m_FirstFree; I m_TotalElements; Node_t* m_pElements; void ResetDbgInfo() { m_pElements = (Node_t*)m_Elements.Base(); } }; //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- template CUtlRBTree::CUtlRBTree( int growSize, int initSize, LessFunc_t lessfunc ) : m_Elements( growSize, initSize ), m_LessFunc( lessfunc ), m_Root( InvalidIndex() ), m_NumElements( 0 ), m_TotalElements( 0 ), m_FirstFree( InvalidIndex() ) { ResetDbgInfo(); } template CUtlRBTree::~CUtlRBTree() { } //----------------------------------------------------------------------------- // gets particular elements //----------------------------------------------------------------------------- template inline T &CUtlRBTree::Element( I i ) { return m_Elements[i].m_Data; } template inline T const &CUtlRBTree::Element( I i ) const { return m_Elements[i].m_Data; } template inline T &CUtlRBTree::operator[]( I i ) { return Element(i); } template inline T const &CUtlRBTree::operator[]( I i ) const { return Element(i); } //----------------------------------------------------------------------------- // // various accessors // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Gets the root //----------------------------------------------------------------------------- template inline I CUtlRBTree::Root() const { return m_Root; } //----------------------------------------------------------------------------- // Num elements //----------------------------------------------------------------------------- template inline unsigned int CUtlRBTree::Count() const { return (unsigned int)m_NumElements; } //----------------------------------------------------------------------------- // Max "size" of the vector //----------------------------------------------------------------------------- template inline I CUtlRBTree::MaxElement() const { return (I)m_TotalElements; } //----------------------------------------------------------------------------- // Gets the children //----------------------------------------------------------------------------- template inline I CUtlRBTree::Parent( I i ) const { return Links(i).m_Parent; } template inline I CUtlRBTree::LeftChild( I i ) const { return Links(i).m_Left; } template inline I CUtlRBTree::RightChild( I i ) const { return Links(i).m_Right; } //----------------------------------------------------------------------------- // Tests if a node is a left or right child //----------------------------------------------------------------------------- template inline bool CUtlRBTree::IsLeftChild( I i ) const { return LeftChild(Parent(i)) == i; } template inline bool CUtlRBTree::IsRightChild( I i ) const { return RightChild(Parent(i)) == i; } //----------------------------------------------------------------------------- // Tests if root or leaf //----------------------------------------------------------------------------- template inline bool CUtlRBTree::IsRoot( I i ) const { return i == m_Root; } template inline bool CUtlRBTree::IsLeaf( I i ) const { return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); } //----------------------------------------------------------------------------- // Checks if a node is valid and in the tree //----------------------------------------------------------------------------- template inline bool CUtlRBTree::IsValidIndex( I i ) const { return LeftChild(i) != i; } //----------------------------------------------------------------------------- // Invalid index //----------------------------------------------------------------------------- template I CUtlRBTree::InvalidIndex() { return (I)~0; } //----------------------------------------------------------------------------- // returns the tree depth (not a very fast operation) //----------------------------------------------------------------------------- template inline int CUtlRBTree::Depth() const { return Depth(Root()); } //----------------------------------------------------------------------------- // Sets the children //----------------------------------------------------------------------------- template inline void CUtlRBTree::SetParent( I i, I parent ) { Links(i).m_Parent = parent; } template inline void CUtlRBTree::SetLeftChild( I i, I child ) { Links(i).m_Left = child; } template inline void CUtlRBTree::SetRightChild( I i, I child ) { Links(i).m_Right = child; } //----------------------------------------------------------------------------- // Gets at the links //----------------------------------------------------------------------------- template inline typename CUtlRBTree::Links_t const &CUtlRBTree::Links( I i ) const { // Sentinel node, makes life easier static Links_t s_Sentinel = { InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree::BLACK }; return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : *(Links_t*)&s_Sentinel; } template inline typename CUtlRBTree::Links_t &CUtlRBTree::Links( I i ) { Assert(i != InvalidIndex()); return *(Links_t *)&m_Elements[i]; } //----------------------------------------------------------------------------- // Checks if a link is red or black //----------------------------------------------------------------------------- template inline bool CUtlRBTree::IsRed( I i ) const { return (Links(i).m_Tag == RED); } template inline bool CUtlRBTree::IsBlack( I i ) const { return (Links(i).m_Tag == BLACK); } //----------------------------------------------------------------------------- // Sets/gets node color //----------------------------------------------------------------------------- template inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color( I i ) const { return (NodeColor_t)Links(i).m_Tag; } template inline void CUtlRBTree::SetColor( I i, typename CUtlRBTree::NodeColor_t c ) { Links(i).m_Tag = (I)c; } //----------------------------------------------------------------------------- // Allocates/ deallocates nodes //----------------------------------------------------------------------------- template I CUtlRBTree::NewNode() { I newElem; // Nothing in the free list; add. if (m_FirstFree == InvalidIndex()) { if (m_Elements.NumAllocated() == m_TotalElements) m_Elements.Grow(); newElem = m_TotalElements++; } else { newElem = m_FirstFree; m_FirstFree = RightChild(m_FirstFree); } #ifdef _DEBUG // reset links to invalid.... Links_t &node = Links(newElem); node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); #endif Construct( &Element(newElem) ); ResetDbgInfo(); return newElem; } template void CUtlRBTree::FreeNode( I i ) { Assert( IsValidIndex(i) && (i != InvalidIndex()) ); Destruct( &Element(i) ); SetLeftChild( i, i ); // indicates it's in not in the tree SetRightChild( i, m_FirstFree ); m_FirstFree = i; } //----------------------------------------------------------------------------- // Rotates node i to the left //----------------------------------------------------------------------------- template void CUtlRBTree::RotateLeft(I elem) { I rightchild = RightChild(elem); SetRightChild( elem, LeftChild(rightchild) ); if (LeftChild(rightchild) != InvalidIndex()) SetParent( LeftChild(rightchild), elem ); if (rightchild != InvalidIndex()) SetParent( rightchild, Parent(elem) ); if (!IsRoot(elem)) { if (IsLeftChild(elem)) SetLeftChild( Parent(elem), rightchild ); else SetRightChild( Parent(elem), rightchild ); } else m_Root = rightchild; SetLeftChild( rightchild, elem ); if (elem != InvalidIndex()) SetParent( elem, rightchild ); } //----------------------------------------------------------------------------- // Rotates node i to the right //----------------------------------------------------------------------------- template void CUtlRBTree::RotateRight(I elem) { I leftchild = LeftChild(elem); SetLeftChild( elem, RightChild(leftchild) ); if (RightChild(leftchild) != InvalidIndex()) SetParent( RightChild(leftchild), elem ); if (leftchild != InvalidIndex()) SetParent( leftchild, Parent(elem) ); if (!IsRoot(elem)) { if (IsRightChild(elem)) SetRightChild( Parent(elem), leftchild ); else SetLeftChild( Parent(elem), leftchild ); } else m_Root = leftchild; SetRightChild( leftchild, elem ); if (elem != InvalidIndex()) SetParent( elem, leftchild ); } //----------------------------------------------------------------------------- // Rebalances the tree after an insertion //----------------------------------------------------------------------------- template void CUtlRBTree::InsertRebalance(I elem) { while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) ) { I parent = Parent(elem); I grandparent = Parent(parent); /* we have a violation */ if (IsLeftChild(parent)) { I uncle = RightChild(grandparent); if (IsRed(uncle)) { /* uncle is RED */ SetColor(parent, BLACK); SetColor(uncle, BLACK); SetColor(grandparent, RED); elem = grandparent; } else { /* uncle is BLACK */ if (IsRightChild(elem)) { /* make x a left child, will change parent and grandparent */ elem = parent; RotateLeft(elem); parent = Parent(elem); grandparent = Parent(parent); } /* recolor and rotate */ SetColor(parent, BLACK); SetColor(grandparent, RED); RotateRight(grandparent); } } else { /* mirror image of above code */ I uncle = LeftChild(grandparent); if (IsRed(uncle)) { /* uncle is RED */ SetColor(parent, BLACK); SetColor(uncle, BLACK); SetColor(grandparent, RED); elem = grandparent; } else { /* uncle is BLACK */ if (IsLeftChild(elem)) { /* make x a right child, will change parent and grandparent */ elem = parent; RotateRight(parent); parent = Parent(elem); grandparent = Parent(parent); } /* recolor and rotate */ SetColor(parent, BLACK); SetColor(grandparent, RED); RotateLeft(grandparent); } } } SetColor( m_Root, BLACK ); } //----------------------------------------------------------------------------- // Insert a node into the tree //----------------------------------------------------------------------------- template I CUtlRBTree::InsertAt( I parent, bool leftchild ) { I i = NewNode(); LinkToParent( i, parent, leftchild ); ++m_NumElements; return i; } template void CUtlRBTree::LinkToParent( I i, I parent, bool isLeft ) { Links_t &elem = Links(i); elem.m_Parent = parent; elem.m_Left = elem.m_Right = InvalidIndex(); elem.m_Tag = RED; /* insert node in tree */ if (parent != InvalidIndex()) { if (isLeft) Links(parent).m_Left = i; else Links(parent).m_Right = i; } else { m_Root = i; } InsertRebalance(i); Assert(IsValid()); } //----------------------------------------------------------------------------- // Rebalance the tree after a deletion //----------------------------------------------------------------------------- template void CUtlRBTree::RemoveRebalance(I elem) { while (elem != m_Root && IsBlack(elem)) { I parent = Parent(elem); // If elem is the left child of the parent if (elem == LeftChild(parent)) { // Get our sibling I sibling = RightChild(parent); if (IsRed(sibling)) { SetColor(sibling, BLACK); SetColor(parent, RED); RotateLeft(parent); // We may have a new parent now parent = Parent(elem); sibling = RightChild(parent); } if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) ) { if (sibling != InvalidIndex()) SetColor(sibling, RED); elem = parent; } else { if (IsBlack(RightChild(sibling))) { SetColor(LeftChild(sibling), BLACK); SetColor(sibling, RED); RotateRight(sibling); // rotation may have changed this parent = Parent(elem); sibling = RightChild(parent); } SetColor( sibling, Color(parent) ); SetColor( parent, BLACK ); SetColor( RightChild(sibling), BLACK ); RotateLeft( parent ); elem = m_Root; } } else { // Elem is the right child of the parent I sibling = LeftChild(parent); if (IsRed(sibling)) { SetColor(sibling, BLACK); SetColor(parent, RED); RotateRight(parent); // We may have a new parent now parent = Parent(elem); sibling = LeftChild(parent); } if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) ) { if (sibling != InvalidIndex()) SetColor( sibling, RED ); elem = parent; } else { if (IsBlack(LeftChild(sibling))) { SetColor( RightChild(sibling), BLACK ); SetColor( sibling, RED ); RotateLeft( sibling ); // rotation may have changed this parent = Parent(elem); sibling = LeftChild(parent); } SetColor( sibling, Color(parent) ); SetColor( parent, BLACK ); SetColor( LeftChild(sibling), BLACK ); RotateRight( parent ); elem = m_Root; } } } SetColor( elem, BLACK ); } template void CUtlRBTree::Unlink( I elem ) { if ( elem != InvalidIndex() ) { I x, y; if ((LeftChild(elem) == InvalidIndex()) || (RightChild(elem) == InvalidIndex())) { /* y has a NIL node as a child */ y = elem; } else { /* find tree successor with a NIL node as a child */ y = RightChild(elem); while (LeftChild(y) != InvalidIndex()) y = LeftChild(y); } /* x is y's only child */ if (LeftChild(y) != InvalidIndex()) x = LeftChild(y); else x = RightChild(y); /* remove y from the parent chain */ if (x != InvalidIndex()) SetParent( x, Parent(y) ); if (!IsRoot(y)) { if (IsLeftChild(y)) SetLeftChild( Parent(y), x ); else SetRightChild( Parent(y), x ); } else m_Root = x; // need to store this off now, we'll be resetting y's color NodeColor_t ycolor = Color(y); if (y != elem) { // Standard implementations copy the data around, we cannot here. // Hook in y to link to the same stuff elem used to. SetParent( y, Parent(elem) ); SetRightChild( y, RightChild(elem) ); SetLeftChild( y, LeftChild(elem) ); if (!IsRoot(elem)) if (IsLeftChild(elem)) SetLeftChild( Parent(elem), y ); else SetRightChild( Parent(elem), y ); else m_Root = y; if (LeftChild(y) != InvalidIndex()) SetParent( LeftChild(y), y ); if (RightChild(y) != InvalidIndex()) SetParent( RightChild(y), y ); SetColor( y, Color(elem) ); } if ((x != InvalidIndex()) && (ycolor == BLACK)) RemoveRebalance(x); } } template void CUtlRBTree::Link( I elem ) { if ( elem != InvalidIndex() ) { I parent; bool leftchild; FindInsertionPosition( Element( elem ), parent, leftchild ); LinkToParent( elem, parent, leftchild ); } } //----------------------------------------------------------------------------- // Delete a node from the tree //----------------------------------------------------------------------------- template void CUtlRBTree::RemoveAt(I elem) { if ( elem != InvalidIndex() ) { Unlink( elem ); FreeNode(elem); --m_NumElements; } } //----------------------------------------------------------------------------- // remove a node in the tree //----------------------------------------------------------------------------- template bool CUtlRBTree::Remove( T const &search ) { I node = Find( search ); if (node != InvalidIndex()) { RemoveAt(node); return true; } return false; } //----------------------------------------------------------------------------- // Removes all nodes from the tree //----------------------------------------------------------------------------- template void CUtlRBTree::RemoveAll() { // Just iterate through the whole list and add to free list // much faster than doing all of the rebalancing // also, do it so the free list is pointing to stuff in order // to get better cache coherence when re-adding stuff to this tree. I prev = InvalidIndex(); for (int i = (int)m_TotalElements; --i >= 0; ) { I idx = (I)i; if (IsValidIndex(idx)) Destruct( &Element(idx) ); SetRightChild( idx, prev ); SetLeftChild( idx, idx ); prev = idx; } m_FirstFree = m_TotalElements ? (I)0 : InvalidIndex(); m_Root = InvalidIndex(); m_NumElements = 0; } //----------------------------------------------------------------------------- // iteration //----------------------------------------------------------------------------- template I CUtlRBTree::FirstInorder() const { I i = m_Root; while (LeftChild(i) != InvalidIndex()) i = LeftChild(i); return i; } template I CUtlRBTree::NextInorder( I i ) const { Assert(IsValidIndex(i)); if (RightChild(i) != InvalidIndex()) { i = RightChild(i); while (LeftChild(i) != InvalidIndex()) i = LeftChild(i); return i; } I parent = Parent(i); while (IsRightChild(i)) { i = parent; if (i == InvalidIndex()) break; parent = Parent(i); } return parent; } template I CUtlRBTree::PrevInorder( I i ) const { Assert(IsValidIndex(i)); if (LeftChild(i) != InvalidIndex()) { i = LeftChild(i); while (RightChild(i) != InvalidIndex()) i = RightChild(i); return i; } I parent = Parent(i); while (IsLeftChild(i)) { i = parent; if (i == InvalidIndex()) break; parent = Parent(i); } return parent; } template I CUtlRBTree::LastInorder() const { I i = m_Root; while (RightChild(i) != InvalidIndex()) i = RightChild(i); return i; } template I CUtlRBTree::FirstPreorder() const { return m_Root; } template I CUtlRBTree::NextPreorder( I i ) const { if (LeftChild(i) != InvalidIndex()) return LeftChild(i); if (RightChild(i) != InvalidIndex()) return RightChild(i); I parent = Parent(i); while( parent != InvalidIndex()) { if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) return RightChild(parent); i = parent; parent = Parent(parent); } return InvalidIndex(); } template I CUtlRBTree::PrevPreorder( I i ) const { Assert(0); // not implemented yet return InvalidIndex(); } template I CUtlRBTree::LastPreorder() const { I i = m_Root; while (1) { while (RightChild(i) != InvalidIndex()) i = RightChild(i); if (LeftChild(i) != InvalidIndex()) i = LeftChild(i); else break; } return i; } template I CUtlRBTree::FirstPostorder() const { I i = m_Root; while (!IsLeaf(i)) { if (LeftChild(i)) i = LeftChild(i); else i = RightChild(i); } return i; } template I CUtlRBTree::NextPostorder( I i ) const { I parent = Parent(i); if (parent == InvalidIndex()) return InvalidIndex(); if (IsRightChild(i)) return parent; if (RightChild(parent) == InvalidIndex()) return parent; i = RightChild(parent); while (!IsLeaf(i)) { if (LeftChild(i)) i = LeftChild(i); else i = RightChild(i); } return i; } template void CUtlRBTree::Reinsert( I elem ) { Unlink( elem ); Link( elem ); } //----------------------------------------------------------------------------- // returns the tree depth (not a very fast operation) //----------------------------------------------------------------------------- template int CUtlRBTree::Depth( I node ) const { if (node == InvalidIndex()) return 0; int depthright = Depth( RightChild(node) ); int depthleft = Depth( LeftChild(node) ); return max(depthright, depthleft) + 1; } //----------------------------------------------------------------------------- // Makes sure the tree is valid after every operation //----------------------------------------------------------------------------- template bool CUtlRBTree::IsValid() const { if ( !Count() ) return true; if (( Root() >= MaxElement()) || ( Parent( Root() ) != InvalidIndex() )) goto InvalidTree; #ifdef UTLTREE_PARANOID // First check to see that mNumEntries matches reality. // count items on the free list int numFree = 0; int curr = m_FirstFree; while (curr != InvalidIndex()) { ++numFree; curr = RightChild(curr); if ( (curr > MaxElement()) && (curr != InvalidIndex()) ) goto InvalidTree; } if (MaxElement() - numFree != Count()) goto InvalidTree; // iterate over all elements, looking for validity // based on the self pointers int numFree2 = 0; for (curr = 0; curr < MaxElement(); ++curr) { if (!IsValidIndex(curr)) ++numFree2; else { int right = RightChild(curr); int left = LeftChild(curr); if ((right == left) && (right != InvalidIndex()) ) goto InvalidTree; if (right != InvalidIndex()) { if (!IsValidIndex(right)) goto InvalidTree; if (Parent(right) != curr) goto InvalidTree; if (IsRed(curr) && IsRed(right)) goto InvalidTree; } if (left != InvalidIndex()) { if (!IsValidIndex(left)) goto InvalidTree; if (Parent(left) != curr) goto InvalidTree; if (IsRed(curr) && IsRed(left)) goto InvalidTree; } } } if (numFree2 != numFree) goto InvalidTree; #endif // UTLTREE_PARANOID return true; InvalidTree: return false; } //----------------------------------------------------------------------------- // Sets the less func //----------------------------------------------------------------------------- template void CUtlRBTree::SetLessFunc( typename CUtlRBTree::LessFunc_t func ) { if (!m_LessFunc) m_LessFunc = func; else { // need to re-sort the tree here.... Assert(0); } } //----------------------------------------------------------------------------- // inserts a node into the tree //----------------------------------------------------------------------------- // Inserts a node into the tree, doesn't copy the data in. template void CUtlRBTree::FindInsertionPosition( T const &insert, I &parent, bool &leftchild ) { Assert( m_LessFunc ); /* find where node belongs */ I current = m_Root; parent = InvalidIndex(); leftchild = false; while (current != InvalidIndex()) { parent = current; if (m_LessFunc( insert, Element(current) )) { leftchild = true; current = LeftChild(current); } else { leftchild = false; current = RightChild(current); } } } template I CUtlRBTree::Insert( T const &insert ) { // use copy constructor to copy it in I parent; bool leftchild; FindInsertionPosition( insert, parent, leftchild ); I newNode = InsertAt( parent, leftchild ); CopyConstruct( &Element( newNode ), insert ); return newNode; } template void CUtlRBTree::Insert( const T *pArray, int nItems ) { while ( nItems-- ) { Insert( *pArray++ ); } } //----------------------------------------------------------------------------- // finds a node in the tree //----------------------------------------------------------------------------- template I CUtlRBTree::Find( T const &search ) const { Assert( m_LessFunc ); I current = m_Root; while (current != InvalidIndex()) { if (m_LessFunc( search, Element(current) )) current = LeftChild(current); else if (m_LessFunc( Element(current), search )) current = RightChild(current); else break; } return current; } #endif // UTLRBTREE_H