js/src/ds/SplayTree.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef ds_SplayTree_h
     8 #define ds_SplayTree_h
    10 #include "ds/LifoAlloc.h"
    12 namespace js {
    14 /*
    15  * Class which represents a splay tree with nodes allocated from a LifoAlloc.
    16  * Splay trees are balanced binary search trees for which search, insert and
    17  * remove are all amortized O(log n).
    18  *
    19  * T indicates the type of tree elements, C must have a static
    20  * compare(const T&, const T&) method ordering the elements. As for LifoAlloc
    21  * objects, T objects stored in the tree will not be explicitly destroyed.
    22  */
    23 template <class T, class C>
    24 class SplayTree
    25 {
    26     struct Node {
    27         T item;
    28         Node *left, *right, *parent;
    30         Node(const T &item)
    31           : item(item), left(nullptr), right(nullptr), parent(nullptr)
    32         {}
    33     };
    35     LifoAlloc *alloc;
    36     Node *root, *freeList;
    38     SplayTree(const SplayTree &) MOZ_DELETE;
    39     SplayTree &operator=(const SplayTree &) MOZ_DELETE;
    41   public:
    43     SplayTree(LifoAlloc *alloc = nullptr)
    44       : alloc(alloc), root(nullptr), freeList(nullptr)
    45     {}
    47     void setAllocator(LifoAlloc *alloc) {
    48         this->alloc = alloc;
    49     }
    51     bool empty() const {
    52         return !root;
    53     }
    55     bool contains(const T &v, T *res)
    56     {
    57         if (!root)
    58             return false;
    59         Node *last = lookup(v);
    60         splay(last);
    61         checkCoherency(root, nullptr);
    62         if (C::compare(v, last->item) == 0) {
    63             *res = last->item;
    64             return true;
    65         }
    66         return false;
    67     }
    69     bool insert(const T &v)
    70     {
    71         Node *element = allocateNode(v);
    72         if (!element)
    73             return false;
    75         if (!root) {
    76             root = element;
    77             return true;
    78         }
    79         Node *last = lookup(v);
    80         int cmp = C::compare(v, last->item);
    82         // Don't tolerate duplicate elements.
    83         JS_ASSERT(cmp);
    85         Node *&parentPointer = (cmp < 0) ? last->left : last->right;
    86         JS_ASSERT(!parentPointer);
    87         parentPointer = element;
    88         element->parent = last;
    90         splay(element);
    91         checkCoherency(root, nullptr);
    92         return true;
    93     }
    95     void remove(const T &v)
    96     {
    97         Node *last = lookup(v);
    98         JS_ASSERT(last && C::compare(v, last->item) == 0);
   100         splay(last);
   101         JS_ASSERT(last == root);
   103         // Find another node which can be swapped in for the root: either the
   104         // rightmost child of the root's left, or the leftmost child of the
   105         // root's right.
   106         Node *swap, *swapChild;
   107         if (root->left) {
   108             swap = root->left;
   109             while (swap->right)
   110                 swap = swap->right;
   111             swapChild = swap->left;
   112         } else if (root->right) {
   113             swap = root->right;
   114             while (swap->left)
   115                 swap = swap->left;
   116             swapChild = swap->right;
   117         } else {
   118             freeNode(root);
   119             root = nullptr;
   120             return;
   121         }
   123         // The selected node has at most one child, in swapChild. Detach it
   124         // from the subtree by replacing it with that child.
   125         if (swap == swap->parent->left)
   126             swap->parent->left = swapChild;
   127         else
   128             swap->parent->right = swapChild;
   129         if (swapChild)
   130             swapChild->parent = swap->parent;
   132         root->item = swap->item;
   133         freeNode(swap);
   135         checkCoherency(root, nullptr);
   136     }
   138     template <class Op>
   139     void forEach(Op op)
   140     {
   141         forEachInner(op, root);
   142     }
   144   private:
   146     Node *lookup(const T &v)
   147     {
   148         JS_ASSERT(root);
   149         Node *node = root, *parent;
   150         do {
   151             parent = node;
   152             int c = C::compare(v, node->item);
   153             if (c == 0)
   154                 return node;
   155             else if (c < 0)
   156                 node = node->left;
   157             else
   158                 node = node->right;
   159         } while (node);
   160         return parent;
   161     }
   163     Node *allocateNode(const T &v)
   164     {
   165         Node *node = freeList;
   166         if (node) {
   167             freeList = node->left;
   168             new(node) Node(v);
   169             return node;
   170         }
   171         return alloc->new_<Node>(v);
   172     }
   174     void freeNode(Node *node)
   175     {
   176         node->left = freeList;
   177         freeList = node;
   178     }
   180     void splay(Node *node)
   181     {
   182         // Rotate the element until it is at the root of the tree. Performing
   183         // the rotations in this fashion preserves the amortized balancing of
   184         // the tree.
   185         JS_ASSERT(node);
   186         while (node != root) {
   187             Node *parent = node->parent;
   188             if (parent == root) {
   189                 // Zig rotation.
   190                 rotate(node);
   191                 JS_ASSERT(node == root);
   192                 return;
   193             }
   194             Node *grandparent = parent->parent;
   195             if ((parent->left == node) == (grandparent->left == parent)) {
   196                 // Zig-zig rotation.
   197                 rotate(parent);
   198                 rotate(node);
   199             } else {
   200                 // Zig-zag rotation.
   201                 rotate(node);
   202                 rotate(node);
   203             }
   204         }
   205     }
   207     void rotate(Node *node)
   208     {
   209         // Rearrange nodes so that node becomes the parent of its current
   210         // parent, while preserving the sortedness of the tree.
   211         Node *parent = node->parent;
   212         if (parent->left == node) {
   213             //     x          y
   214             //   y  c  ==>  a  x
   215             //  a b           b c
   216             parent->left = node->right;
   217             if (node->right)
   218                 node->right->parent = parent;
   219             node->right = parent;
   220         } else {
   221             JS_ASSERT(parent->right == node);
   222             //   x             y
   223             //  a  y   ==>   x  c
   224             //    b c       a b
   225             parent->right = node->left;
   226             if (node->left)
   227                 node->left->parent = parent;
   228             node->left = parent;
   229         }
   230         node->parent = parent->parent;
   231         parent->parent = node;
   232         if (Node *grandparent = node->parent) {
   233             if (grandparent->left == parent)
   234                 grandparent->left = node;
   235             else
   236                 grandparent->right = node;
   237         } else {
   238             root = node;
   239         }
   240     }
   242     template <class Op>
   243     void forEachInner(Op op, Node *node)
   244     {
   245         if (!node)
   246             return;
   248         forEachInner(op, node->left);
   249         op(node->item);
   250         forEachInner(op, node->right);
   251     }
   253     Node *checkCoherency(Node *node, Node *minimum)
   254     {
   255 #ifdef DEBUG
   256         if (!node) {
   257             JS_ASSERT(!root);
   258             return nullptr;
   259         }
   260         JS_ASSERT_IF(!node->parent, node == root);
   261         JS_ASSERT_IF(minimum, C::compare(minimum->item, node->item) < 0);
   262         if (node->left) {
   263             JS_ASSERT(node->left->parent == node);
   264             Node *leftMaximum = checkCoherency(node->left, minimum);
   265             JS_ASSERT(C::compare(leftMaximum->item, node->item) < 0);
   266         }
   267         if (node->right) {
   268             JS_ASSERT(node->right->parent == node);
   269             return checkCoherency(node->right, node);
   270         }
   271         return node;
   272 #else
   273         return nullptr;
   274 #endif
   275     }
   276 };
   278 }  /* namespace js */
   280 #endif /* ds_SplayTree_h */

mercurial