Seaside/SpyCustom/sdk/utlrbtree.h

1432 lines
31 KiB
C
Raw Normal View History

2021-06-16 18:49:07 +03:00
#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 <typename T >
class CDefOps
{
public:
static bool LessFunc(const T& lhs, const T& rhs) { return (lhs < rhs); }
};
#define DefLessFunc( type ) CDefOps< type >::LessFunc
template <typename T>
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<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));
}
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<T, I, L, M>& 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<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;
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<T, I, L, M> 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<T, I, L, M>::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<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();
}
template < class T, class I, typename L, class M >
inline T& CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<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);
}
template < class T, class I, typename L, class M >
inline I CUtlRBTree<T, I, L, M>::Root() const
{
return m_Root;
}
template < class T, class I, typename L, class M >
inline unsigned int CUtlRBTree<T, I, L, M>::Count() const
{
return (unsigned int)m_NumElements;
}
template < class T, class I, typename L, class M >
inline I CUtlRBTree<T, I, L, M>::MaxElement() const
{
return (I)m_Elements.NumAllocated();
}
template < class T, class I, typename L, class M >
inline I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<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;
}
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());
}
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;
return LeftChild(i) != i;
}
template < class T, class I, typename L, class M >
inline I CUtlRBTree<T, I, L, M>::InvalidIndex()
{
return (I)M::InvalidIndex();
}
template < class T, class I, typename L, class M >
inline int CUtlRBTree<T, I, L, M>::Depth() const
{
return Depth(Root());
}
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;
}
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
{
static const Links_t s_Sentinel =
{
M::INVALID_INDEX, M::INVALID_INDEX, M::INVALID_INDEX, CUtlRBTree<T, I, L, M>::BLACK
};
return (i != InvalidIndex()) ? m_Elements[i] : 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 m_Elements[i];
}
template < class T, class I, typename L, class M >
inline bool CUtlRBTree<T, I, L, M>::IsRed(I i) const
{
return Color(i) == RED;
}
template < class T, class I, typename L, class M >
inline bool CUtlRBTree<T, I, L, M>::IsBlack(I i) const
{
return Color(i) == BLACK;
}
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)(i != InvalidIndex() ? m_Elements[i].m_Tag : BLACK);
}
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;
}
#pragma warning(push)
#pragma warning(disable:4389)
template < class T, class I, typename L, class M >
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<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);
}
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);
}
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);
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<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;
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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::Purge()
{
RemoveAll();
m_FirstFree = InvalidIndex();
m_Elements.Purge();
m_LastAlloc = m_Elements.InvalidIterator();
}
template < class T, class I, typename L, class M >
I CUtlRBTree<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<T, I, L, M>::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<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
{
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<T, I, L, M>::PrevPreorder(I i) const
{
Assert(0);
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)
{
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<T, I, L, M>::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<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))
{
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<T, I, L, M>::Reinsert(I elem)
{
Unlink(elem);
Link(elem);
}
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;
}
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
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<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)
{
Assert(0);
}
}
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);
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)
{
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<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)
{
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<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;
}
template <class T, class I, typename L, class E>
I CUtlRBTree<T, I, L, E>::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 <class T, class I, typename L, class E>
I CUtlRBTree<T, I, L, E>::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<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