LCOV - code coverage report
Current view: top level - js/src/ds - SplayTree.h (source / functions) Hit Total Coverage
Test: output.info Lines: 131 151 86.8 %
Date: 2017-07-14 16:53:18 Functions: 23 37 62.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #ifndef ds_SplayTree_h
       8             : #define ds_SplayTree_h
       9             : 
      10             : #include "ds/LifoAlloc.h"
      11             : 
      12             : namespace js {
      13             : 
      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;
      29             :         Node* right;
      30             :         Node* parent;
      31             : 
      32        4476 :         explicit Node(const T& item)
      33        4476 :           : item(item), left(nullptr), right(nullptr), parent(nullptr)
      34        4476 :         {}
      35             :     };
      36             : 
      37             :     LifoAlloc* alloc;
      38             :     Node* root;
      39             :     Node* freeList;
      40             : 
      41             : #ifdef DEBUG
      42             :     bool enableCheckCoherency;
      43             : #endif
      44             : 
      45             :     SplayTree(const SplayTree&) = delete;
      46             :     SplayTree& operator=(const SplayTree&) = delete;
      47             : 
      48             :   public:
      49             : 
      50         615 :     explicit SplayTree(LifoAlloc* alloc = nullptr)
      51             :       : alloc(alloc), root(nullptr), freeList(nullptr)
      52             : #ifdef DEBUG
      53         615 :       , enableCheckCoherency(true)
      54             : #endif
      55         615 :     {}
      56             : 
      57         528 :     void setAllocator(LifoAlloc* alloc) {
      58         528 :         this->alloc = alloc;
      59         528 :     }
      60             : 
      61             :     void disableCheckCoherency() {
      62             : #ifdef DEBUG
      63             :         enableCheckCoherency = false;
      64             : #endif
      65             :     }
      66             : 
      67           0 :     bool empty() const {
      68           0 :         return !root;
      69             :     }
      70             : 
      71           0 :     T* maybeLookup(const T& v)
      72             :     {
      73           0 :         if (!root)
      74           0 :             return nullptr;
      75           0 :         Node* last = lookup(v);
      76           0 :         return (C::compare(v, last->item) == 0) ? &(last->item) : nullptr;
      77             :     }
      78             : 
      79       24978 :     bool contains(const T& v, T* res)
      80             :     {
      81       24978 :         if (!root)
      82          79 :             return false;
      83       24899 :         Node* last = lookup(v);
      84       24899 :         splay(last);
      85       24899 :         checkCoherency(root, nullptr);
      86       24899 :         if (C::compare(v, last->item) == 0) {
      87       12232 :             *res = last->item;
      88       12232 :             return true;
      89             :         }
      90       12667 :         return false;
      91             :     }
      92             : 
      93        4476 :     MOZ_MUST_USE bool insert(const T& v)
      94             :     {
      95        4476 :         Node* element = allocateNode(v);
      96        4476 :         if (!element)
      97           0 :             return false;
      98             : 
      99        4476 :         if (!root) {
     100         459 :             root = element;
     101         459 :             return true;
     102             :         }
     103        4017 :         Node* last = lookup(v);
     104        4017 :         int cmp = C::compare(v, last->item);
     105             : 
     106             :         // Don't tolerate duplicate elements.
     107        4017 :         MOZ_ASSERT(cmp);
     108             : 
     109        4017 :         Node*& parentPointer = (cmp < 0) ? last->left : last->right;
     110        4017 :         MOZ_ASSERT(!parentPointer);
     111        4017 :         parentPointer = element;
     112        4017 :         element->parent = last;
     113             : 
     114        4017 :         splay(element);
     115        4017 :         checkCoherency(root, nullptr);
     116        4017 :         return true;
     117             :     }
     118             : 
     119         171 :     void remove(const T& v)
     120             :     {
     121         171 :         Node* last = lookup(v);
     122         171 :         MOZ_ASSERT(last && C::compare(v, last->item) == 0);
     123             : 
     124         171 :         splay(last);
     125         171 :         MOZ_ASSERT(last == root);
     126             : 
     127             :         // Find another node which can be swapped in for the root: either the
     128             :         // rightmost child of the root's left, or the leftmost child of the
     129             :         // root's right.
     130             :         Node* swap;
     131             :         Node* swapChild;
     132         171 :         if (root->left) {
     133          88 :             swap = root->left;
     134         186 :             while (swap->right)
     135          49 :                 swap = swap->right;
     136          88 :             swapChild = swap->left;
     137          83 :         } else if (root->right) {
     138          80 :             swap = root->right;
     139         162 :             while (swap->left)
     140          41 :                 swap = swap->left;
     141          80 :             swapChild = swap->right;
     142             :         } else {
     143           3 :             freeNode(root);
     144           3 :             root = nullptr;
     145           3 :             return;
     146             :         }
     147             : 
     148             :         // The selected node has at most one child, in swapChild. Detach it
     149             :         // from the subtree by replacing it with that child.
     150         168 :         if (swap == swap->parent->left)
     151          97 :             swap->parent->left = swapChild;
     152             :         else
     153          71 :             swap->parent->right = swapChild;
     154         168 :         if (swapChild)
     155         121 :             swapChild->parent = swap->parent;
     156             : 
     157         168 :         root->item = swap->item;
     158         168 :         freeNode(swap);
     159             : 
     160         168 :         checkCoherency(root, nullptr);
     161             :     }
     162             : 
     163             :     template <class Op>
     164           0 :     void forEach(Op op)
     165             :     {
     166           0 :         forEachInner<Op>(op, root);
     167           0 :     }
     168             : 
     169             :   private:
     170             : 
     171       29087 :     Node* lookup(const T& v)
     172             :     {
     173       29087 :         MOZ_ASSERT(root);
     174       29087 :         Node* node = root;
     175             :         Node* parent;
     176       55229 :         do {
     177       67632 :             parent = node;
     178       67632 :             int c = C::compare(v, node->item);
     179       67632 :             if (c == 0)
     180       12403 :                 return node;
     181       55229 :             else if (c < 0)
     182       30449 :                 node = node->left;
     183             :             else
     184       24780 :                 node = node->right;
     185             :         } while (node);
     186       16684 :         return parent;
     187             :     }
     188             : 
     189        4476 :     Node* allocateNode(const T& v)
     190             :     {
     191        4476 :         Node* node = freeList;
     192        4476 :         if (node) {
     193         159 :             freeList = node->left;
     194         159 :             new(node) Node(v);
     195         159 :             return node;
     196             :         }
     197        4317 :         return alloc->new_<Node>(v);
     198             :     }
     199             : 
     200         171 :     void freeNode(Node* node)
     201             :     {
     202         171 :         node->left = freeList;
     203         171 :         freeList = node;
     204         171 :     }
     205             : 
     206       29087 :     void splay(Node* node)
     207             :     {
     208             :         // Rotate the element until it is at the root of the tree. Performing
     209             :         // the rotations in this fashion preserves the amortized balancing of
     210             :         // the tree.
     211       29087 :         MOZ_ASSERT(node);
     212       55587 :         while (node != root) {
     213       29312 :             Node* parent = node->parent;
     214       29312 :             if (parent == root) {
     215             :                 // Zig rotation.
     216       16062 :                 rotate(node);
     217       16062 :                 MOZ_ASSERT(node == root);
     218       16062 :                 return;
     219             :             }
     220       13250 :             Node* grandparent = parent->parent;
     221       13250 :             if ((parent->left == node) == (grandparent->left == parent)) {
     222             :                 // Zig-zig rotation.
     223        8279 :                 rotate(parent);
     224        8279 :                 rotate(node);
     225             :             } else {
     226             :                 // Zig-zag rotation.
     227        4971 :                 rotate(node);
     228        4971 :                 rotate(node);
     229             :             }
     230             :         }
     231             :     }
     232             : 
     233       42562 :     void rotate(Node* node)
     234             :     {
     235             :         // Rearrange nodes so that node becomes the parent of its current
     236             :         // parent, while preserving the sortedness of the tree.
     237       42562 :         Node* parent = node->parent;
     238       42562 :         if (parent->left == node) {
     239             :             //     x          y
     240             :             //   y  c  ==>  a  x
     241             :             //  a b           b c
     242       23664 :             parent->left = node->right;
     243       23664 :             if (node->right)
     244        9516 :                 node->right->parent = parent;
     245       23664 :             node->right = parent;
     246             :         } else {
     247       18898 :             MOZ_ASSERT(parent->right == node);
     248             :             //   x             y
     249             :             //  a  y   ==>   x  c
     250             :             //    b c       a b
     251       18898 :             parent->right = node->left;
     252       18898 :             if (node->left)
     253        6047 :                 node->left->parent = parent;
     254       18898 :             node->left = parent;
     255             :         }
     256       42562 :         node->parent = parent->parent;
     257       42562 :         parent->parent = node;
     258       42562 :         if (Node* grandparent = node->parent) {
     259       18077 :             if (grandparent->left == parent)
     260        9734 :                 grandparent->left = node;
     261             :             else
     262        8343 :                 grandparent->right = node;
     263             :         } else {
     264       24485 :             root = node;
     265             :         }
     266       42562 :     }
     267             : 
     268             :     template <class Op>
     269           0 :     void forEachInner(Op op, Node* node)
     270             :     {
     271           0 :         if (!node)
     272           0 :             return;
     273             : 
     274           0 :         forEachInner<Op>(op, node->left);
     275           0 :         op(node->item);
     276           0 :         forEachInner<Op>(op, node->right);
     277             :     }
     278             : 
     279      618681 :     Node* checkCoherency(Node* node, Node* minimum)
     280             :     {
     281             : #ifdef DEBUG
     282      618681 :         if (!enableCheckCoherency)
     283           0 :             return nullptr;
     284      618681 :         if (!node) {
     285           0 :             MOZ_ASSERT(!root);
     286           0 :             return nullptr;
     287             :         }
     288      618681 :         MOZ_ASSERT_IF(!node->parent, node == root);
     289      618681 :         MOZ_ASSERT_IF(minimum, C::compare(minimum->item, node->item) < 0);
     290      618681 :         if (node->left) {
     291      282330 :             MOZ_ASSERT(node->left->parent == node);
     292      282330 :             Node* leftMaximum = checkCoherency(node->left, minimum);
     293      282330 :             MOZ_ASSERT(C::compare(leftMaximum->item, node->item) < 0);
     294             :         }
     295      618681 :         if (node->right) {
     296      307267 :             MOZ_ASSERT(node->right->parent == node);
     297      307267 :             return checkCoherency(node->right, node);
     298             :         }
     299      311414 :         return node;
     300             : #else
     301             :         return nullptr;
     302             : #endif
     303             :     }
     304             : };
     305             : 
     306             : }  /* namespace js */
     307             : 
     308             : #endif /* ds_SplayTree_h */

Generated by: LCOV version 1.13