PODRedBlackTree.h   [plain text]


/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// A red-black tree, which is a form of a balanced binary tree. It
// supports efficient insertion, deletion and queries of comparable
// elements. The same element may be inserted multiple times. The
// algorithmic complexity of common operations is:
//
//   Insertion: O(lg(n))
//   Deletion:  O(lg(n))
//   Querying:  O(lg(n))
//
// The data type T that is stored in this red-black tree must be only
// Plain Old Data (POD), or bottom out into POD. It must _not_ rely on
// having its destructor called. This implementation internally
// allocates storage in large chunks and does not call the destructor
// on each object.
//
// Type T must supply a default constructor, a copy constructor, and
// the "<" and "==" operators.
//
// In debug mode, printing of the data contained in the tree is
// enabled. This requires the template specialization to be available:
//
//   template<> struct WebCore::ValueToString<T> {
//       static String string(const T& t);
//   };
//
// Note that when complex types are stored in this red/black tree, it
// is possible that single invocations of the "<" and "==" operators
// will be insufficient to describe the ordering of elements in the
// tree during queries. As a concrete example, consider the case where
// intervals are stored in the tree sorted by low endpoint. The "<"
// operator on the Interval class only compares the low endpoint, but
// the "==" operator takes into account the high endpoint as well.
// This makes the necessary logic for querying and deletion somewhat
// more complex. In order to properly handle such situations, the
// property "needsFullOrderingComparisons" must be set to true on
// the tree.
//
// This red-black tree is designed to be _augmented_; subclasses can
// add additional and summary information to each node to efficiently
// store and index more complex data structures. A concrete example is
// the IntervalTree, which extends each node with a summary statistic
// to efficiently store one-dimensional intervals.
//
// The design of this red-black tree comes from Cormen, Leiserson,
// and Rivest, _Introduction to Algorithms_, MIT Press, 1990.

#ifndef PODRedBlackTree_h
#define PODRedBlackTree_h

#include "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;

    // Visitor interface for walking all of the tree's elements.
    class Visitor {
    public:
        virtual void visit(const T& data) = 0;
    protected:
        virtual ~Visitor() { }
    };

    // Constructs a new red-black tree without allocating an arena.
    // isInitialized will return false in this case. initIfNeeded can be used
    // to init the structure. This constructor is usefull for creating
    // lazy initialized tree.
    explicit PODRedBlackTree(UninitializedTreeEnum)
        : m_root(0)
        , m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
        , m_verboseDebugging(false)
#endif
    {
    }

    // Constructs a new red-black tree, allocating temporary objects
    // from a newly constructed PODFreeListArena.
    PODRedBlackTree()
        : m_arena(PODFreeListArena<Node>::create())
        , m_root(0)
        , m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
        , m_verboseDebugging(false)
#endif
    {
    }

    // Constructs a new red-black tree, allocating temporary objects
    // from the given PODArena.
    explicit PODRedBlackTree(PassRefPtr<PODFreeListArena<Node> > arena)
        : m_arena(arena)
        , m_root(0)
        , m_needsFullOrderingComparisons(false)
#ifndef NDEBUG
        , m_verboseDebugging(false)
#endif
    {
    }

    virtual ~PODRedBlackTree() { }

    // Clearing will delete the contents of the tree. After this call
    // isInitialized will return false.
    void clear()
    {
        markFree(m_root);
        m_arena = 0;
        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);
    }

    // Returns true if the datum was found in the tree.
    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();
    }

    // See the class documentation for an explanation of this property.
    void setNeedsFullOrderingComparisons(bool needsFullOrderingComparisons)
    {
        m_needsFullOrderingComparisons = needsFullOrderingComparisons;
    }

    virtual bool checkInvariants() const
    {
        ASSERT(isInitialized());
        int blackCount;
        return checkInvariantsFromNode(m_root, &blackCount);
    }

#ifndef NDEBUG
    // Dumps the tree's contents to the logging info stream for
    // debugging purposes.
    void dump() const
    {
        if (m_arena)
            dumpFromNode(m_root, 0);
    }

    // Turns on or off verbose debugging of the tree, causing many
    // messages to be logged during insertion and other operations in
    // debug mode.
    void setVerboseDebugging(bool verboseDebugging)
    {
        m_verboseDebugging = verboseDebugging;
    }
