//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $Header: $ // $NoKeywords: $ //=============================================================================// #ifndef UTLRBTREE_H #define UTLRBTREE_H #include "tier1/utlmemory.h" #include "tier1/utlfixedmemory.h" #include "tier1/utlblockmemory.h" #include "tier1/strtools.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< type >::LessFunc template class CDefLess { public: CDefLess() {} CDefLess( int i ) {} inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs < rhs ); } inline bool operator!() const { return false; } }; //------------------------------------- inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { if ( !lhs ) return false; if ( !rhs ) return true; return ( V_strcmp( lhs, rhs) < 0 ); } inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { if ( !lhs ) return false; if ( !rhs ) return true; return ( V_stricmp( lhs, rhs) < 0 ); } // Same as CaselessStringLessThan, but it ignores differences in / and \. inline bool CaselessStringLessThanIgnoreSlashes( const char * const &lhs, const char * const &rhs ) { const char *pa = lhs; const char *pb = rhs; while ( *pa && *pb ) { char a = *pa; char b = *pb; // Check for dir slashes. if ( a == '/' || a == '\\' ) { if ( b != '/' && b != '\\' ) return ('/' < b); } else { if ( a >= 'a' && a <= 'z' ) a = 'A' + (a - 'a'); if ( b >= 'a' && b <= 'z' ) b = 'A' + (b - 'a'); if ( a > b ) return false; else if ( a < b ) return true; } ++pa; ++pb; } // Filenames also must be the same length. if ( *pa != *pb ) { // If pa shorter than pb then it's "less" return ( !*pa ); } return false; } //------------------------------------- // 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 ) { RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); } //----------------------------------------------------------------------------- // A red-black binary search tree //----------------------------------------------------------------------------- template < class I > struct UtlRBTreeLinks_t { I m_Left; I m_Right; I m_Parent; I m_Tag; }; template < class T, class I > struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I > { T m_Data; }; template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > > class CUtlRBTree { public: typedef T KeyType_t; typedef T ElemType_t; typedef I IndexType_t; // Less func typedef // Returns true if the first parameter is "less" than the second typedef L LessFunc_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, const LessFunc_t &lessfunc = 0 ); CUtlRBTree( const LessFunc_t &lessfunc ); ~CUtlRBTree( ); void EnsureCapacity( int num ); void CopyFrom( const CUtlRBTree &other ); // 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 // it's not generally safe to iterate from index 0 to MaxElement()-1 // it IS safe to do so when using CUtlMemory as the allocator, // but we should really remove patterns using this anyways, for safety and generality 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( const LessFunc_t &func ); // Allocation method I NewNode(); // Insert method (inserts in order) I Insert( T const &insert ); void Insert( const T *pArray, int nItems ); I InsertIfNotFound( T const &insert ); // Find method I Find( T const &search ) const; // Remove methods void RemoveAt( I i ); bool Remove( T const &remove ); void RemoveAll( ); void Purge(); bool HasElement( T const &search ) const { return Find( search ) != InvalidIndex(); } // 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 ); // swap in place void Swap( CUtlRBTree< T, I, L > &that ); private: // Can't copy the tree this way! CUtlRBTree& operator=( const CUtlRBTree &other ); protected: enum NodeColor_t { RED = 0, BLACK }; typedef UtlRBTreeNode_t< T, I > Node_t; typedef UtlRBTreeLinks_t< I > Links_t; // 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; M m_Elements; I m_Root; I m_NumElements; I m_FirstFree; typename M::Iterator_t m_LastAlloc; // the last index allocated Node_t* m_pElements; FORCEINLINE M const &Elements( void ) const { return m_Elements; } void ResetDbgInfo() { m_pElements = (Node_t*)m_Elements.Base(); } }; // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice template < class T, class I = int, typename L = bool (*)( const T &, const T & ) > class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > { public: typedef L LessFunc_t; CUtlFixedRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( growSize, initSize, lessfunc ) {} CUtlFixedRBTree( const LessFunc_t &lessfunc ) : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( lessfunc ) {} typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass; bool IsValidIndex( I i ) const { if ( !BaseClass::Elements().IsIdxValid( i ) ) return false; #ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElement() if ( BaseClass::Elements().IsIdxAfter( i, this->m_LastAlloc ) ) { Assert( 0 ); return false; // don't read values that have been allocated, but not constructed } #endif return LeftChild(i) != i; } protected: void ResetDbgInfo() {} private: // this doesn't make sense for fixed rbtrees, since there's no useful max pointer, and the index space isn't contiguous anyways I MaxElement() const; }; // this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ) > class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > > { public: typedef L LessFunc_t; CUtlBlockRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( growSize, initSize, lessfunc ) {} CUtlBlockRBTree( const LessFunc_t &lessfunc ) : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( lessfunc ) {} protected: void ResetDbgInfo() {} }; //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline CUtlRBTree::CUtlRBTree( int growSize, int initSize, const LessFunc_t &lessfunc ) : m_Elements( growSize, initSize ), m_LessFunc( lessfunc ), m_Root( InvalidIndex() ), m_NumElements( 0 ), m_FirstFree( InvalidIndex() ), m_LastAlloc( m_Elements.InvalidIterator() ) { ResetDbgInfo(); } template < class T, class I, typename L, class M > inline CUtlRBTree::CUtlRBTree( const LessFunc_t &lessfunc ) : m_Elements( 0, 0 ), m_LessFunc( lessfunc ), m_Root( InvalidIndex() ), m_NumElements( 0 ), m_FirstFree( InvalidIndex() ), m_LastAlloc( m_Elements.InvalidIterator() ) { ResetDbgInfo(); } template < class T, class I, typename L, class M > inline CUtlRBTree::~CUtlRBTree() { Purge(); } template < class T, class I, typename L, class M > inline void CUtlRBTree::EnsureCapacity( int num ) { m_Elements.EnsureCapacity( num ); } template < class T, class I, typename L, class M > inline void CUtlRBTree::CopyFrom( const CUtlRBTree &other ) { Purge(); m_Elements.EnsureCapacity( other.m_Elements.Count() ); memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( T ) ); m_LessFunc = other.m_LessFunc; m_Root = other.m_Root; m_NumElements = other.m_NumElements; m_FirstFree = other.m_FirstFree; m_LastAlloc = other.m_LastAlloc; ResetDbgInfo(); } //----------------------------------------------------------------------------- // gets particular elements //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline T &CUtlRBTree::Element( I i ) { return m_Elements[i].m_Data; } template < class T, class I, typename L, class M > inline T const &CUtlRBTree::Element( I i ) const { return m_Elements[i].m_Data; } template < class T, class I, typename L, class M > inline T &CUtlRBTree::operator[]( I i ) { return Element(i); } template < class T, class I, typename L, class M > inline T const &CUtlRBTree::operator[]( I i ) const { return Element(i); } //----------------------------------------------------------------------------- // // various accessors // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Gets the root //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline I CUtlRBTree::Root() const { return m_Root; } //----------------------------------------------------------------------------- // Num elements //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline unsigned int CUtlRBTree::Count() const { return (unsigned int)m_NumElements; } //----------------------------------------------------------------------------- // Max "size" of the vector //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline I CUtlRBTree::MaxElement() const { return ( I )m_Elements.NumAllocated(); } //----------------------------------------------------------------------------- // Gets the children //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline I CUtlRBTree::Parent( I i ) const { return Links(i).m_Parent; } template < class T, class I, typename L, class M > inline I CUtlRBTree::LeftChild( I i ) const { return Links(i).m_Left; } template < class T, class I, typename L, class M > inline I CUtlRBTree::RightChild( I i ) const { return Links(i).m_Right; } //----------------------------------------------------------------------------- // Tests if a node is a left or right child //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsLeftChild( I i ) const { return LeftChild(Parent(i)) == i; } template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsRightChild( I i ) const { return RightChild(Parent(i)) == i; } //----------------------------------------------------------------------------- // Tests if root or leaf //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsRoot( I i ) const { return i == m_Root; } template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > inline bool CUtlRBTree::IsValidIndex( I i ) const { if ( !m_Elements.IsIdxValid( i ) ) return false; if ( m_LastAlloc == m_Elements.InvalidIndex() || m_Elements.IsIdxAfter( i, m_LastAlloc ) ) return false; // don't read values that have been allocated, but not constructed return LeftChild(i) != i; } //----------------------------------------------------------------------------- // Invalid index //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline I CUtlRBTree::InvalidIndex() { return ( I )M::InvalidIndex(); } //----------------------------------------------------------------------------- // returns the tree depth (not a very fast operation) //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline int CUtlRBTree::Depth() const { return Depth(Root()); } //----------------------------------------------------------------------------- // Sets the children //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline void CUtlRBTree::SetParent( I i, I parent ) { Links(i).m_Parent = parent; } template < class T, class I, typename L, class M > inline void CUtlRBTree::SetLeftChild( I i, I child ) { Links(i).m_Left = child; } template < class T, class I, typename L, class M > inline void CUtlRBTree::SetRightChild( I i, I child ) { Links(i).m_Right = child; } //----------------------------------------------------------------------------- // Gets at the links //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > inline bool CUtlRBTree::IsRed( I i ) const { return (Links(i).m_Tag == RED); } template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsBlack( I i ) const { return (Links(i).m_Tag == BLACK); } //----------------------------------------------------------------------------- // Sets/gets node color //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color( I i ) const { return (NodeColor_t)Links(i).m_Tag; } template < class T, class I, typename L, class M > inline void CUtlRBTree::SetColor( I i, typename CUtlRBTree::NodeColor_t c ) { Links(i).m_Tag = (I)c; } //----------------------------------------------------------------------------- // Allocates/ deallocates nodes //----------------------------------------------------------------------------- #pragma warning(push) #pragma warning(disable:4389) // '==' : signed/unsigned mismatch template < class T, class I, typename L, class M > I CUtlRBTree::NewNode() { I elem; // Nothing in the free list; add. if ( m_FirstFree == InvalidIndex() ) { Assert( m_Elements.IsValidIterator( m_LastAlloc ) || m_NumElements == 0 ); typename M::Iterator_t it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); if ( !m_Elements.IsValidIterator( it ) ) { MEM_ALLOC_CREDIT_CLASS(); m_Elements.Grow(); it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); Assert( m_Elements.IsValidIterator( it ) ); if ( !m_Elements.IsValidIterator( it ) ) { Error( "CUtlRBTree overflow!\n" ); } } m_LastAlloc = it; elem = m_Elements.GetIndex( m_LastAlloc ); Assert( m_Elements.IsValidIterator( m_LastAlloc ) ); } else { elem = m_FirstFree; m_FirstFree = Links( m_FirstFree ).m_Right; } #ifdef _DEBUG // reset links to invalid.... Links_t &node = Links( elem ); node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); #endif Construct( &Element( elem ) ); ResetDbgInfo(); return elem; } #pragma warning(pop) template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > I CUtlRBTree::InsertAt( I parent, bool leftchild ) { I i = NewNode(); LinkToParent( i, parent, leftchild ); ++m_NumElements; Assert(IsValid()); return i; } template < class T, class I, typename L, class M > 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); } //----------------------------------------------------------------------------- // Rebalance the tree after a deletion //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > void CUtlRBTree::Link( I elem ) { if ( elem != InvalidIndex() ) { I parent; bool leftchild; FindInsertionPosition( Element( elem ), parent, leftchild ); LinkToParent( elem, parent, leftchild ); Assert(IsValid()); } } //----------------------------------------------------------------------------- // Delete a node from the tree //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > void CUtlRBTree::RemoveAt(I elem) { if ( elem != InvalidIndex() ) { Unlink( elem ); FreeNode(elem); --m_NumElements; Assert(IsValid()); } } //----------------------------------------------------------------------------- // remove a node in the tree //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > void CUtlRBTree::RemoveAll() { // Have to do some convoluted stuff to invoke the destructor on all // valid elements for the multilist case (since we don't have all elements // connected to each other in a list). if ( m_LastAlloc == m_Elements.InvalidIterator() ) { Assert( m_Root == InvalidIndex() ); Assert( m_FirstFree == InvalidIndex() ); Assert( m_NumElements == 0 ); return; } for ( typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) { I i = m_Elements.GetIndex( it ); if ( IsValidIndex( i ) ) // skip elements in the free list { Destruct( &Element( i ) ); SetRightChild( i, m_FirstFree ); SetLeftChild( i, i ); m_FirstFree = i; } if ( it == m_LastAlloc ) break; // don't destruct elements that haven't ever been constucted } // Clear everything else out m_Root = InvalidIndex(); // Technically, this iterator could become invalid. It will not, because it's // always the same iterator. If we don't clear this here, the state of this // container will be invalid after we start inserting elements again. m_LastAlloc = m_Elements.InvalidIterator(); m_FirstFree = InvalidIndex(); m_NumElements = 0; Assert( IsValid() ); } //----------------------------------------------------------------------------- // Removes all nodes from the tree and purges memory //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > void CUtlRBTree::Purge() { RemoveAll(); m_Elements.Purge(); } //----------------------------------------------------------------------------- // iteration //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > I CUtlRBTree::FirstInorder() const { I i = m_Root; while (LeftChild(i) != InvalidIndex()) i = LeftChild(i); return i; } template < class T, class I, typename L, class M > I CUtlRBTree::NextInorder( I i ) const { // Don't go into an infinite loop if it's a bad index Assert(IsValidIndex(i)); if ( !IsValidIndex(i) ) return InvalidIndex(); 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 < class T, class I, typename L, class M > I CUtlRBTree::PrevInorder( I i ) const { // Don't go into an infinite loop if it's a bad index Assert(IsValidIndex(i)); if ( !IsValidIndex(i) ) return InvalidIndex(); 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 < class T, class I, typename L, class M > I CUtlRBTree::LastInorder() const { I i = m_Root; while (RightChild(i) != InvalidIndex()) i = RightChild(i); return i; } template < class T, class I, typename L, class M > I CUtlRBTree::FirstPreorder() const { return m_Root; } template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > I CUtlRBTree::PrevPreorder( I i ) const { Assert(0); // not implemented yet return InvalidIndex(); } template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > I CUtlRBTree::FirstPostorder() const { I i = m_Root; while (!IsLeaf(i)) { if (LeftChild(i)) i = LeftChild(i); else i = RightChild(i); } return i; } template < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > void CUtlRBTree::Reinsert( I elem ) { Unlink( elem ); Link( elem ); } //----------------------------------------------------------------------------- // returns the tree depth (not a very fast operation) //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > 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; } //#define UTLTREE_PARANOID //----------------------------------------------------------------------------- // Makes sure the tree is valid after every operation //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > bool CUtlRBTree::IsValid() const { if ( !Count() ) return true; if ( m_LastAlloc == m_Elements.InvalidIterator() ) return false; if ( !m_Elements.IsIdxValid( Root() ) ) return false; if ( Parent( Root() ) != InvalidIndex() ) return false; #ifdef UTLTREE_PARANOID // First check to see that mNumEntries matches reality. // count items on the free list int numFree = 0; for ( int i = m_FirstFree; i != InvalidIndex(); i = RightChild( i ) ) { ++numFree; if ( !m_Elements.IsIdxValid( i ) ) return false; } // iterate over all elements, looking for validity // based on the self pointers int nElements = 0; int numFree2 = 0; for ( M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) { I i = m_Elements.GetIndex( it ); if ( !IsValidIndex( i ) ) { ++numFree2; } else { ++nElements; int right = RightChild( i ); int left = LeftChild( i ); if ( ( right == left ) && ( right != InvalidIndex() ) ) return false; if ( right != InvalidIndex() ) { if ( !IsValidIndex( right ) ) return false; if ( Parent( right ) != i ) return false; if ( IsRed( i ) && IsRed( right ) ) return false; } if ( left != InvalidIndex() ) { if ( !IsValidIndex( left ) ) return false; if ( Parent( left ) != i ) return false; if ( IsRed( i ) && IsRed( left ) ) return false; } } if ( it == m_LastAlloc ) break; } if ( numFree2 != numFree ) return false; if ( nElements != m_NumElements ) return false; #endif // UTLTREE_PARANOID return true; } //----------------------------------------------------------------------------- // Sets the less func //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > void CUtlRBTree::SetLessFunc( const typename CUtlRBTree::LessFunc_t &func ) { if (!m_LessFunc) { m_LessFunc = func; } else if ( Count() > 0 ) { // 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > 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 < class T, class I, typename L, class M > void CUtlRBTree::Insert( const T *pArray, int nItems ) { while ( nItems-- ) { Insert( *pArray++ ); } } template < class T, class I, typename L, class M > I CUtlRBTree::InsertIfNotFound( T const &insert ) { // use copy constructor to copy it in I parent; bool leftchild; 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 if (m_LessFunc( Element(current), insert )) { leftchild = false; current = RightChild(current); } else // Match found, no insertion return InvalidIndex(); } I newNode = InsertAt( parent, leftchild ); CopyConstruct( &Element( newNode ), insert ); return newNode; } //----------------------------------------------------------------------------- // finds a node in the tree //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > 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; } //----------------------------------------------------------------------------- // swap in place //----------------------------------------------------------------------------- template < class T, class I, typename L, class M > void CUtlRBTree::Swap( CUtlRBTree< T, I, L > &that ) { m_Elements.Swap( that.m_Elements ); V_swap( m_LessFunc, that.m_LessFunc ); V_swap( m_Root, that.m_Root ); V_swap( m_NumElements, that.m_NumElements ); V_swap( m_FirstFree, that.m_FirstFree ); V_swap( m_pElements, that.m_pElements ); V_swap( m_LastAlloc, that.m_LastAlloc ); Assert( IsValid() ); Assert( m_Elements.IsValidIterator( m_LastAlloc ) || ( m_NumElements == 0 && m_FirstFree == InvalidIndex() ) ); } #endif // UTLRBTREE_H