[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

kbr at google.com kbr at google.com
Wed Dec 22 12:58:05 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 35323a7b2fe07f90204577b698b19d1b060585e4
Author: kbr at google.com <kbr at google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Sep 3 02:10:37 2010 +0000

    2010-09-02  Kenneth Russell  <kbr at google.com>
    
            Reviewed by Darin Fisher.
    
            Add red-black tree capable of holding plain old data (POD)
            https://bugs.webkit.org/show_bug.cgi?id=45059
    
            Adding an augmentable red-black tree capable of holding Plain Old
            Data (POD), or classes bottoming out into only POD, and an
            associated PODArena. Note that the PODArena will be used by other
            classes to allocate temporary structures, which is why it is not
            just an implementation detail of the red-black tree.
    
            These classes are being placed under WebCore/platform/graphics/gpu
            for the time being. If they are generalized to hold even data
            types which internally perform dynamic memory allocation, we may
            consider moving them to WTF in the future.
    
            Unit tests for the PODRedBlackTree will be integrated separately
            under bug 45060.
    
            * WebCore.gypi:
            * platform/graphics/gpu/PODArena.h: Added.
            (WebCore::PODArena::Allocator::~Allocator):
            (WebCore::PODArena::FastMallocAllocator::create):
            (WebCore::PODArena::FastMallocAllocator::allocate):
            (WebCore::PODArena::FastMallocAllocator::free):
            (WebCore::PODArena::FastMallocAllocator::FastMallocAllocator):
            (WebCore::PODArena::create):
            (WebCore::PODArena::allocateObject):
            (WebCore::PODArena::~PODArena):
            (WebCore::PODArena::PODArena):
            (WebCore::PODArena::minAlignment):
            (WebCore::PODArena::roundUp):
            (WebCore::PODArena::Chunk::Chunk):
            (WebCore::PODArena::Chunk::~Chunk):
            (WebCore::PODArena::Chunk::allocate):
            * platform/graphics/gpu/PODRedBlackTree.h: Added.
            (WebCore::PODRedBlackTree::Visitor::~Visitor):
            (WebCore::PODRedBlackTree::PODRedBlackTree):
            (WebCore::PODRedBlackTree::~PODRedBlackTree):
            (WebCore::PODRedBlackTree::add):
            (WebCore::PODRedBlackTree::remove):
            (WebCore::PODRedBlackTree::contains):
            (WebCore::PODRedBlackTree::visitInorder):
            (WebCore::PODRedBlackTree::size):
            (WebCore::PODRedBlackTree::setNeedsFullOrderingComparisons):
            (WebCore::PODRedBlackTree::checkInvariants):
            (WebCore::PODRedBlackTree::dump):
            (WebCore::PODRedBlackTree::setVerboseDebugging):
            (WebCore::PODRedBlackTree::Node::Node):
            (WebCore::PODRedBlackTree::Node::~Node):
            (WebCore::PODRedBlackTree::Node::color):
            (WebCore::PODRedBlackTree::Node::setColor):
            (WebCore::PODRedBlackTree::Node::data):
            (WebCore::PODRedBlackTree::Node::copyFrom):
            (WebCore::PODRedBlackTree::Node::left):
            (WebCore::PODRedBlackTree::Node::setLeft):
            (WebCore::PODRedBlackTree::Node::right):
            (WebCore::PODRedBlackTree::Node::setRight):
            (WebCore::PODRedBlackTree::Node::parent):
            (WebCore::PODRedBlackTree::Node::setParent):
            (WebCore::PODRedBlackTree::root):
            (WebCore::PODRedBlackTree::updateNode):
            (WebCore::PODRedBlackTree::treeSearch):
            (WebCore::PODRedBlackTree::treeSearchNormal):
            (WebCore::PODRedBlackTree::treeSearchFullComparisons):
            (WebCore::PODRedBlackTree::treeInsert):
            (WebCore::PODRedBlackTree::treeSuccessor):
            (WebCore::PODRedBlackTree::treeMinimum):
            (WebCore::PODRedBlackTree::propagateUpdates):
            (WebCore::PODRedBlackTree::leftRotate):
            (WebCore::PODRedBlackTree::rightRotate):
            (WebCore::PODRedBlackTree::insertNode):
            (WebCore::PODRedBlackTree::deleteFixup):
            (WebCore::PODRedBlackTree::deleteNode):
            (WebCore::PODRedBlackTree::visitInorderImpl):
            (WebCore::PODRedBlackTree::Counter::Counter):
            (WebCore::PODRedBlackTree::Counter::visit):
            (WebCore::PODRedBlackTree::Counter::count):
            (WebCore::PODRedBlackTree::checkInvariantsFromNode):
            (WebCore::PODRedBlackTree::logIfVerbose):
            (WebCore::PODRedBlackTree::dumpFromNode):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66704 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 7f1fea3..98fff40 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,87 @@
+2010-09-02  Kenneth Russell  <kbr at google.com>
+
+        Reviewed by Darin Fisher.
+
+        Add red-black tree capable of holding plain old data (POD)
+        https://bugs.webkit.org/show_bug.cgi?id=45059
+
+        Adding an augmentable red-black tree capable of holding Plain Old
+        Data (POD), or classes bottoming out into only POD, and an
+        associated PODArena. Note that the PODArena will be used by other
+        classes to allocate temporary structures, which is why it is not
+        just an implementation detail of the red-black tree.
+
+        These classes are being placed under WebCore/platform/graphics/gpu
+        for the time being. If they are generalized to hold even data
+        types which internally perform dynamic memory allocation, we may
+        consider moving them to WTF in the future.
+
+        Unit tests for the PODRedBlackTree will be integrated separately
+        under bug 45060.
+
+        * WebCore.gypi:
+        * platform/graphics/gpu/PODArena.h: Added.
+        (WebCore::PODArena::Allocator::~Allocator):
+        (WebCore::PODArena::FastMallocAllocator::create):
+        (WebCore::PODArena::FastMallocAllocator::allocate):
+        (WebCore::PODArena::FastMallocAllocator::free):
+        (WebCore::PODArena::FastMallocAllocator::FastMallocAllocator):
+        (WebCore::PODArena::create):
+        (WebCore::PODArena::allocateObject):
+        (WebCore::PODArena::~PODArena):
+        (WebCore::PODArena::PODArena):
+        (WebCore::PODArena::minAlignment):
+        (WebCore::PODArena::roundUp):
+        (WebCore::PODArena::Chunk::Chunk):
+        (WebCore::PODArena::Chunk::~Chunk):
+        (WebCore::PODArena::Chunk::allocate):
+        * platform/graphics/gpu/PODRedBlackTree.h: Added.
+        (WebCore::PODRedBlackTree::Visitor::~Visitor):
+        (WebCore::PODRedBlackTree::PODRedBlackTree):
+        (WebCore::PODRedBlackTree::~PODRedBlackTree):
+        (WebCore::PODRedBlackTree::add):
+        (WebCore::PODRedBlackTree::remove):
+        (WebCore::PODRedBlackTree::contains):
+        (WebCore::PODRedBlackTree::visitInorder):
+        (WebCore::PODRedBlackTree::size):
+        (WebCore::PODRedBlackTree::setNeedsFullOrderingComparisons):
+        (WebCore::PODRedBlackTree::checkInvariants):
+        (WebCore::PODRedBlackTree::dump):
+        (WebCore::PODRedBlackTree::setVerboseDebugging):
+        (WebCore::PODRedBlackTree::Node::Node):
+        (WebCore::PODRedBlackTree::Node::~Node):
+        (WebCore::PODRedBlackTree::Node::color):
+        (WebCore::PODRedBlackTree::Node::setColor):
+        (WebCore::PODRedBlackTree::Node::data):
+        (WebCore::PODRedBlackTree::Node::copyFrom):
+        (WebCore::PODRedBlackTree::Node::left):
+        (WebCore::PODRedBlackTree::Node::setLeft):
+        (WebCore::PODRedBlackTree::Node::right):
+        (WebCore::PODRedBlackTree::Node::setRight):
+        (WebCore::PODRedBlackTree::Node::parent):
+        (WebCore::PODRedBlackTree::Node::setParent):
+        (WebCore::PODRedBlackTree::root):
+        (WebCore::PODRedBlackTree::updateNode):
+        (WebCore::PODRedBlackTree::treeSearch):
+        (WebCore::PODRedBlackTree::treeSearchNormal):
+        (WebCore::PODRedBlackTree::treeSearchFullComparisons):
+        (WebCore::PODRedBlackTree::treeInsert):
+        (WebCore::PODRedBlackTree::treeSuccessor):
+        (WebCore::PODRedBlackTree::treeMinimum):
+        (WebCore::PODRedBlackTree::propagateUpdates):
+        (WebCore::PODRedBlackTree::leftRotate):
+        (WebCore::PODRedBlackTree::rightRotate):
+        (WebCore::PODRedBlackTree::insertNode):
+        (WebCore::PODRedBlackTree::deleteFixup):
+        (WebCore::PODRedBlackTree::deleteNode):
+        (WebCore::PODRedBlackTree::visitInorderImpl):
+        (WebCore::PODRedBlackTree::Counter::Counter):
+        (WebCore::PODRedBlackTree::Counter::visit):
+        (WebCore::PODRedBlackTree::Counter::count):
+        (WebCore::PODRedBlackTree::checkInvariantsFromNode):
+        (WebCore::PODRedBlackTree::logIfVerbose):
+        (WebCore::PODRedBlackTree::dumpFromNode):
+
 2010-09-02  Rafael Antognolli  <antognolli at profusion.mobi>
 
         Reviewed by Martin Robinson.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 89f4202..5506854 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -2341,6 +2341,8 @@
             'platform/graphics/filters/SourceAlpha.h',
             'platform/graphics/filters/SourceGraphic.cpp',
             'platform/graphics/filters/SourceGraphic.h',
+            'platform/graphics/gpu/PODArena.h',
+            'platform/graphics/gpu/PODRedBlackTree.h',
             'platform/graphics/gpu/Shader.cpp',
             'platform/graphics/gpu/Shader.h',
             'platform/graphics/gpu/SolidFillShader.cpp',
diff --git a/WebCore/platform/graphics/gpu/PODArena.h b/WebCore/platform/graphics/gpu/PODArena.h
new file mode 100644
index 0000000..a322f81
--- /dev/null
+++ b/WebCore/platform/graphics/gpu/PODArena.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+#ifndef PODArena_h
+#define PODArena_h
+
+#include <stdint.h>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// An arena which allocates only Plain Old Data (POD), or classes and
+// structs bottoming out in Plain Old Data. NOTE: the constructors of
+// the objects allocated in this arena are called, but _not_ their
+// destructors.
+
+class PODArena : public RefCounted<PODArena> {
+public:
+    // The arena is configured with an allocator, which is responsible
+    // for allocating and freeing chunks of memory at a time.
+    class Allocator : public RefCounted<Allocator> {
+    public:
+        virtual void* allocate(size_t size) = 0;
+        virtual void free(void* ptr) = 0;
+    protected:
+        virtual ~Allocator() { }
+        friend class WTF::RefCounted<Allocator>;
+    };
+
+    // The Arena's default allocator, which uses fastMalloc and
+    // fastFree to allocate chunks of storage.
+    class FastMallocAllocator : public Allocator {
+    public:
+        static PassRefPtr<FastMallocAllocator> create()
+        {
+            return adoptRef(new FastMallocAllocator);
+        }
+
+        virtual void* allocate(size_t size) { return fastMalloc(size); }
+        virtual void free(void* ptr) { fastFree(ptr); }
+
+    protected:
+        FastMallocAllocator() { }
+    };
+
+    // Creates a new PODArena configured with a FastMallocAllocator.
+    static PassRefPtr<PODArena> create()
+    {
+        return adoptRef(new PODArena);
+    }
+
+    // Creates a new PODArena configured with the given Allocator.
+    static PassRefPtr<PODArena> create(PassRefPtr<Allocator> allocator)
+    {
+        return adoptRef(new PODArena(allocator));
+    }
+
+    // Allocates an object from the arena.
+    template<class T> T* allocateObject()
+    {
+        void* ptr = 0;
+        size_t roundedSize = roundUp(sizeof(T), minAlignment<T>());
+        if (m_current)
+            ptr = m_current->allocate(roundedSize);
+
+        if (!ptr) {
+            if (roundedSize > m_currentChunkSize)
+                m_currentChunkSize = roundedSize;
+            m_chunks.append(adoptPtr(new Chunk(m_allocator.get(), m_currentChunkSize)));
+            m_current = m_chunks.last().get();
+            ptr = m_current->allocate(roundedSize);
+        }
+
+        if (ptr) {
+            // Use placement operator new to allocate a T at this location.
+            new(ptr) T();
+        }
+
+        return static_cast<T*>(ptr);
+    }
+
+protected:
+    ~PODArena() { }
+    friend class WTF::RefCounted<PODArena>;
+
+private:
+    PODArena()
+        : m_allocator(FastMallocAllocator::create())
+        , m_current(0)
+        , m_currentChunkSize(DefaultChunkSize) { }
+
+    explicit PODArena(PassRefPtr<Allocator> allocator)
+        : m_allocator(allocator)
+        , m_current(0)
+        , m_currentChunkSize(DefaultChunkSize) { }
+
+    enum {
+        DefaultChunkSize = 16384
+    };
+
+    // Returns the alignment requirement for classes and structs on the
+    // current platform.
+    template <class T> static size_t minAlignment()
+    {
+        return WTF_ALIGN_OF(T);
+    }
+
+    // Rounds up the given allocation size to the specified alignment.
+    size_t roundUp(size_t size, size_t alignment)
+    {
+        ASSERT(!(alignment % 2));
+        return (size + alignment - 1) & ~(alignment - 1);
+    }
+
+    // Manages a chunk of memory and individual allocations out of it.
+    class Chunk : public Noncopyable {
+    public:
+        // Allocates a block of memory of the given size from the passed
+        // Allocator.
+        Chunk(Allocator* allocator, size_t size)
+            : m_allocator(allocator)
+            , m_size(size)
+            , m_currentOffset(0)
+        {
+            m_base = static_cast<uint8_t*>(m_allocator->allocate(size));
+        }
+
+        // Frees the memory allocated from the Allocator in the
+        // constructor.
+        ~Chunk()
+        {
+            m_allocator->free(m_base);
+        }
+
+        // Returns a pointer to "size" bytes of storage, or 0 if this
+        // Chunk could not satisfy the allocation.
+        void* allocate(size_t size)
+        {
+            // Check for overflow
+            if (m_currentOffset + size < m_currentOffset)
+                return 0;
+
+            if (m_currentOffset + size > m_size)
+                return 0;
+
+            void* result = m_base + m_currentOffset;
+            m_currentOffset += size;
+            return result;
+        }
+
+    private:
+        Allocator* m_allocator;
+        uint8_t* m_base;
+        size_t m_size;
+        size_t m_currentOffset;
+    };
+
+    RefPtr<Allocator> m_allocator;
+    Chunk* m_current;
+    size_t m_currentChunkSize;
+    Vector<OwnPtr<Chunk> > m_chunks;
+};
+
+} // namespace WebCore
+
+#endif // PODArena_h
diff --git a/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/WebCore/platform/graphics/gpu/PODRedBlackTree.h
new file mode 100644
index 0000000..7bfa64c
--- /dev/null
+++ b/WebCore/platform/graphics/gpu/PODRedBlackTree.h
@@ -0,0 +1,756 @@
+/*
+ * Copyright 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 following function to be available:
+//
+//   String valueToString(const 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 "PODArena.h"
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+#ifndef NDEBUG
+#include "Logging.h"
+#include "PlatformString.h"
+#include "StringBuilder.h"
+#include <wtf/text/CString.h>
+#endif
+
+namespace WebCore {
+
+template<class T>
+class PODRedBlackTree {
+public:
+    // 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, allocating temporary objects
+    // from a newly constructed PODArena.
+    PODRedBlackTree()
+        : m_arena(PODArena::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<PODArena> arena)
+        : m_arena(arena)
+        , m_root(0)
+        , m_needsFullOrderingComparisons(false)
+#ifndef NDEBUG
+        , m_verboseDebugging(false)
+#endif
+    {
+    }
+
+    virtual ~PODRedBlackTree() { }
+
+    void add(const T& data)
+    {
+        Node* node = new Node(data);
+        insertNode(node);
+    }
+
+    // Returns true if the datum was found in the tree.
+    bool remove(const T& data)
+    {
+        Node* node = treeSearch(data);
+        if (node) {
+            deleteNode(node);
+            return true;
+        }
+        return false;
+    }
+
+    bool contains(const T& data) const { return treeSearch(data); }
+
+    void visitInorder(Visitor* visitor) const
+    {
+        if (!m_root)
+            return;
+        visitInorderImpl(m_root, visitor);
+    }
+
+    int size() const
+    {
+        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
+    {
+        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
+    {
+        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
+
+protected:
+    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 : public Noncopyable {
+    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;
+    };
+
+    // 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* 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);
+    }
+
+    // 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);
+    }
+
+    //----------------------------------------------------------------------
+    // Helper class for size()
+
+    // A Visitor which simply counts the number of visited elements.
+    class Counter : public Visitor, public Noncopyable {
+    public:
+        Counter()
+            : m_count(0) { }
+
+        virtual void visit(const T& data) { ++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* output) 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(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<PODArena> m_arena;
+    Node* m_root;
+    bool m_needsFullOrderingComparisons;
+#ifndef NDEBUG
+    bool m_verboseDebugging;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // PODRedBlackTree_h

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list