1569 lines
41 KiB
C++
1569 lines
41 KiB
C++
//========= Copyright <20> 1996-2005, 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"
|
||
|
||
|
||
// This is a useful macro to iterate from start to end in order in a map
|
||
#define FOR_EACH_UTLRBTREE( treeName, iteratorName ) \
|
||
for ( int iteratorName = treeName.FirstInorder(); iteratorName != treeName.InvalidIndex(); iteratorName = treeName.NextInorder( iteratorName ) )
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Tool to generate a default compare function for any type that implements
|
||
// operator<, including all simple types
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template <typename T >
|
||
class CDefOps
|
||
{
|
||
public:
|
||
static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); }
|
||
};
|
||
|
||
#define DefLessFunc( type ) CDefOps< type >::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 ); }
|
||
|
||
|
||
// 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<const char *>::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); }
|
||
template <> inline bool CDefOps<char *>::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); }
|
||
|
||
//-------------------------------------
|
||
|
||
template <typename RBTREE_T>
|
||
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<T, I, L, M> &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();
|
||
|
||
// 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<T, I, L, M>& operator=( const CUtlRBTree<T, I, L, M> &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<T, I, L, M> 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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::~CUtlRBTree()
|
||
{
|
||
Purge();
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::EnsureCapacity( int num )
|
||
{
|
||
m_Elements.EnsureCapacity( num );
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::CopyFrom( const CUtlRBTree<T, I, L, M> &other )
|
||
{
|
||
Purge();
|
||
m_Elements.EnsureCapacity( other.m_Elements.Count() );
|
||
memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( UtlRBTreeNode_t< T, I > ) );
|
||
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<T, I, L, M>::Element( I i )
|
||
{
|
||
return m_Elements[i].m_Data;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline T const &CUtlRBTree<T, I, L, M>::Element( I i ) const
|
||
{
|
||
return m_Elements[i].m_Data;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline T &CUtlRBTree<T, I, L, M>::operator[]( I i )
|
||
{
|
||
return Element(i);
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline T const &CUtlRBTree<T, I, L, M>::operator[]( I i ) const
|
||
{
|
||
return Element(i);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//
|
||
// various accessors
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Gets the root
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline I CUtlRBTree<T, I, L, M>::Root() const
|
||
{
|
||
return m_Root;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Num elements
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline unsigned int CUtlRBTree<T, I, L, M>::Count() const
|
||
{
|
||
return (unsigned int)m_NumElements;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Max "size" of the vector
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline I CUtlRBTree<T, I, L, M>::MaxElement() const
|
||
{
|
||
return ( I )m_Elements.NumAllocated();
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Gets the children
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline I CUtlRBTree<T, I, L, M>::Parent( I i ) const
|
||
{
|
||
return Links(i).m_Parent;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline I CUtlRBTree<T, I, L, M>::LeftChild( I i ) const
|
||
{
|
||
return Links(i).m_Left;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::IsLeftChild( I i ) const
|
||
{
|
||
return LeftChild(Parent(i)) == i;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline bool CUtlRBTree<T, I, L, M>::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<T, I, L, M>::IsRoot( I i ) const
|
||
{
|
||
return i == m_Root;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline bool CUtlRBTree<T, I, L, M>::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<T, I, L, M>::IsValidIndex( I i ) const
|
||
{
|
||
if ( !m_Elements.IsIdxValid( i ) )
|
||
return false;
|
||
|
||
if ( 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<T, I, L, M>::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<T, I, L, M>::Depth() const
|
||
{
|
||
return Depth(Root());
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// Sets the children
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::SetParent( I i, I parent )
|
||
{
|
||
Links(i).m_Parent = parent;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::SetLeftChild( I i, I child )
|
||
{
|
||
Links(i).m_Left = child;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::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<T, I, L, M>::Links_t const &CUtlRBTree<T, I, L, M>::Links( I i ) const
|
||
{
|
||
// Sentinel node, makes life easier
|
||
static Links_t s_Sentinel =
|
||
{
|
||
InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree<T, I, L, M>::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<T, I, L, M>::Links_t &CUtlRBTree<T, I, L, M>::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<T, I, L, M>::IsRed( I i ) const
|
||
{
|
||
return (Links(i).m_Tag == RED);
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline bool CUtlRBTree<T, I, L, M>::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<T, I, L, M>::NodeColor_t CUtlRBTree<T, I, L, M>::Color( I i ) const
|
||
{
|
||
return (NodeColor_t)Links(i).m_Tag;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
inline void CUtlRBTree<T, I, L, M>::SetColor( I i, typename CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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();
|
||
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<T, I, L, M>::Purge()
|
||
{
|
||
RemoveAll();
|
||
m_FirstFree = InvalidIndex();
|
||
m_Elements.Purge();
|
||
m_LastAlloc = m_Elements.InvalidIterator();
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// iteration
|
||
//-----------------------------------------------------------------------------
|
||
|
||
template < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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 < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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 < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::FirstPreorder() const
|
||
{
|
||
return m_Root;
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::PrevPreorder( I i ) const
|
||
{
|
||
Assert(0); // not implemented yet
|
||
return InvalidIndex();
|
||
}
|
||
|
||
template < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::SetLessFunc( const typename CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::Insert( const T *pArray, int nItems )
|
||
{
|
||
while ( nItems-- )
|
||
{
|
||
Insert( *pArray++ );
|
||
}
|
||
}
|
||
|
||
|
||
template < class T, class I, typename L, class M >
|
||
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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
|