1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #ifndef V8_SPLAY_TREE_INL_H_
29 #define V8_SPLAY_TREE_INL_H_
30
31 #include "splay-tree.h"
32
33 namespace v8 {
34 namespace internal {
35
36
37 template<typename Config, class Allocator>
~SplayTree()38 SplayTree<Config, Allocator>::~SplayTree() {
39 NodeDeleter deleter;
40 ForEachNode(&deleter);
41 }
42
43
44 template<typename Config, class Allocator>
Insert(const Key & key,Locator * locator)45 bool SplayTree<Config, Allocator>::Insert(const Key& key,
46 Locator* locator) {
47 if (is_empty()) {
48 // If the tree is empty, insert the new node.
49 root_ = new(allocator_) Node(key, Config::NoValue());
50 } else {
51 // Splay on the key to move the last node on the search path
52 // for the key to the root of the tree.
53 Splay(key);
54 // Ignore repeated insertions with the same key.
55 int cmp = Config::Compare(key, root_->key_);
56 if (cmp == 0) {
57 locator->bind(root_);
58 return false;
59 }
60 // Insert the new node.
61 Node* node = new(allocator_) Node(key, Config::NoValue());
62 InsertInternal(cmp, node);
63 }
64 locator->bind(root_);
65 return true;
66 }
67
68
69 template<typename Config, class Allocator>
InsertInternal(int cmp,Node * node)70 void SplayTree<Config, Allocator>::InsertInternal(int cmp, Node* node) {
71 if (cmp > 0) {
72 node->left_ = root_;
73 node->right_ = root_->right_;
74 root_->right_ = NULL;
75 } else {
76 node->right_ = root_;
77 node->left_ = root_->left_;
78 root_->left_ = NULL;
79 }
80 root_ = node;
81 }
82
83
84 template<typename Config, class Allocator>
FindInternal(const Key & key)85 bool SplayTree<Config, Allocator>::FindInternal(const Key& key) {
86 if (is_empty())
87 return false;
88 Splay(key);
89 return Config::Compare(key, root_->key_) == 0;
90 }
91
92
93 template<typename Config, class Allocator>
Contains(const Key & key)94 bool SplayTree<Config, Allocator>::Contains(const Key& key) {
95 return FindInternal(key);
96 }
97
98
99 template<typename Config, class Allocator>
Find(const Key & key,Locator * locator)100 bool SplayTree<Config, Allocator>::Find(const Key& key, Locator* locator) {
101 if (FindInternal(key)) {
102 locator->bind(root_);
103 return true;
104 } else {
105 return false;
106 }
107 }
108
109
110 template<typename Config, class Allocator>
FindGreatestLessThan(const Key & key,Locator * locator)111 bool SplayTree<Config, Allocator>::FindGreatestLessThan(const Key& key,
112 Locator* locator) {
113 if (is_empty())
114 return false;
115 // Splay on the key to move the node with the given key or the last
116 // node on the search path to the top of the tree.
117 Splay(key);
118 // Now the result is either the root node or the greatest node in
119 // the left subtree.
120 int cmp = Config::Compare(root_->key_, key);
121 if (cmp <= 0) {
122 locator->bind(root_);
123 return true;
124 } else {
125 Node* temp = root_;
126 root_ = root_->left_;
127 bool result = FindGreatest(locator);
128 root_ = temp;
129 return result;
130 }
131 }
132
133
134 template<typename Config, class Allocator>
FindLeastGreaterThan(const Key & key,Locator * locator)135 bool SplayTree<Config, Allocator>::FindLeastGreaterThan(const Key& key,
136 Locator* locator) {
137 if (is_empty())
138 return false;
139 // Splay on the key to move the node with the given key or the last
140 // node on the search path to the top of the tree.
141 Splay(key);
142 // Now the result is either the root node or the least node in
143 // the right subtree.
144 int cmp = Config::Compare(root_->key_, key);
145 if (cmp >= 0) {
146 locator->bind(root_);
147 return true;
148 } else {
149 Node* temp = root_;
150 root_ = root_->right_;
151 bool result = FindLeast(locator);
152 root_ = temp;
153 return result;
154 }
155 }
156
157
158 template<typename Config, class Allocator>
FindGreatest(Locator * locator)159 bool SplayTree<Config, Allocator>::FindGreatest(Locator* locator) {
160 if (is_empty())
161 return false;
162 Node* current = root_;
163 while (current->right_ != NULL)
164 current = current->right_;
165 locator->bind(current);
166 return true;
167 }
168
169
170 template<typename Config, class Allocator>
FindLeast(Locator * locator)171 bool SplayTree<Config, Allocator>::FindLeast(Locator* locator) {
172 if (is_empty())
173 return false;
174 Node* current = root_;
175 while (current->left_ != NULL)
176 current = current->left_;
177 locator->bind(current);
178 return true;
179 }
180
181
182 template<typename Config, class Allocator>
Move(const Key & old_key,const Key & new_key)183 bool SplayTree<Config, Allocator>::Move(const Key& old_key,
184 const Key& new_key) {
185 if (!FindInternal(old_key))
186 return false;
187 Node* node_to_move = root_;
188 RemoveRootNode(old_key);
189 Splay(new_key);
190 int cmp = Config::Compare(new_key, root_->key_);
191 if (cmp == 0) {
192 // A node with the target key already exists.
193 delete node_to_move;
194 return false;
195 }
196 node_to_move->key_ = new_key;
197 InsertInternal(cmp, node_to_move);
198 return true;
199 }
200
201
202 template<typename Config, class Allocator>
Remove(const Key & key)203 bool SplayTree<Config, Allocator>::Remove(const Key& key) {
204 if (!FindInternal(key))
205 return false;
206 Node* node_to_remove = root_;
207 RemoveRootNode(key);
208 delete node_to_remove;
209 return true;
210 }
211
212
213 template<typename Config, class Allocator>
RemoveRootNode(const Key & key)214 void SplayTree<Config, Allocator>::RemoveRootNode(const Key& key) {
215 if (root_->left_ == NULL) {
216 // No left child, so the new tree is just the right child.
217 root_ = root_->right_;
218 } else {
219 // Left child exists.
220 Node* right = root_->right_;
221 // Make the original left child the new root.
222 root_ = root_->left_;
223 // Splay to make sure that the new root has an empty right child.
224 Splay(key);
225 // Insert the original right child as the right child of the new
226 // root.
227 root_->right_ = right;
228 }
229 }
230
231
232 template<typename Config, class Allocator>
Splay(const Key & key)233 void SplayTree<Config, Allocator>::Splay(const Key& key) {
234 if (is_empty())
235 return;
236 Node dummy_node(Config::kNoKey, Config::NoValue());
237 // Create a dummy node. The use of the dummy node is a bit
238 // counter-intuitive: The right child of the dummy node will hold
239 // the L tree of the algorithm. The left child of the dummy node
240 // will hold the R tree of the algorithm. Using a dummy node, left
241 // and right will always be nodes and we avoid special cases.
242 Node* dummy = &dummy_node;
243 Node* left = dummy;
244 Node* right = dummy;
245 Node* current = root_;
246 while (true) {
247 int cmp = Config::Compare(key, current->key_);
248 if (cmp < 0) {
249 if (current->left_ == NULL)
250 break;
251 if (Config::Compare(key, current->left_->key_) < 0) {
252 // Rotate right.
253 Node* temp = current->left_;
254 current->left_ = temp->right_;
255 temp->right_ = current;
256 current = temp;
257 if (current->left_ == NULL)
258 break;
259 }
260 // Link right.
261 right->left_ = current;
262 right = current;
263 current = current->left_;
264 } else if (cmp > 0) {
265 if (current->right_ == NULL)
266 break;
267 if (Config::Compare(key, current->right_->key_) > 0) {
268 // Rotate left.
269 Node* temp = current->right_;
270 current->right_ = temp->left_;
271 temp->left_ = current;
272 current = temp;
273 if (current->right_ == NULL)
274 break;
275 }
276 // Link left.
277 left->right_ = current;
278 left = current;
279 current = current->right_;
280 } else {
281 break;
282 }
283 }
284 // Assemble.
285 left->right_ = current->left_;
286 right->left_ = current->right_;
287 current->left_ = dummy->right_;
288 current->right_ = dummy->left_;
289 root_ = current;
290 }
291
292
293 template <typename Config, class Allocator> template <class Callback>
ForEach(Callback * callback)294 void SplayTree<Config, Allocator>::ForEach(Callback* callback) {
295 NodeToPairAdaptor<Callback> callback_adaptor(callback);
296 ForEachNode(&callback_adaptor);
297 }
298
299
300 template <typename Config, class Allocator> template <class Callback>
ForEachNode(Callback * callback)301 void SplayTree<Config, Allocator>::ForEachNode(Callback* callback) {
302 if (root_ == NULL) return;
303 // Pre-allocate some space for tiny trees.
304 List<Node*, Allocator> nodes_to_visit(10, allocator_);
305 nodes_to_visit.Add(root_, allocator_);
306 int pos = 0;
307 while (pos < nodes_to_visit.length()) {
308 Node* node = nodes_to_visit[pos++];
309 if (node->left() != NULL) nodes_to_visit.Add(node->left(), allocator_);
310 if (node->right() != NULL) nodes_to_visit.Add(node->right(), allocator_);
311 callback->Call(node);
312 }
313 }
314
315
316 } } // namespace v8::internal
317
318 #endif // V8_SPLAY_TREE_INL_H_
319