#endif

    enum Color {
        Red = 1,
        Black
    };

    // The base Node class which is stored in the tree. Nodes are only
    // an internal concept; users of the tree deal only with the data
    // they store in it.
    class Node {
        WTF_MAKE_NONCOPYABLE(Node);
    public:
        // Constructor. Newly-created nodes are colored red.
        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; }

        // Fetches the user data.
        T& data() { return m_data; }

        // Copies all user-level fields from the source node, but not
        // internal fields. For example, the base implementation of this
        // method copies the "m_data" field, but not the child or parent
        // fields. Any augmentation information also does not need to be
        // copied, as it will be recomputed. Subclasses must call the
        // superclass implementation.
        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:
    // Returns the root of the tree, which is needed by some subclasses.
    Node* root() const { return m_root; }

private:
    // This virtual method is the hook that subclasses should use when
    // augmenting the red-black tree with additional per-node summary
    // information. For example, in the case of an interval tree, this
    // is used to compute the maximum endpoint of the subtree below the
    // given node based on the values in the left and right children. It
    // is guaranteed that this will be called in the correct order to
    // properly update such summary information based only on the values
    // in the left and right children. This method should return true if
    // the node's summary information changed.
    virtual bool updateNode(Node*) { return false; }

    //----------------------------------------------------------------------
    // Generic binary search tree operations
    //

    // Searches the tree for the given datum.
    Node* treeSearch(const T& data) const
    {
        if (m_needsFullOrderingComparisons)
            return treeSearchFullComparisons(m_root, data);

        return treeSearchNormal(m_root, data);
    }

    // Searches the tree using the normal comparison operations,
    // suitable for simple data types such as numbers.
    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;
    }

    // Searches the tree using multiple comparison operations, required
    // for data types with more complex behavior such as intervals.
    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;

        // We may need to traverse both the left and right subtrees.
        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);
        }
    }

    // Finds the node following the given one in sequential ordering of
    // their data, or null if none exists.
    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;
    }

    // Finds the minimum element in the sub-tree rooted at the given
    // node.
    Node* treeMinimum(Node* x)
    {
        while (x->left())
            x = x->left();
        return x;
    }

    // Helper for maintaining the augmented red-black tree.
    void propagateUpdates(Node* start)
    {
        bool shouldContinue = true;
        while (start && shouldContinue) {
            shouldContinue = updateNode(start);
            start = start->parent();
        }
    }

    //----------------------------------------------------------------------
    // Red-Black tree operations
    //

    // Left-rotates the subtree rooted at x.
    // Returns the new root of the subtree (x's right child).
    Node* leftRotate(Node* x)
    {
        // Set y.
        Node* y = x->right();

        // Turn y's left subtree into x's right subtree.
        x->setRight(y->left());
        if (y->left())
            y->left()->setParent(x);

        // Link x's parent to y.
        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);
        }

        // Put x on y's left.
        y->setLeft(x);
        x->setParent(y);

        // Update nodes lowest to highest.
        updateNode(x);
        updateNode(y);
        return y;
    }

    // Right-rotates the subtree rooted at y.
    // Returns the new root of the subtree (y's left child).
    Node* rightRotate(Node* y)
    {
        // Set x.
        Node* x = y->left();

        // Turn x's right subtree into y's left subtree.
        y->setLeft(x->right());
        if (x->right())
            x->right()->setParent(y);

        // Link y's parent to x.
        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);
        }

        // Put y on x's right.
        x->setRight(y);
        y->setParent(x);

        // Update nodes lowest to highest.
        updateNode(y);
        updateNode(x);
        return x;
    }

    // Inserts the given node into the tree.
    void insertNode(Node* x)
    {
        treeInsert(x);
        x->setColor(Red);
        updateNode(x);

        logIfVerbose("  PODRedBlackTree::InsertNode");

        // The node from which to start propagating updates upwards.
        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) {
                    // Case 1
                    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");
                        // Case 2
                        x = x->parent();
                        leftRotate(x);
                    }
                    // Case 3
                    logIfVerbose("  Case 1/3");
                    x->parent()->setColor(Black);
                    x->parent()->parent()->setColor(Red);
                    Node* newSubTreeRoot = rightRotate(x->parent()->parent());
                    updateStart = newSubTreeRoot->parent();
                }
            } else {
                // Same as "then" clause with "right" and "left" exchanged.
                Node* y = x->parent()->parent()->left();
                if (y && y->color() == Red) {
                    // Case 1
                    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()) {
                        // Case 2
                        logIfVerbose("  Case 2/2");
                        x = x->parent();
                        rightRotate(x);
                    }
                    // Case 3
                    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);
    }

    // Restores the red-black property to the tree after splicing out
    // a node. Note that x may be null, which is why xParent must be
    // supplied.
    void deleteFixup(Node* x, Node* xParent)
    {
        while (x != m_root && (!x || x->color() == Black)) {
            if (x == xParent->left()) {
                // Note: the text points out that w can not be null.
                // The reason is not obvious from simply looking at
                // the code; it comes about from the properties of the
                // red-black tree.
                Node* w = xParent->right();
                ASSERT(w); // x's sibling should not be null.
                if (w->color() == Red) {
                    // Case 1
                    w->setColor(Black);
                    xParent->setColor(Red);
                    leftRotate(xParent);
                    w = xParent->right();
                }
                if ((!w->left() || w->left()->color() == Black)
                    && (!w->right() || w->right()->color() == Black)) {
                    // Case 2
                    w->setColor(Red);
                    x = xParent;
                    xParent = x->parent();
                } else {
                    if (!w->right() || w->right()->color() == Black) {
                        // Case 3
                        w->left()->setColor(Black);
                        w->setColor(Red);
                        rightRotate(w);
                        w = xParent->right();
                    }
                    // Case 4
                    w->setColor(xParent->color());
                    xParent->setColor(Black);
                    if (w->right())
                        w->right()->setColor(Black);
                    leftRotate(xParent);
                    x = m_root;
                    xParent = x->parent();
                }
            } else {
                // Same as "then" clause with "right" and "left"
                // exchanged.

                // Note: the text points out that w can not be null.
                // The reason is not obvious from simply looking at
                // the code; it comes about from the properties of the
                // red-black tree.
                Node* w = xParent->left();
                ASSERT(w); // x's sibling should not be null.
                if (w->color() == Red) {
                    // Case 1
                    w->setColor(Black);
                    xParent->setColor(Red);
                    rightRotate(xParent);
                    w = xParent->left();
                }
                if ((!w->right() || w->right()->color() == Black)
                    && (!w->left() || w->left()->color() == Black)) {
                    // Case 2
                    w->setColor(Red);
                    x = xParent;
                    xParent = x->parent();
                } else {
                    if (!w->left() || w->left()->color() == Black) {
                        // Case 3
                        w->right()->setColor(Black);
                        w->setColor(Red);
                        leftRotate(w);
                        w = xParent->left();
                    }
                    // Case 4
                    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);
    }

    // Deletes the given node from the tree. Note that this
    // particular node may not actually be removed from the tree;
    // instead, another node might be removed and its contents
    // copied into z.
    void deleteNode(Node* z)
    {
        // Y is the node to be unlinked from the tree.
        Node* y;
        if (!z->left() || !z->right())
            y = z;
        else
            y = treeSuccessor(z);

        // Y is guaranteed to be non-null at this point.
        Node* x;
        if (y->left())
            x = y->left();
        else
            x = y->right();

        // X is the child of y which might potentially replace y in
        // the tree. X might be null at this point.
        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);
            // This node has changed location in the tree and must be updated.
            updateNode(z);
            // The parent and its parents may now be out of date.
            propagateUpdates(z->parent());
        }

        // If we haven't already updated starting from xParent, do so now.
        if (xParent && xParent != y && xParent != z)
            propagateUpdates(xParent);
        if (y->color() == Black)
            deleteFixup(x, xParent);

        m_arena->freeObject(y);
    }

    // Visits the subtree rooted at the given node in order.
    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);
    }

    //----------------------------------------------------------------------
    // Helper class for size()

    // A Visitor which simply counts the number of visited elements.
    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;
    };

    //----------------------------------------------------------------------
    // Verification and debugging routines
    //

    // Returns in the "blackCount" parameter the number of black
    // children along all paths to all leaves of the given node.
    bool checkInvariantsFromNode(Node* node, int* blackCount) const
    {
        // Base case is a leaf node.
        if (!node) {
            *blackCount = 1;
            return true;
        }

        // Each node is either red or black.
        if (!(node->color() == Red || node->color() == Black))
            return false;

        // Every leaf (or null) is black.

        if (node->color() == Red) {
            // Both of its children are black.
            if (!((!node->left() || node->left()->color() == Black)))
                return false;
            if (!((!node->right() || node->right()->color() == Black)))
                return false;
        }

        // Every simple path to a leaf node contains the same number of
        // black nodes.
        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)
            LOG_ERROR("%s", output);
    }
#endif

#ifndef NDEBUG
    // Dumps the subtree rooted at the given node.
    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)");
        }
        LOG_ERROR("%s", builder.toString().ascii().data());
        if (node) {
            dumpFromNode(node->left(), indentation + 2);
            dumpFromNode(node->right(), indentation + 2);
        }
    }
#endif

    //----------------------------------------------------------------------
    // Data members

    RefPtr<PODFreeListArena<Node> > m_arena;
    Node* m_root;
    bool m_needsFullOrderingComparisons;
#ifndef NDEBUG
    bool m_verboseDebugging;
#endif
};

} // namespace WebCore

#endif // PODRedBlackTree_h