| // Copyright (c) 2010, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 | // | 
 | // The original file can be found at: | 
 | // https://github.com/v8/v8/blob/master/src/splay-tree-inl.h | 
 |  | 
 | #ifndef RUNTIME_PLATFORM_SPLAY_TREE_INL_H_ | 
 | #define RUNTIME_PLATFORM_SPLAY_TREE_INL_H_ | 
 |  | 
 | #include <vector> | 
 |  | 
 | #include "platform/splay-tree.h" | 
 |  | 
 | namespace dart { | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | SplayTree<Config, B, Allocator>::~SplayTree() { | 
 |   NodeDeleter deleter; | 
 |   ForEachNode(&deleter); | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::Insert(const Key& key, Locator* locator) { | 
 |   if (is_empty()) { | 
 |     // If the tree is empty, insert the new node. | 
 |     root_ = new (allocator_) Node(key, Config::NoValue()); | 
 |   } else { | 
 |     // Splay on the key to move the last node on the search path | 
 |     // for the key to the root of the tree. | 
 |     Splay(key); | 
 |     // Ignore repeated insertions with the same key. | 
 |     int cmp = Config::Compare(key, root_->key_); | 
 |     if (cmp == 0) { | 
 |       locator->bind(root_); | 
 |       return false; | 
 |     } | 
 |     // Insert the new node. | 
 |     Node* node = new (allocator_) Node(key, Config::NoValue()); | 
 |     InsertInternal(cmp, node); | 
 |   } | 
 |   locator->bind(root_); | 
 |   return true; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | void SplayTree<Config, B, Allocator>::InsertInternal(int cmp, Node* node) { | 
 |   if (cmp > 0) { | 
 |     node->left_ = root_; | 
 |     node->right_ = root_->right_; | 
 |     root_->right_ = nullptr; | 
 |   } else { | 
 |     node->right_ = root_; | 
 |     node->left_ = root_->left_; | 
 |     root_->left_ = nullptr; | 
 |   } | 
 |   root_ = node; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::FindInternal(const Key& key) { | 
 |   if (is_empty()) return false; | 
 |   Splay(key); | 
 |   return Config::Compare(key, root_->key_) == 0; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::Contains(const Key& key) { | 
 |   return FindInternal(key); | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::Find(const Key& key, Locator* locator) { | 
 |   if (FindInternal(key)) { | 
 |     locator->bind(root_); | 
 |     return true; | 
 |   } else { | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::FindGreatestLessThan(const Key& key, | 
 |                                                            Locator* locator) { | 
 |   if (is_empty()) return false; | 
 |   // Splay on the key to move the node with the given key or the last | 
 |   // node on the search path to the top of the tree. | 
 |   Splay(key); | 
 |   // Now the result is either the root node or the greatest node in | 
 |   // the left subtree. | 
 |   int cmp = Config::Compare(root_->key_, key); | 
 |   if (cmp <= 0) { | 
 |     locator->bind(root_); | 
 |     return true; | 
 |   } else { | 
 |     Node* temp = root_; | 
 |     root_ = root_->left_; | 
 |     bool result = FindGreatest(locator); | 
 |     root_ = temp; | 
 |     return result; | 
 |   } | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::FindLeastGreaterThan(const Key& key, | 
 |                                                            Locator* locator) { | 
 |   if (is_empty()) return false; | 
 |   // Splay on the key to move the node with the given key or the last | 
 |   // node on the search path to the top of the tree. | 
 |   Splay(key); | 
 |   // Now the result is either the root node or the least node in | 
 |   // the right subtree. | 
 |   int cmp = Config::Compare(root_->key_, key); | 
 |   if (cmp >= 0) { | 
 |     locator->bind(root_); | 
 |     return true; | 
 |   } else { | 
 |     Node* temp = root_; | 
 |     root_ = root_->right_; | 
 |     bool result = FindLeast(locator); | 
 |     root_ = temp; | 
 |     return result; | 
 |   } | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::FindGreatest(Locator* locator) { | 
 |   if (is_empty()) return false; | 
 |   Node* current = root_; | 
 |   while (current->right_ != nullptr) | 
 |     current = current->right_; | 
 |   locator->bind(current); | 
 |   return true; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::FindLeast(Locator* locator) { | 
 |   if (is_empty()) return false; | 
 |   Node* current = root_; | 
 |   while (current->left_ != nullptr) | 
 |     current = current->left_; | 
 |   locator->bind(current); | 
 |   return true; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::Move(const Key& old_key, | 
 |                                            const Key& new_key) { | 
 |   if (!FindInternal(old_key)) return false; | 
 |   Node* node_to_move = root_; | 
 |   RemoveRootNode(old_key); | 
 |   Splay(new_key); | 
 |   int cmp = Config::Compare(new_key, root_->key_); | 
 |   if (cmp == 0) { | 
 |     // A node with the target key already exists. | 
 |     delete node_to_move; | 
 |     return false; | 
 |   } | 
 |   node_to_move->key_ = new_key; | 
 |   InsertInternal(cmp, node_to_move); | 
 |   return true; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | bool SplayTree<Config, B, Allocator>::Remove(const Key& key) { | 
 |   if (!FindInternal(key)) return false; | 
 |   Node* node_to_remove = root_; | 
 |   RemoveRootNode(key); | 
 |   delete node_to_remove; | 
 |   return true; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | void SplayTree<Config, B, Allocator>::RemoveRootNode(const Key& key) { | 
 |   if (root_->left_ == nullptr) { | 
 |     // No left child, so the new tree is just the right child. | 
 |     root_ = root_->right_; | 
 |   } else { | 
 |     // Left child exists. | 
 |     Node* right = root_->right_; | 
 |     // Make the original left child the new root. | 
 |     root_ = root_->left_; | 
 |     // Splay to make sure that the new root has an empty right child. | 
 |     Splay(key); | 
 |     // Insert the original right child as the right child of the new | 
 |     // root. | 
 |     root_->right_ = right; | 
 |   } | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | void SplayTree<Config, B, Allocator>::Splay(const Key& key) { | 
 |   if (is_empty()) return; | 
 |   Node dummy_node(Config::kNoKey, Config::NoValue()); | 
 |   // Create a dummy node.  The use of the dummy node is a bit | 
 |   // counter-intuitive: The right child of the dummy node will hold | 
 |   // the L tree of the algorithm.  The left child of the dummy node | 
 |   // will hold the R tree of the algorithm.  Using a dummy node, left | 
 |   // and right will always be nodes and we avoid special cases. | 
 |   Node* dummy = &dummy_node; | 
 |   Node* left = dummy; | 
 |   Node* right = dummy; | 
 |   Node* current = root_; | 
 |   while (true) { | 
 |     int cmp = Config::Compare(key, current->key_); | 
 |     if (cmp < 0) { | 
 |       if (current->left_ == nullptr) break; | 
 |       if (Config::Compare(key, current->left_->key_) < 0) { | 
 |         // Rotate right. | 
 |         Node* temp = current->left_; | 
 |         current->left_ = temp->right_; | 
 |         temp->right_ = current; | 
 |         current = temp; | 
 |         if (current->left_ == nullptr) break; | 
 |       } | 
 |       // Link right. | 
 |       right->left_ = current; | 
 |       right = current; | 
 |       current = current->left_; | 
 |     } else if (cmp > 0) { | 
 |       if (current->right_ == nullptr) break; | 
 |       if (Config::Compare(key, current->right_->key_) > 0) { | 
 |         // Rotate left. | 
 |         Node* temp = current->right_; | 
 |         current->right_ = temp->left_; | 
 |         temp->left_ = current; | 
 |         current = temp; | 
 |         if (current->right_ == nullptr) break; | 
 |       } | 
 |       // Link left. | 
 |       left->right_ = current; | 
 |       left = current; | 
 |       current = current->right_; | 
 |     } else { | 
 |       break; | 
 |     } | 
 |   } | 
 |   // Assemble. | 
 |   left->right_ = current->left_; | 
 |   right->left_ = current->right_; | 
 |   current->left_ = dummy->right_; | 
 |   current->right_ = dummy->left_; | 
 |   root_ = current; | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | template <class Callback> | 
 | void SplayTree<Config, B, Allocator>::ForEach(Callback* callback) { | 
 |   NodeToPairAdaptor<Callback> callback_adaptor(callback); | 
 |   ForEachNode(&callback_adaptor); | 
 | } | 
 |  | 
 | template <typename Config, class B, class Allocator> | 
 | template <class Callback> | 
 | void SplayTree<Config, B, Allocator>::ForEachNode(Callback* callback) { | 
 |   if (root_ == nullptr) return; | 
 |   // Pre-allocate some space for tiny trees. | 
 |   std::vector<Node*> nodes_to_visit; | 
 |   nodes_to_visit.push_back(root_); | 
 |   size_t pos = 0; | 
 |   while (pos < nodes_to_visit.size()) { | 
 |     Node* node = nodes_to_visit[pos++]; | 
 |     if (node->left() != nullptr) nodes_to_visit.push_back(node->left()); | 
 |     if (node->right() != nullptr) nodes_to_visit.push_back(node->right()); | 
 |     callback->Call(node); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace dart | 
 |  | 
 | #endif  // RUNTIME_PLATFORM_SPLAY_TREE_INL_H_ |