#ifndef PODRedBlackTree_h
#define PODRedBlackTree_h
#include "platform/PODFreeListArena.h"
#include "wtf/Assertions.h"
#include "wtf/Noncopyable.h"
#include "wtf/RefPtr.h"
#ifndef NDEBUG
#include "wtf/text/CString.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
#endif
namespace WebCore {
#ifndef NDEBUG
template<class T>
struct ValueToString;
#endif
enum UninitializedTreeEnum {
UninitializedTree
};
template<class T>
class PODRedBlackTree {
public:
class Node;
class Visitor {
public:
virtual void visit(const T& data) = 0;
protected:
virtual ~Visitor() { }
};
explicit PODRedBlackTree(UninitializedTreeEnum)
: m_root(0)
, m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
, m_verboseDebugging(false)
#endif
{
}
PODRedBlackTree()
: m_arena(PODFreeListArena<Node>::create())
, m_root(0)
, m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
, m_verboseDebugging(false)
#endif
{
}
explicit PODRedBlackTree(PassRefPtr<PODFreeListArena<Node> > arena)
: m_arena(arena)
, m_root(0)
, m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
, m_verboseDebugging(false)
#endif
{
}
virtual ~PODRedBlackTree() { }
void clear()
{
markFree(m_root);
m_arena = nullptr;
m_root = 0;
}
bool isInitialized() const
{
return m_arena;
}
void initIfNeeded()
{
if (!m_arena)
m_arena = PODFreeListArena<Node>::create();
}
void initIfNeeded(PODFreeListArena<Node>* arena)
{
if (!m_arena)
m_arena = arena;
}
void add(const T& data)
{
ASSERT(isInitialized());
Node* node = m_arena->template allocateObject<T>(data);
insertNode(node);
}
bool remove(const T& data)
{
ASSERT(isInitialized());
Node* node = treeSearch(data);
if (node) {
deleteNode(node);
return true;
}
return false;
}
bool contains(const T& data) const
{
ASSERT(isInitialized());
return treeSearch(data);
}
void visitInorder(Visitor* visitor) const
{
ASSERT(isInitialized());
if (!m_root)
return;
visitInorderImpl(m_root, visitor);
}
int size() const
{
ASSERT(isInitialized());
Counter counter;
visitInorder(&counter);
return counter.count();
}
void setNeedsFullOrderingComparisons(bool needsFullOrderingComparisons)
{
m_needsFullOrderingComparisons = needsFullOrderingComparisons;
}
virtual bool checkInvariants() const
{
ASSERT(isInitialized());
int blackCount;
return checkInvariantsFromNode(m_root, &blackCount);
}
#ifndef NDEBUG
void dump() const
{
if (m_arena)
dumpFromNode(m_root, 0);
}
void setVerboseDebugging(bool verboseDebugging)
{
m_verboseDebugging = verboseDebugging;
}
#endif
enum Color {
Red = 1,
Black
};
class Node {
WTF_MAKE_NONCOPYABLE(Node);
public:
explicit Node(const T& data)
: m_left(0)
, m_right(0)
, m_parent(0)
, m_color(Red)
, m_data(data)
{
}
virtual ~Node() { }
Color color() const { return m_color; }
void setColor(Color color) { m_color = color; }
T& data() { return m_data; }
virtual void copyFrom(Node* src) { m_data = src->data(); }
Node* left() const { return m_left; }
void setLeft(Node* node) { m_left = node; }
Node* right() const { return m_right; }
void setRight(Node* node) { m_right = node; }
Node* parent() const { return m_parent; }
void setParent(Node* node) { m_parent = node; }
private:
Node* m_left;
Node* m_right;
Node* m_parent;
Color m_color;
T m_data;
};
protected:
Node* root() const { return m_root; }
private:
virtual bool updateNode(Node*) { return false; }
Node* treeSearch(const T& data) const
{
if (m_needsFullOrderingComparisons)
return treeSearchFullComparisons(m_root, data);
return treeSearchNormal(m_root, data);
}
Node* treeSearchNormal(Node* current, const T& data) const
{
while (current) {
if (current->data() == data)
return current;
if (data < current->data())
current = current->left();
else
current = current->right();
}
return 0;
}
Node* treeSearchFullComparisons(Node* current, const T& data) const
{
if (!current)
return 0;
if (data < current->data())
return treeSearchFullComparisons(current->left(), data);
if (current->data() < data)
return treeSearchFullComparisons(current->right(), data);
if (data == current->data())
return current;
Node* result = treeSearchFullComparisons(current->left(), data);
if (!result)
result = treeSearchFullComparisons(current->right(), data);
return result;
}
void treeInsert(Node* z)
{
Node* y = 0;
Node* x = m_root;
while (x) {
y = x;
if (z->data() < x->data())
x = x->left();
else
x = x->right();
}
z->setParent(y);
if (!y) {
m_root = z;
} else {
if (z->data() < y->data())
y->setLeft(z);
else
y->setRight(z);
}
}
Node* treeSuccessor(Node* x)
{
if (x->right())
return treeMinimum(x->right());
Node* y = x->parent();
while (y && x == y->right()) {
x = y;
y = y->parent();
}
return y;
}
Node* treeMinimum(Node* x)
{
while (x->left())
x = x->left();
return x;
}
void propagateUpdates(Node* start)
{
bool shouldContinue = true;
while (start && shouldContinue) {
shouldContinue = updateNode(start);
start = start->parent();
}
}
Node* leftRotate(Node* x)
{
Node* y = x->right();
x->setRight(y->left());
if (y->left())
y->left()->setParent(x);
y->setParent(x->parent());
if (!x->parent()) {
m_root = y;
} else {
if (x == x->parent()->left())
x->parent()->setLeft(y);
else
x->parent()->setRight(y);
}
y->setLeft(x);
x->setParent(y);
updateNode(x);
updateNode(y);
return y;
}
Node* rightRotate(Node* y)
{
Node* x = y->left();
y->setLeft(x->right());
if (x->right())
x->right()->setParent(y);
x->setParent(y->parent());
if (!y->parent()) {
m_root = x;
} else {
if (y == y->parent()->left())
y->parent()->setLeft(x);
else
y->parent()->setRight(x);
}
x->setRight(y);
y->setParent(x);
updateNode(y);
updateNode(x);
return x;
}
void insertNode(Node* x)
{
treeInsert(x);
x->setColor(Red);
updateNode(x);
logIfVerbose(" PODRedBlackTree::InsertNode");
Node* updateStart = x->parent();
while (x != m_root && x->parent()->color() == Red) {
if (x->parent() == x->parent()->parent()->left()) {
Node* y = x->parent()->parent()->right();
if (y && y->color() == Red) {
logIfVerbose(" Case 1/1");
x->parent()->setColor(Black);
y->setColor(Black);
x->parent()->parent()->setColor(Red);
updateNode(x->parent());
x = x->parent()->parent();
updateNode(x);
updateStart = x->parent();
} else {
if (x == x->parent()->right()) {
logIfVerbose(" Case 1/2");
x = x->parent();
leftRotate(x);
}
logIfVerbose(" Case 1/3");
x->parent()->setColor(Black);
x->parent()->parent()->setColor(Red);
Node* newSubTreeRoot = rightRotate(x->parent()->parent());
updateStart = newSubTreeRoot->parent();
}
} else {
Node* y = x->parent()->parent()->left();
if (y && y->color() == Red) {
logIfVerbose(" Case 2/1");
x->parent()->setColor(Black);
y->setColor(Black);
x->parent()->parent()->setColor(Red);
updateNode(x->parent());
x = x->parent()->parent();
updateNode(x);
updateStart = x->parent();
} else {
if (x == x->parent()->left()) {
logIfVerbose(" Case 2/2");
x = x->parent();
rightRotate(x);
}
logIfVerbose(" Case 2/3");
x->parent()->setColor(Black);
x->parent()->parent()->setColor(Red);
Node* newSubTreeRoot = leftRotate(x->parent()->parent());
updateStart = newSubTreeRoot->parent();
}
}
}
propagateUpdates(updateStart);
m_root->setColor(Black);
}
void deleteFixup(Node* x, Node* xParent)
{
while (x != m_root && (!x || x->color() == Black)) {
if (x == xParent->left()) {
Node* w = xParent->right();
ASSERT(w);
if (w->color() == Red) {
w->setColor(Black);
xParent->setColor(Red);
leftRotate(xParent);
w = xParent->right();
}
if ((!w->left() || w->left()->color() == Black)
&& (!w->right() || w->right()->color() == Black)) {
w->setColor(Red);
x = xParent;
xParent = x->parent();
} else {
if (!w->right() || w->right()->color() == Black) {
w->left()->setColor(Black);
w->setColor(Red);
rightRotate(w);
w = xParent->right();
}
w->setColor(xParent->color());
xParent->setColor(Black);
if (w->right())
w->right()->setColor(Black);
leftRotate(xParent);
x = m_root;
xParent = x->parent();
}
} else {
Node* w = xParent->left();
ASSERT(w);
if (w->color() == Red) {
w->setColor(Black);
xParent->setColor(Red);
rightRotate(xParent);
w = xParent->left();
}
if ((!w->right() || w->right()->color() == Black)
&& (!w->left() || w->left()->color() == Black)) {
w->setColor(Red);
x = xParent;
xParent = x->parent();
} else {
if (!w->left() || w->left()->color() == Black) {
w->right()->setColor(Black);
w->setColor(Red);
leftRotate(w);
w = xParent->left();
}
w->setColor(xParent->color());
xParent->setColor(Black);
if (w->left())
w->left()->setColor(Black);
rightRotate(xParent);
x = m_root;
xParent = x->parent();
}
}
}
if (x)
x->setColor(Black);
}
void deleteNode(Node* z)
{
Node* y;
if (!z->left() || !z->right())
y = z;
else
y = treeSuccessor(z);
Node* x;
if (y->left())
x = y->left();
else
x = y->right();
Node* xParent;
if (x) {
x->setParent(y->parent());
xParent = x->parent();
} else {
xParent = y->parent();
}
if (!y->parent()) {
m_root = x;
} else {
if (y == y->parent()->left())
y->parent()->setLeft(x);
else
y->parent()->setRight(x);
}
if (y != z) {
z->copyFrom(y);
updateNode(z);
propagateUpdates(z->parent());
}
if (xParent && xParent != y && xParent != z)
propagateUpdates(xParent);
if (y->color() == Black)
deleteFixup(x, xParent);
m_arena->freeObject(y);
}
void visitInorderImpl(Node* node, Visitor* visitor) const
{
if (node->left())
visitInorderImpl(node->left(), visitor);
visitor->visit(node->data());
if (node->right())
visitInorderImpl(node->right(), visitor);
}
void markFree(Node *node)
{
if (!node)
return;
if (node->left())
markFree(node->left());
if (node->right())
markFree(node->right());
m_arena->freeObject(node);
}
class Counter : public Visitor {
WTF_MAKE_NONCOPYABLE(Counter);
public:
Counter()
: m_count(0) { }
virtual void visit(const T&) { ++m_count; }
int count() const { return m_count; }
private:
int m_count;
};
bool checkInvariantsFromNode(Node* node, int* blackCount) const
{
if (!node) {
*blackCount = 1;
return true;
}
if (!(node->color() == Red || node->color() == Black))
return false;
if (node->color() == Red) {
if (!((!node->left() || node->left()->color() == Black)))
return false;
if (!((!node->right() || node->right()->color() == Black)))
return false;
}
int leftCount = 0, rightCount = 0;
bool leftValid = checkInvariantsFromNode(node->left(), &leftCount);
bool rightValid = checkInvariantsFromNode(node->right(), &rightCount);
if (!leftValid || !rightValid)
return false;
*blackCount = leftCount + (node->color() == Black ? 1 : 0);
return leftCount == rightCount;
}
#ifdef NDEBUG
void logIfVerbose(const char*) const { }
#else
void logIfVerbose(const char* output) const
{
if (m_verboseDebugging)
WTF_LOG_ERROR("%s", output);
}
#endif
#ifndef NDEBUG
void dumpFromNode(Node* node, int indentation) const
{
StringBuilder builder;
for (int i = 0; i < indentation; i++)
builder.append(" ");
builder.append("-");
if (node) {
builder.append(" ");
builder.append(ValueToString<T>::string(node->data()));
builder.append((node->color() == Black) ? " (black)" : " (red)");
}
WTF_LOG_ERROR("%s", builder.toString().ascii().data());
if (node) {
dumpFromNode(node->left(), indentation + 2);
dumpFromNode(node->right(), indentation + 2);
}
}
#endif
RefPtr<PODFreeListArena<Node> > m_arena;
Node* m_root;
bool m_needsFullOrderingComparisons;
#ifndef NDEBUG
bool m_verboseDebugging;
#endif
};
}
#endif