#ifndef UTLRBTREE_H #define UTLRBTREE_H #include "utlmemory.h" #include "utlfixedmemory.h" #include "utlblockmemory.h" #define FOR_EACH_UTLRBTREE( treeName, iteratorName ) \ for ( int iteratorName = treeName.FirstInorder(); (treeName).IsUtlRBTree && iteratorName != treeName.InvalidIndex(); iteratorName = treeName.NextInorder( iteratorName ) ) 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 (strcmp(lhs, rhs) < 0); } inline bool CaselessStringLessThan(const char* const& lhs, const char* const& rhs) { if (!lhs) return false; if (!rhs) return true; return (stricmp(lhs, rhs) < 0); } 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; 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; } if (*pa != *pb) { return (!*pa); } return false; } 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)); } enum CompareOperands_t { k_EEqual = 0x1, k_EGreaterThan = 0x2, k_ELessThan = 0x4, k_EGreaterThanOrEqualTo = k_EGreaterThan | k_EEqual, k_ELessThanOrEqualTo = k_ELessThan | k_EEqual, }; 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; enum { IsUtlRBTree = true }; typedef L LessFunc_t; explicit CUtlRBTree(int growSize = 0, int initSize = 0, const LessFunc_t& lessfunc = 0); explicit CUtlRBTree(const LessFunc_t& lessfunc); ~CUtlRBTree(); void EnsureCapacity(int num); void CopyFrom(const CUtlRBTree& other); T& Element(I i); T const& Element(I i) const; T& operator[](I i); T const& operator[](I i) const; I Root() const; unsigned int Count() const; I MaxElement() const; I Parent(I i) const; I LeftChild(I i) const; I RightChild(I i) const; bool IsLeftChild(I i) const; bool IsRightChild(I i) const; bool IsRoot(I i) const; bool IsLeaf(I i) const; bool IsValidIndex(I i) const; bool IsValid() const; static I InvalidIndex(); int Depth(I node) const; int Depth() const; void SetLessFunc(const LessFunc_t& func); I NewNode(); I Insert(T const& insert); void Insert(const T* pArray, int nItems); I InsertIfNotFound(T const& insert); I Find(T const& search) const; I FindFirst(T const& search) const; I FindClosest(T const& search, CompareOperands_t eFindCriteria) const; void RemoveAt(I i); bool Remove(T const& remove); void RemoveAll(); void Purge(); void FreeNode(I i); 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; void Reinsert(I elem); void Swap(CUtlRBTree< T, I, L >& that); private: 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; 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); Links_t const& Links(I i) const; Links_t& Links(I i); bool IsRed(I i) const; bool IsBlack(I i) const; NodeColor_t Color(I i) const; void SetColor(I i, NodeColor_t c); void RotateLeft(I i); void RotateRight(I i); void InsertRebalance(I i); void RemoveRebalance(I i); I InsertAt(I parent, bool leftchild); CUtlRBTree(CUtlRBTree const& tree); void FindInsertionPosition(T const& insert, I& parent, bool& leftchild); void Unlink(I elem); void Link(I elem); LessFunc_t m_LessFunc; M m_Elements; I m_Root; I m_NumElements; I m_FirstFree; typename M::Iterator_t m_LastAlloc; Node_t* m_pElements; FORCEINLINE M const& Elements(void) const { return m_Elements; } void ResetDbgInfo() { m_pElements = (Node_t*)m_Elements.Base(); } }; 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 if (BaseClass::Elements().IsIdxAfter(i, this->m_LastAlloc)) { Assert(0); return false; } #endif return LeftChild(i) != i; } protected: void ResetDbgInfo() {} private: I MaxElement() const; }; 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() {} }; template < class T, class I, typename L, class M > inline CUtlRBTree::CUtlRBTree(int growSize, int initSize, const LessFunc_t& lessfunc) : m_LessFunc(lessfunc), m_Elements(growSize, initSize), 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(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(); } template < class T, class I, typename L, class M > inline T& CUtlRBTree::Element(I i) { Assert(IsValidIndex(i)); return m_Elements[i].m_Data; } template < class T, class I, typename L, class M > inline T const& CUtlRBTree::Element(I i) const { Assert(IsValidIndex(i)); 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); } template < class T, class I, typename L, class M > inline I CUtlRBTree::Root() const { return m_Root; } template < class T, class I, typename L, class M > inline unsigned int CUtlRBTree::Count() const { return (unsigned int)m_NumElements; } template < class T, class I, typename L, class M > inline I CUtlRBTree::MaxElement() const { return (I)m_Elements.NumAllocated(); } template < class T, class I, typename L, class M > inline I CUtlRBTree::Parent(I i) const { return i != InvalidIndex() ? m_Elements[i].m_Parent : InvalidIndex(); } template < class T, class I, typename L, class M > inline I CUtlRBTree::LeftChild(I i) const { return i != InvalidIndex() ? m_Elements[i].m_Left : InvalidIndex(); } template < class T, class I, typename L, class M > inline I CUtlRBTree::RightChild(I i) const { return i != InvalidIndex() ? m_Elements[i].m_Right : InvalidIndex(); } 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; } 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()); } 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_Elements.IsIdxAfter(i, m_LastAlloc)) return false; return LeftChild(i) != i; } template < class T, class I, typename L, class M > inline I CUtlRBTree::InvalidIndex() { return (I)M::InvalidIndex(); } template < class T, class I, typename L, class M > inline int CUtlRBTree::Depth() const { return Depth(Root()); } 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; } template < class T, class I, typename L, class M > inline typename CUtlRBTree::Links_t const& CUtlRBTree::Links(I i) const { static const Links_t s_Sentinel = { M::INVALID_INDEX, M::INVALID_INDEX, M::INVALID_INDEX, CUtlRBTree::BLACK }; return (i != InvalidIndex()) ? m_Elements[i] : s_Sentinel; } template < class T, class I, typename L, class M > inline typename CUtlRBTree::Links_t& CUtlRBTree::Links(I i) { Assert(i != InvalidIndex()); return m_Elements[i]; } template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsRed(I i) const { return Color(i) == RED; } template < class T, class I, typename L, class M > inline bool CUtlRBTree::IsBlack(I i) const { return Color(i) == BLACK; } template < class T, class I, typename L, class M > inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color(I i) const { return (NodeColor_t)(i != InvalidIndex() ? m_Elements[i].m_Tag : BLACK); } 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; } #pragma warning(push) #pragma warning(disable:4389) template < class T, class I, typename L, class M > I CUtlRBTree::NewNode() { I elem; 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 = RightChild(m_FirstFree); } #ifdef _DEBUG 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); SetRightChild(i, m_FirstFree); m_FirstFree = i; } 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); } 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); } 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); if (IsLeftChild(parent)) { I uncle = RightChild(grandparent); if (IsRed(uncle)) { SetColor(parent, BLACK); SetColor(uncle, BLACK); SetColor(grandparent, RED); elem = grandparent; } else { if (IsRightChild(elem)) { elem = parent; RotateLeft(elem); parent = Parent(elem); grandparent = Parent(parent); } SetColor(parent, BLACK); SetColor(grandparent, RED); RotateRight(grandparent); } } else { I uncle = LeftChild(grandparent); if (IsRed(uncle)) { SetColor(parent, BLACK); SetColor(uncle, BLACK); SetColor(grandparent, RED); elem = grandparent; } else { if (IsLeftChild(elem)) { elem = parent; RotateRight(parent); parent = Parent(elem); grandparent = Parent(parent); } SetColor(parent, BLACK); SetColor(grandparent, RED); RotateLeft(grandparent); } } } SetColor(m_Root, BLACK); } 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; if (parent != InvalidIndex()) { if (isLeft) Links(parent).m_Left = i; else Links(parent).m_Right = i; } else { m_Root = i; } InsertRebalance(i); } 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 == LeftChild(parent)) { I sibling = RightChild(parent); if (IsRed(sibling)) { SetColor(sibling, BLACK); SetColor(parent, RED); RotateLeft(parent); 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); parent = Parent(elem); sibling = RightChild(parent); } SetColor(sibling, Color(parent)); SetColor(parent, BLACK); SetColor(RightChild(sibling), BLACK); RotateLeft(parent); elem = m_Root; } } else { I sibling = LeftChild(parent); if (IsRed(sibling)) { SetColor(sibling, BLACK); SetColor(parent, RED); RotateRight(parent); 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); 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 = elem; } else { y = RightChild(elem); while (LeftChild(y) != InvalidIndex()) y = LeftChild(y); } if (LeftChild(y) != InvalidIndex()) x = LeftChild(y); else x = RightChild(y); 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; NodeColor_t ycolor = Color(y); if (y != elem) { 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 = InvalidIndex(); bool leftchild = false; FindInsertionPosition(Element(elem), parent, leftchild); LinkToParent(elem, parent, leftchild); Assert(IsValid()); } } 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()); } } 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; } template < class T, class I, typename L, class M > void CUtlRBTree::RemoveAll() { 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)) { Destruct(&Element(i)); SetRightChild(i, m_FirstFree); SetLeftChild(i, i); m_FirstFree = i; } if (it == m_LastAlloc) break; } m_Root = InvalidIndex(); m_NumElements = 0; Assert(IsValid()); } template < class T, class I, typename L, class M > void CUtlRBTree::Purge() { RemoveAll(); m_FirstFree = InvalidIndex(); m_Elements.Purge(); m_LastAlloc = m_Elements.InvalidIterator(); } template < class T, class I, typename L, class M > I CUtlRBTree::FirstInorder() const { I i = m_Root; I left; while ((left = LeftChild(i)) != InvalidIndex()) i = left; return i; } template < class T, class I, typename L, class M > I CUtlRBTree::NextInorder(I i) const { Assert(IsValidIndex(i)); I right; if ((right = RightChild(i)) != InvalidIndex()) { i = right; I left; while ((left = LeftChild(i)) != InvalidIndex()) i = left; 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 { Assert(IsValidIndex(i)); I left, right; if ((left = LeftChild(i)) != InvalidIndex()) { i = left; while ((right = RightChild(i)) != InvalidIndex()) i = right; 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; I right; while ((right = RightChild(i)) != InvalidIndex()) i = right; 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 { I left, right; if ((left = LeftChild(i)) != InvalidIndex()) return left; if ((right = RightChild(i)) != InvalidIndex()) return right; 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); return InvalidIndex(); } template < class T, class I, typename L, class M > I CUtlRBTree::LastPreorder() const { I i = m_Root; while (1) { I left, right; while ((right = RightChild(i)) != InvalidIndex()) i = right; if ((left = LeftChild(i)) != InvalidIndex()) i = left; else break; } return i; } template < class T, class I, typename L, class M > I CUtlRBTree::FirstPostorder() const { I i = m_Root; while (!IsLeaf(i)) { I left; if ((left = LeftChild(i)) != InvalidIndex()) i = left; 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)) { I left; if ((left = LeftChild(i)) != InvalidIndex()) i = left; else i = RightChild(i); } return i; } template < class T, class I, typename L, class M > void CUtlRBTree::Reinsert(I elem) { Unlink(elem); Link(elem); } 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; } 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 int numFree = 0; for (int i = m_FirstFree; i != InvalidIndex(); i = RightChild(i)) { ++numFree; if (!m_Elements.IsIdxValid(i)) return false; } 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 return true; } 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) { Assert(0); } } template < class T, class I, typename L, class M > void CUtlRBTree::FindInsertionPosition(T const& insert, I& parent, bool& leftchild) { Assert(!!m_LessFunc); 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) { I parent = InvalidIndex(); bool leftchild = false; 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) { 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 return InvalidIndex(); } I newNode = InsertAt(parent, leftchild); CopyConstruct(&Element(newNode), insert); return newNode; } 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; } template I CUtlRBTree::FindFirst(T const& search) const { Assert(!!m_LessFunc); I current = m_Root; I best = InvalidIndex(); while (current != InvalidIndex()) { if (m_LessFunc(search, Element(current))) current = LeftChild(current); else if (m_LessFunc(Element(current), search)) current = RightChild(current); else { best = current; current = LeftChild(current); } } return best; } template I CUtlRBTree::FindClosest(T const& search, CompareOperands_t eFindCriteria) const { Assert(!!m_LessFunc); Assert((eFindCriteria & (k_EGreaterThan | k_ELessThan)) ^ (k_EGreaterThan | k_ELessThan)); I current = m_Root; I best = InvalidIndex(); while (current != InvalidIndex()) { if (m_LessFunc(search, Element(current))) { if (eFindCriteria & k_EGreaterThan) best = current; current = LeftChild(current); } else if (m_LessFunc(Element(current), search)) { if (eFindCriteria & k_ELessThan) best = current; current = RightChild(current); } else { if (eFindCriteria & k_EEqual) { best = current; break; } else if (eFindCriteria & k_EGreaterThan) { current = RightChild(current); } else if (eFindCriteria & k_ELessThan) { current = LeftChild(current); } } } return best; } 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