// Copyright 2010 the V8 project authors. 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 V8_SPLAY_TREE_INL_H_ #define V8_SPLAY_TREE_INL_H_ #include "splay-tree.h" namespace v8 { namespace internal { template<typename Config, class Allocator> SplayTree<Config, Allocator>::~SplayTree() { NodeDeleter deleter; ForEachNode(&deleter); } template<typename Config, class Allocator> bool SplayTree<Config, Allocator>::Insert(const Key& key, Locator* locator) { if (is_empty()) { // If the tree is empty, insert the new node. root_ = new 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 Node(key, Config::NoValue()); InsertInternal(cmp, node); } locator->bind(root_); return true; } template<typename Config, class Allocator> void SplayTree<Config, Allocator>::InsertInternal(int cmp, Node* node) { if (cmp > 0) { node->left_ = root_; node->right_ = root_->right_; root_->right_ = NULL; } else { node->right_ = root_; node->left_ = root_->left_; root_->left_ = NULL; } root_ = node; } template<typename Config, class Allocator> bool SplayTree<Config, Allocator>::FindInternal(const Key& key) { if (is_empty()) return false; Splay(key); return Config::Compare(key, root_->key_) == 0; } template<typename Config, class Allocator> bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) { if (FindInternal(key)) { locator->bind(root_); return true; } else { return false; } } template<typename Config, class Allocator> bool SplayTree<Config, 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 Allocator> bool SplayTree<Config, 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 Allocator> bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) { if (is_empty()) return false; Node* current = root_; while (current->right_ != NULL) current = current->right_; locator->bind(current); return true; } template<typename Config, class Allocator> bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) { if (is_empty()) return false; Node* current = root_; while (current->left_ != NULL) current = current->left_; locator->bind(current); return true; } template<typename Config, class Allocator> bool SplayTree<Config, 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 Allocator> bool SplayTree<Config, 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 Allocator> void SplayTree<Config, Allocator>::RemoveRootNode(const Key& key) { if (root_->left_ == NULL) { // 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 Allocator> void SplayTree<Config, 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_ == NULL) 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_ == NULL) break; } // Link right. right->left_ = current; right = current; current = current->left_; } else if (cmp > 0) { if (current->right_ == NULL) 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_ == NULL) 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 Allocator> template <class Callback> void SplayTree<Config, Allocator>::ForEach(Callback* callback) { NodeToPairAdaptor<Callback> callback_adaptor(callback); ForEachNode(&callback_adaptor); } template <typename Config, class Allocator> template <class Callback> void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) { // Pre-allocate some space for tiny trees. List<Node*, Allocator> nodes_to_visit(10); if (root_ != NULL) nodes_to_visit.Add(root_); int pos = 0; while (pos < nodes_to_visit.length()) { Node* node = nodes_to_visit[pos++]; if (node->left() != NULL) nodes_to_visit.Add(node->left()); if (node->right() != NULL) nodes_to_visit.Add(node->right()); callback->Call(node); } } } } // namespace v8::internal #endif // V8_SPLAY_TREE_INL_H_