/* * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as a special exception, the author gives permission to * link the code of this program with the Half-Life Game Engine ("HL * Engine") and Modified Game Libraries ("MODs") developed by Valve, * L.L.C ("Valve"). You must obey the GNU General Public License in all * respects for all of the code used other than the HL Engine and MODs * from Valve. If you modify this file, you may extend this exception * to your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. * */ #pragma once #include "utlmemory.h" // 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); } // 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; }; // A red-black binary search tree 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, LessFunc_t lessfunc = 0); ~CUtlRBTree(); // gets particular elements T& Element(I i); T const& Element(I i) const; T& operator[](I i); T const& operator[](I i) const; // Gets the root I Root() const; // Num elements unsigned int Count() const; // Max "size" of the vector I MaxElement() const; // Gets the children I Parent(I i) const; I LeftChild(I i) const; I RightChild(I i) const; // Tests if a node is a left or right child bool IsLeftChild(I i) const; bool IsRightChild(I i) const; // Tests if root or leaf bool IsRoot(I i) const; bool IsLeaf(I i) const; // Checks if a node is valid and in the tree bool IsValidIndex(I i) const; // Checks if the tree as a whole is valid bool IsValid() const; // Invalid index static I InvalidIndex(); // returns the tree depth (not a very fast operation) int Depth(I node) const; int Depth() const; // Sets the less func void SetLessFunc(LessFunc_t func); // Allocation method I NewNode(); // Insert method (inserts in order) I Insert(T const &insert); void Insert(const T *pArray, int nItems); // Find method I Find(T const &search) const; // Remove methods void RemoveAt(I i); bool Remove(T const &remove); void RemoveAll(); // Allocation, deletion void FreeNode(I i); // Iteration I FirstInorder() const; I NextInorder(I i) const; I PrevInorder(I i) const; I LastInorder() const; I FirstPreorder() const; I NextPreorder(I i) const; I PrevPreorder(I i) const; I LastPreorder() const; I FirstPostorder() const; I NextPostorder(I i) const; // If you change the search key, this can be used to reinsert the // element into the tree. void Reinsert(I elem); 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; I m_TotalElements; }; // Constructor, Destructor template <class T, class I, typename L, class M> CUtlRBTree<T, I, L, M>::CUtlRBTree(int growSize, int initSize, LessFunc_t lessfunc) : m_Elements(growSize, initSize), m_LessFunc(lessfunc), m_Root(InvalidIndex()), m_NumElements(0), m_TotalElements(0), m_FirstFree(InvalidIndex()) { } template <class T, class I, typename L, class M> CUtlRBTree<T, I, L, M>::~CUtlRBTree() { } // 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); } // 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_TotalElements; } // 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 { return LeftChild(i) != i; } // Invalid index template <class T, class I, typename L, class M> 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 template <class T, class I, typename L, class M> I CUtlRBTree<T, I, L, M>::NewNode() { I newElem; // Nothing in the free list; add. if (m_FirstFree == InvalidIndex()) { if (m_Elements.NumAllocated() == m_TotalElements) m_Elements.Grow(); newElem = m_TotalElements++; } else { newElem = m_FirstFree; m_FirstFree = RightChild(m_FirstFree); } #ifdef _DEBUG // reset links to invalid.... Links_t &node = Links(newElem); node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); #endif Construct(&Element(newElem)); return newElem; } 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++; 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); Assert(IsValid()); } // 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); } } // 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--; } } // 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() { // Just iterate through the whole list and add to free list // much faster than doing all of the rebalancing // also, do it so the free list is pointing to stuff in order // to get better cache coherence when re-adding stuff to this tree. I prev = InvalidIndex(); for (int i = (int)m_TotalElements; --i >= 0;) { I idx = (I)i; if (IsValidIndex(idx)) Destruct(&Element(idx)); SetRightChild(idx, prev); SetLeftChild(idx, idx); prev = idx; } m_FirstFree = m_TotalElements ? (I)0 : InvalidIndex(); m_Root = InvalidIndex(); m_NumElements = 0; } // Iteration template <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; } // 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 ((Root() >= MaxElement()) || (Parent(Root()) != InvalidIndex())) goto InvalidTree; #ifdef UTLTREE_PARANOID // First check to see that mNumEntries matches reality. // count items on the free list int numFree = 0; int curr = m_FirstFree; while (curr != InvalidIndex()) { numFree++; curr = RightChild(curr); if ((curr > MaxElement()) && (curr != InvalidIndex())) goto InvalidTree; } if (MaxElement() - numFree != Count()) goto InvalidTree; // Iterate over all elements, looking for validity // based on the self pointers int numFree2 = 0; for (curr = 0; curr < MaxElement(); curr++) { if (!IsValidIndex(curr)) numFree2++; else { int right = RightChild(curr); int left = LeftChild(curr); if ((right == left) && (right != InvalidIndex())) goto InvalidTree; if (right != InvalidIndex()) { if (!IsValidIndex(right)) goto InvalidTree; if (Parent(right) != curr) goto InvalidTree; if (IsRed(curr) && IsRed(right)) goto InvalidTree; } if (left != InvalidIndex()) { if (!IsValidIndex(left)) goto InvalidTree; if (Parent(left) != curr) goto InvalidTree; if (IsRed(curr) && IsRed(left)) goto InvalidTree; } } } if (numFree2 != numFree) goto InvalidTree; #endif // UTLTREE_PARANOID return true; InvalidTree: return false; } // Sets the less func template <class T, class I, typename L, class M> void CUtlRBTree<T, I, L, M>::SetLessFunc(typename CUtlRBTree<T, I, L, M>::LessFunc_t func) { if (!m_LessFunc) m_LessFunc = func; else { // Need to re-sort the tree here.... Assert(0); } } // Inserts a node into the tree, 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++); } } // 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; }