Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_SPLAY_TREE_INL_H_
      6 #define V8_SPLAY_TREE_INL_H_
      7 
      8 #include "src/splay-tree.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 
     14 template<typename Config, class Allocator>
     15 SplayTree<Config, Allocator>::~SplayTree() {
     16   NodeDeleter deleter;
     17   ForEachNode(&deleter);
     18 }
     19 
     20 
     21 template<typename Config, class Allocator>
     22 bool SplayTree<Config, Allocator>::Insert(const Key& key,
     23                                           Locator* locator) {
     24   if (is_empty()) {
     25     // If the tree is empty, insert the new node.
     26     root_ = new(allocator_) Node(key, Config::NoValue());
     27   } else {
     28     // Splay on the key to move the last node on the search path
     29     // for the key to the root of the tree.
     30     Splay(key);
     31     // Ignore repeated insertions with the same key.
     32     int cmp = Config::Compare(key, root_->key_);
     33     if (cmp == 0) {
     34       locator->bind(root_);
     35       return false;
     36     }
     37     // Insert the new node.
     38     Node* node = new(allocator_) Node(key, Config::NoValue());
     39     InsertInternal(cmp, node);
     40   }
     41   locator->bind(root_);
     42   return true;
     43 }
     44 
     45 
     46 template<typename Config, class Allocator>
     47 void SplayTree<Config, Allocator>::InsertInternal(int cmp, Node* node) {
     48   if (cmp > 0) {
     49     node->left_ = root_;
     50     node->right_ = root_->right_;
     51     root_->right_ = NULL;
     52   } else {
     53     node->right_ = root_;
     54     node->left_ = root_->left_;
     55     root_->left_ = NULL;
     56   }
     57   root_ = node;
     58 }
     59 
     60 
     61 template<typename Config, class Allocator>
     62 bool SplayTree<Config, Allocator>::FindInternal(const Key& key) {
     63   if (is_empty())
     64     return false;
     65   Splay(key);
     66   return Config::Compare(key, root_->key_) == 0;
     67 }
     68 
     69 
     70 template<typename Config, class Allocator>
     71 bool SplayTree<Config, Allocator>::Contains(const Key& key) {
     72   return FindInternal(key);
     73 }
     74 
     75 
     76 template<typename Config, class Allocator>
     77 bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
     78   if (FindInternal(key)) {
     79     locator->bind(root_);
     80     return true;
     81   } else {
     82     return false;
     83   }
     84 }
     85 
     86 
     87 template<typename Config, class Allocator>
     88 bool SplayTree<Config, Allocator>::FindGreatestLessThan(const Key& key,
     89                                                         Locator* locator) {
     90   if (is_empty())
     91     return false;
     92   // Splay on the key to move the node with the given key or the last
     93   // node on the search path to the top of the tree.
     94   Splay(key);
     95   // Now the result is either the root node or the greatest node in
     96   // the left subtree.
     97   int cmp = Config::Compare(root_->key_, key);
     98   if (cmp <= 0) {
     99     locator->bind(root_);
    100     return true;
    101   } else {
    102     Node* temp = root_;
    103     root_ = root_->left_;
    104     bool result = FindGreatest(locator);
    105     root_ = temp;
    106     return result;
    107   }
    108 }
    109 
    110 
    111 template<typename Config, class Allocator>
    112 bool SplayTree<Config, Allocator>::FindLeastGreaterThan(const Key& key,
    113                                                         Locator* locator) {
    114   if (is_empty())
    115     return false;
    116   // Splay on the key to move the node with the given key or the last
    117   // node on the search path to the top of the tree.
    118   Splay(key);
    119   // Now the result is either the root node or the least node in
    120   // the right subtree.
    121   int cmp = Config::Compare(root_->key_, key);
    122   if (cmp >= 0) {
    123     locator->bind(root_);
    124     return true;
    125   } else {
    126     Node* temp = root_;
    127     root_ = root_->right_;
    128     bool result = FindLeast(locator);
    129     root_ = temp;
    130     return result;
    131   }
    132 }
    133 
    134 
    135 template<typename Config, class Allocator>
    136 bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) {
    137   if (is_empty())
    138     return false;
    139   Node* current = root_;
    140   while (current->right_ != NULL)
    141     current = current->right_;
    142   locator->bind(current);
    143   return true;
    144 }
    145 
    146 
    147 template<typename Config, class Allocator>
    148 bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
    149   if (is_empty())
    150     return false;
    151   Node* current = root_;
    152   while (current->left_ != NULL)
    153     current = current->left_;
    154   locator->bind(current);
    155   return true;
    156 }
    157 
    158 
    159 template<typename Config, class Allocator>
    160 bool SplayTree<Config, Allocator>::Move(const Key& old_key,
    161                                         const Key& new_key) {
    162   if (!FindInternal(old_key))
    163     return false;
    164   Node* node_to_move = root_;
    165   RemoveRootNode(old_key);
    166   Splay(new_key);
    167   int cmp = Config::Compare(new_key, root_->key_);
    168   if (cmp == 0) {
    169     // A node with the target key already exists.
    170     delete node_to_move;
    171     return false;
    172   }
    173   node_to_move->key_ = new_key;
    174   InsertInternal(cmp, node_to_move);
    175   return true;
    176 }
    177 
    178 
    179 template<typename Config, class Allocator>
    180 bool SplayTree<Config, Allocator>::Remove(const Key& key) {
    181   if (!FindInternal(key))
    182     return false;
    183   Node* node_to_remove = root_;
    184   RemoveRootNode(key);
    185   delete node_to_remove;
    186   return true;
    187 }
    188 
    189 
    190 template<typename Config, class Allocator>
    191 void SplayTree<Config, Allocator>::RemoveRootNode(const Key& key) {
    192   if (root_->left_ == NULL) {
    193     // No left child, so the new tree is just the right child.
    194     root_ = root_->right_;
    195   } else {
    196     // Left child exists.
    197     Node* right = root_->right_;
    198     // Make the original left child the new root.
    199     root_ = root_->left_;
    200     // Splay to make sure that the new root has an empty right child.
    201     Splay(key);
    202     // Insert the original right child as the right child of the new
    203     // root.
    204     root_->right_ = right;
    205   }
    206 }
    207 
    208 
    209 template<typename Config, class Allocator>
    210 void SplayTree<Config, Allocator>::Splay(const Key& key) {
    211   if (is_empty())
    212     return;
    213   Node dummy_node(Config::kNoKey, Config::NoValue());
    214   // Create a dummy node.  The use of the dummy node is a bit
    215   // counter-intuitive: The right child of the dummy node will hold
    216   // the L tree of the algorithm.  The left child of the dummy node
    217   // will hold the R tree of the algorithm.  Using a dummy node, left
    218   // and right will always be nodes and we avoid special cases.
    219   Node* dummy = &dummy_node;
    220   Node* left = dummy;
    221   Node* right = dummy;
    222   Node* current = root_;
    223   while (true) {
    224     int cmp = Config::Compare(key, current->key_);
    225     if (cmp < 0) {
    226       if (current->left_ == NULL)
    227         break;
    228       if (Config::Compare(key, current->left_->key_) < 0) {
    229         // Rotate right.
    230         Node* temp = current->left_;
    231         current->left_ = temp->right_;
    232         temp->right_ = current;
    233         current = temp;
    234         if (current->left_ == NULL)
    235           break;
    236       }
    237       // Link right.
    238       right->left_ = current;
    239       right = current;
    240       current = current->left_;
    241     } else if (cmp > 0) {
    242       if (current->right_ == NULL)
    243         break;
    244       if (Config::Compare(key, current->right_->key_) > 0) {
    245         // Rotate left.
    246         Node* temp = current->right_;
    247         current->right_ = temp->left_;
    248         temp->left_ = current;
    249         current = temp;
    250         if (current->right_ == NULL)
    251           break;
    252       }
    253       // Link left.
    254       left->right_ = current;
    255       left = current;
    256       current = current->right_;
    257     } else {
    258       break;
    259     }
    260   }
    261   // Assemble.
    262   left->right_ = current->left_;
    263   right->left_ = current->right_;
    264   current->left_ = dummy->right_;
    265   current->right_ = dummy->left_;
    266   root_ = current;
    267 }
    268 
    269 
    270 template <typename Config, class Allocator> template <class Callback>
    271 void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
    272   NodeToPairAdaptor<Callback> callback_adaptor(callback);
    273   ForEachNode(&callback_adaptor);
    274 }
    275 
    276 
    277 template <typename Config, class Allocator> template <class Callback>
    278 void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
    279   if (root_ == NULL) return;
    280   // Pre-allocate some space for tiny trees.
    281   List<Node*, Allocator> nodes_to_visit(10, allocator_);
    282   nodes_to_visit.Add(root_, allocator_);
    283   int pos = 0;
    284   while (pos < nodes_to_visit.length()) {
    285     Node* node = nodes_to_visit[pos++];
    286     if (node->left() != NULL) nodes_to_visit.Add(node->left(), allocator_);
    287     if (node->right() != NULL) nodes_to_visit.Add(node->right(), allocator_);
    288     callback->Call(node);
    289   }
    290 }
    291 
    292 
    293 }  // namespace internal
    294 }  // namespace v8
    295 
    296 #endif  // V8_SPLAY_TREE_INL_H_
    297