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 <vector>
9
10 #include "src/splay-tree.h"
11
12 namespace v8 {
13 namespace internal {
14
15
16 template<typename Config, class Allocator>
~SplayTree()17 SplayTree<Config, Allocator>::~SplayTree() {
18 NodeDeleter deleter;
19 ForEachNode(&deleter);
20 }
21
22
23 template<typename Config, class Allocator>
Insert(const Key & key,Locator * locator)24 bool SplayTree<Config, Allocator>::Insert(const Key& key,
25 Locator* locator) {
26 if (is_empty()) {
27 // If the tree is empty, insert the new node.
28 root_ = new(allocator_) Node(key, Config::NoValue());
29 } else {
30 // Splay on the key to move the last node on the search path
31 // for the key to the root of the tree.
32 Splay(key);
33 // Ignore repeated insertions with the same key.
34 int cmp = Config::Compare(key, root_->key_);
35 if (cmp == 0) {
36 locator->bind(root_);
37 return false;
38 }
39 // Insert the new node.
40 Node* node = new(allocator_) Node(key, Config::NoValue());
41 InsertInternal(cmp, node);
42 }
43 locator->bind(root_);
44 return true;
45 }
46
47
48 template<typename Config, class Allocator>
InsertInternal(int cmp,Node * node)49 void SplayTree<Config, Allocator>::InsertInternal(int cmp, Node* node) {
50 if (cmp > 0) {
51 node->left_ = root_;
52 node->right_ = root_->right_;
53 root_->right_ = nullptr;
54 } else {
55 node->right_ = root_;
56 node->left_ = root_->left_;
57 root_->left_ = nullptr;
58 }
59 root_ = node;
60 }
61
62
63 template<typename Config, class Allocator>
FindInternal(const Key & key)64 bool SplayTree<Config, Allocator>::FindInternal(const Key& key) {
65 if (is_empty())
66 return false;
67 Splay(key);
68 return Config::Compare(key, root_->key_) == 0;
69 }
70
71
72 template<typename Config, class Allocator>
Contains(const Key & key)73 bool SplayTree<Config, Allocator>::Contains(const Key& key) {
74 return FindInternal(key);
75 }
76
77
78 template<typename Config, class Allocator>
Find(const Key & key,Locator * locator)79 bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
80 if (FindInternal(key)) {
81 locator->bind(root_);
82 return true;
83 } else {
84 return false;
85 }
86 }
87
88
89 template<typename Config, class Allocator>
FindGreatestLessThan(const Key & key,Locator * locator)90 bool SplayTree<Config, Allocator>::FindGreatestLessThan(const Key& key,
91 Locator* locator) {
92 if (is_empty())
93 return false;
94 // Splay on the key to move the node with the given key or the last
95 // node on the search path to the top of the tree.
96 Splay(key);
97 // Now the result is either the root node or the greatest node in
98 // the left subtree.
99 int cmp = Config::Compare(root_->key_, key);
100 if (cmp <= 0) {
101 locator->bind(root_);
102 return true;
103 } else {
104 Node* temp = root_;
105 root_ = root_->left_;
106 bool result = FindGreatest(locator);
107 root_ = temp;
108 return result;
109 }
110 }
111
112
113 template<typename Config, class Allocator>
FindLeastGreaterThan(const Key & key,Locator * locator)114 bool SplayTree<Config, Allocator>::FindLeastGreaterThan(const Key& key,
115 Locator* locator) {
116 if (is_empty())
117 return false;
118 // Splay on the key to move the node with the given key or the last
119 // node on the search path to the top of the tree.
120 Splay(key);
121 // Now the result is either the root node or the least node in
122 // the right subtree.
123 int cmp = Config::Compare(root_->key_, key);
124 if (cmp >= 0) {
125 locator->bind(root_);
126 return true;
127 } else {
128 Node* temp = root_;
129 root_ = root_->right_;
130 bool result = FindLeast(locator);
131 root_ = temp;
132 return result;
133 }
134 }
135
136
137 template<typename Config, class Allocator>
FindGreatest(Locator * locator)138 bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) {
139 if (is_empty())
140 return false;
141 Node* current = root_;
142 while (current->right_ != nullptr) current = current->right_;
143 locator->bind(current);
144 return true;
145 }
146
147
148 template<typename Config, class Allocator>
FindLeast(Locator * locator)149 bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
150 if (is_empty())
151 return false;
152 Node* current = root_;
153 while (current->left_ != nullptr) current = current->left_;
154 locator->bind(current);
155 return true;
156 }
157
158
159 template<typename Config, class Allocator>
Move(const Key & old_key,const Key & new_key)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>
Remove(const Key & key)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>
RemoveRootNode(const Key & key)191 void SplayTree<Config, Allocator>::RemoveRootNode(const Key& key) {
192 if (root_->left_ == nullptr) {
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>
Splay(const Key & key)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_ == nullptr) break;
227 if (Config::Compare(key, current->left_->key_) < 0) {
228 // Rotate right.
229 Node* temp = current->left_;
230 current->left_ = temp->right_;
231 temp->right_ = current;
232 current = temp;
233 if (current->left_ == nullptr) break;
234 }
235 // Link right.
236 right->left_ = current;
237 right = current;
238 current = current->left_;
239 } else if (cmp > 0) {
240 if (current->right_ == nullptr) break;
241 if (Config::Compare(key, current->right_->key_) > 0) {
242 // Rotate left.
243 Node* temp = current->right_;
244 current->right_ = temp->left_;
245 temp->left_ = current;
246 current = temp;
247 if (current->right_ == nullptr) break;
248 }
249 // Link left.
250 left->right_ = current;
251 left = current;
252 current = current->right_;
253 } else {
254 break;
255 }
256 }
257 // Assemble.
258 left->right_ = current->left_;
259 right->left_ = current->right_;
260 current->left_ = dummy->right_;
261 current->right_ = dummy->left_;
262 root_ = current;
263 }
264
265
266 template <typename Config, class Allocator> template <class Callback>
ForEach(Callback * callback)267 void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
268 NodeToPairAdaptor<Callback> callback_adaptor(callback);
269 ForEachNode(&callback_adaptor);
270 }
271
272
273 template <typename Config, class Allocator> template <class Callback>
ForEachNode(Callback * callback)274 void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
275 if (root_ == nullptr) return;
276 // Pre-allocate some space for tiny trees.
277 std::vector<Node*> nodes_to_visit;
278 nodes_to_visit.push_back(root_);
279 size_t pos = 0;
280 while (pos < nodes_to_visit.size()) {
281 Node* node = nodes_to_visit[pos++];
282 if (node->left() != nullptr) nodes_to_visit.push_back(node->left());
283 if (node->right() != nullptr) nodes_to_visit.push_back(node->right());
284 callback->Call(node);
285 }
286 }
287
288
289 } // namespace internal
290 } // namespace v8
291
292 #endif // V8_SPLAY_TREE_INL_H_
293