ReGameDLL_CS/regamedll/public/utlrbtree.h

1173 lines
26 KiB
C
Raw Normal View History

/*
*
* 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
2017-10-12 17:50:56 +03:00
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
2017-10-12 17:50:56 +03:00
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
2017-10-12 17:50:56 +03:00
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
2017-10-12 17:50:56 +03:00
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;
};
2017-10-12 17:50:56 +03:00
// 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()
{
}
2017-10-12 17:50:56 +03:00
// 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);
2017-10-12 17:50:56 +03:00
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);
2017-10-12 17:50:56 +03:00
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;
}
2017-10-12 17:50:56 +03:00
// 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
{
2017-10-12 17:50:56 +03:00
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);
}
2017-10-12 17:50:56 +03:00
// 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())
{
2017-10-12 17:50:56 +03:00
numFree++;
curr = RightChild(curr);
if ((curr > MaxElement()) && (curr != InvalidIndex()))
goto InvalidTree;
}
if (MaxElement() - numFree != Count())
goto InvalidTree;
2017-10-12 17:50:56 +03:00
// Iterate over all elements, looking for validity
// based on the self pointers
int numFree2 = 0;
2017-10-12 17:50:56 +03:00
for (curr = 0; curr < MaxElement(); curr++)
{
if (!IsValidIndex(curr))
2017-10-12 17:50:56 +03:00
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
{
2017-10-12 17:50:56 +03:00
// 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);
2017-10-12 17:50:56 +03:00
// 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)
{
2017-10-12 17:50:56 +03:00
// 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++);
}
}
2017-10-12 17:50:56 +03:00
// 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;
}