This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

1411 lines
44 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLRBTREE_H
#define UTLRBTREE_H
#include "strtools.h"
#include "utlblockmemory.h"
#include "utlfixedmemory.h"
#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
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 (V_strcmp(lhs, rhs) < 0);
}
inline bool CaselessStringLessThan(const char *const &lhs,
const char *const &rhs) {
if (!lhs) return false;
if (!rhs) return true;
return (V_stricmp(lhs, rhs) < 0);
}
// Same as CaselessStringLessThan, but it ignores differences in / and \.
inline bool CaselessStringLessThanIgnoreSlashes(const char *const &lhs,
const char *const &rhs) {
const char *pa = lhs;
const char *pb = rhs;
while (*pa && *pb) {
char a = *pa;
char b = *pb;
// Check for dir slashes.
if (a == '/' || a == '\\') {
if (b != '/' && b != '\\') return ('/' < b);
} else {
if (a >= 'a' && a <= 'z') a = 'A' + (a - 'a');
if (b >= 'a' && b <= 'z') b = 'A' + (b - 'a');
if (a > b)
return false;
else if (a < b)
return true;
}
++pa;
++pb;
}
// Filenames also must be the same length.
if (*pa != *pb) {
// If pa shorter than pb then it's "less"
return (!*pa);
}
return false;
}
//-------------------------------------
// inline these two templates to stop multiple definitions of the same code
template <>
inline bool CDefOps<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();
bool HasElement(T const &search) const {
return Find(search) != InvalidIndex();
}
// Allocation, deletion
void FreeNode(I i);
// Iteration
I FirstInorder() const;
I NextInorder(I i) const;
I PrevInorder(I i) const;
I LastInorder() const;
I FirstPreorder() const;
I NextPreorder(I i) const;
I PrevPreorder(I i) const;
I LastPreorder() const;
I FirstPostorder() const;
I NextPostorder(I i) const;
// If you change the search key, this can be used to reinsert the
// element into the tree.
void Reinsert(I elem);
// swap in place
void Swap(CUtlRBTree<T, I, L> &that);
private:
// Can't copy the tree this way!
CUtlRBTree<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(T));
m_LessFunc = other.m_LessFunc;
m_Root = other.m_Root;
m_NumElements = other.m_NumElements;
m_FirstFree = other.m_FirstFree;
m_LastAlloc = other.m_LastAlloc;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// gets particular elements
//-----------------------------------------------------------------------------
template <class T, class I, typename L, class M>
inline T &CUtlRBTree<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();
// Technically, this iterator could become invalid. It will not, because
// it's always the same iterator. If we don't clear this here, the state of
// this container will be invalid after we start inserting elements again.
m_LastAlloc = m_Elements.InvalidIterator();
m_FirstFree = InvalidIndex();
m_NumElements = 0;
Assert(IsValid());
}
//-----------------------------------------------------------------------------
// Removes all nodes from the tree and purges memory
//-----------------------------------------------------------------------------
template <class T, class I, typename L, class M>
void CUtlRBTree<T, I, L, M>::Purge() {
RemoveAll();
m_Elements.Purge();
}
//-----------------------------------------------------------------------------
// 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 {
// Don't go into an infinite loop if it's a bad index
Assert(IsValidIndex(i));
if (!IsValidIndex(i)) return InvalidIndex();
if (RightChild(i) != InvalidIndex()) {
i = RightChild(i);
while (LeftChild(i) != InvalidIndex()) i = LeftChild(i);
return i;
}
I parent = Parent(i);
while (IsRightChild(i)) {
i = parent;
if (i == InvalidIndex()) break;
parent = Parent(i);
}
return parent;
}
template <class T, class I, typename L, class M>
I CUtlRBTree<T, I, L, M>::PrevInorder(I i) const {
// Don't go into an infinite loop if it's a bad index
Assert(IsValidIndex(i));
if (!IsValidIndex(i)) return InvalidIndex();
if (LeftChild(i) != InvalidIndex()) {
i = LeftChild(i);
while (RightChild(i) != InvalidIndex()) i = RightChild(i);
return i;
}
I parent = Parent(i);
while (IsLeftChild(i)) {
i = parent;
if (i == InvalidIndex()) break;
parent = Parent(i);
}
return parent;
}
template <class T, class I, typename L, class M>
I CUtlRBTree<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