source: mainline/uspace/lib/cpp/include/internal/rbtree.hpp@ 614b07e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 614b07e was 71cde76, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: rbtree::find_parent_for_insertion now tests for equivalence too, so it will always return existing node if there is any that matches key

  • Property mode set to 100644
File size: 13.7 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT 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 OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_RBTREE
30#define LIBCPP_INTERNAL_RBTREE
31
32#include <internal/key_extractors.hpp>
33#include <internal/rbtree_iterators.hpp>
34#include <internal/rbtree_node.hpp>
35#include <internal/rbtree_policies.hpp>
36
37namespace std::aux
38{
39 template<
40 class Value, class Key, class KeyExtractor,
41 class KeyComp, class Alloc, class Size,
42 class Iterator, class ConstIterator,
43 class Policy
44 >
45 class rbtree
46 {
47 public:
48 using value_type = Value;
49 using key_type = Key;
50 using size_type = Size;
51 using allocator_type = Alloc;
52 using key_compare = KeyComp;
53 using key_extract = KeyExtractor;
54
55 using iterator = Iterator;
56 using const_iterator = ConstIterator;
57
58 using reverse_iterator = std::reverse_iterator<iterator>;
59 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
60
61 using node_type = rbtree_node<value_type>;
62
63 rbtree(const key_compare& kcmp = key_compare{})
64 : root_{nullptr}, size_{}, key_compare_{},
65 key_extractor_{}
66 { /* DUMMY BODY */ }
67
68 rbtree(const rbtree& other)
69 : rbtree{other.key_compare_}
70 {
71 for (const auto& x: other)
72 insert(x);
73 }
74
75 rbtree(rbtree&& other)
76 : root_{other.root_}, size_{other.size_},
77 key_compare_{move(other.key_compare_)},
78 key_extractor_{move(other.key_extractor_)}
79 {
80 other.root_ = nullptr;
81 other.size_ = size_type{};
82 }
83
84 rbtree& operator=(const rbtree& other)
85 {
86 auto tmp{other};
87 tmp.swap(*this);
88
89 return *this;
90 }
91
92 rbtree& operator=(rbtree&& other)
93 {
94 rbtree tmp{move(other)};
95 tmp.swap(*this);
96
97 return *this;
98 }
99
100 bool empty() const noexcept
101 {
102 return size_;
103 }
104
105 size_type size() const noexcept
106 {
107 return size_;
108 }
109
110 size_type max_size(allocator_type& alloc)
111 {
112 return allocator_traits<allocator_type>::max_size(alloc);
113 }
114
115 iterator begin()
116 {
117 return iterator{find_smallest_(), false};
118 }
119
120 const_iterator begin() const
121 {
122 return cbegin();
123 }
124
125 iterator end()
126 {
127 return iterator{find_largest_(), true};
128 }
129
130 const_iterator end() const
131 {
132 return cend();
133 }
134
135 reverse_iterator rbegin()
136 {
137 return make_reverse_iterator(end());
138 }
139
140 const_reverse_iterator rbegin() const
141 {
142 return make_reverse_iterator(cend());
143 }
144
145 reverse_iterator rend()
146 {
147 return make_reverse_iterator(begin());
148 }
149
150 const_reverse_iterator rend() const
151 {
152 return make_reverse_iterator(cbegin());
153 }
154
155 const_iterator cbegin() const
156 {
157 return const_iterator{find_smallest_(), false};
158 }
159
160 const_iterator cend() const
161 {
162 return const_iterator{find_largest_(), true};
163 }
164
165 const_reverse_iterator crbegin() const
166 {
167 return make_reverse_iterator(cend());
168 }
169
170 const_reverse_iterator crend() const
171 {
172 return make_reverse_iterator(cbegin());
173 }
174
175 template<class... Args>
176 auto emplace(Args&&... args)
177 {
178 return Policy::emplace(*this, forward<Args>(args)...);
179 }
180
181 auto insert(const value_type& val)
182 {
183 return Policy::insert(*this, val);
184 }
185
186 auto insert(value_type&& val)
187 {
188 return Policy::insert(*this, forward<value_type>(val));
189 }
190
191 size_type erase(const key_type& key)
192 {
193 return Policy::erase(*this, key);
194 }
195
196 iterator erase(const_iterator it)
197 {
198 if (it == cend())
199 return end();
200
201 auto node = const_cast<node_type*>(it.node());
202
203 node = delete_node(node);
204 return iterator{const_cast<node_type*>(node), node == nullptr};
205 }
206
207 void clear() noexcept
208 {
209 if (root_)
210 {
211 delete root_;
212 root_ = nullptr;
213 size_ = size_type{};
214 }
215 }
216
217 void swap(rbtree& other)
218 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
219 noexcept(swap(declval<KeyComp&>(), declval<KeyComp&>())))
220 {
221 std::swap(root_, other.root_);
222 std::swap(size_, other.size_);
223 std::swap(key_compare_, other.key_compare_);
224 std::swap(key_extractor_, other.key_extractor_);
225 }
226
227 key_compare key_comp() const
228 {
229 return key_compare_;
230 }
231
232 iterator find(const key_type& key)
233 {
234 auto node = find_(key);
235 if (node)
236 return iterator{node, false};
237 else
238 return end();
239 }
240
241 const_iterator find(const key_type& key) const
242 {
243 auto node = find_(key);
244 if (node)
245 return const_iterator{node, false};
246 else
247 return end();
248 }
249
250 size_type count(const key_type& key) const
251 {
252 return Policy::count(*this, key);
253 }
254
255 iterator upper_bound(const key_type& key)
256 {
257 return Policy::upper_bound(*this, key);
258 }
259
260 const_iterator upper_bound(const key_type& key) const
261 {
262 return Policy::upper_bound_const(*this, key);
263 }
264
265 iterator lower_bound(const key_type& key)
266 {
267 return Policy::lower_bound(*this, key);
268 }
269
270 const_iterator lower_bound(const key_type& key) const
271 {
272 return Policy::lower_bound_const(*this, key);
273 }
274
275 pair<iterator, iterator> equal_range(const key_type& key)
276 {
277 return Policy::equal_range(*this, key);
278 }
279
280 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
281 {
282 return Policy::equal_range_const(*this, key);
283 }
284
285 bool is_eq_to(const rbtree& other) const
286 {
287 if (size_ != other.size())
288 return false;
289
290 auto it1 = begin();
291 auto it2 = other.begin();
292
293 // TODO: this doesn't compare values :/
294 while (keys_equal(*it1++, *it2++))
295 { /* DUMMY BODY */ }
296
297 return (it1 == end()) && (it2 == other.end());
298 }
299
300 const key_type& get_key(const value_type& val) const
301 {
302 return key_extractor_(val);
303 }
304
305 bool keys_comp(const key_type& key, const value_type& val) const
306 {
307 return key_compare_(key, key_extractor_(val));
308 }
309
310 bool keys_equal(const key_type& k1, const key_type& k2) const
311 {
312 return !key_compare_(k1, k2) && !key_compare_(k2, k1);
313 }
314
315 node_type* find_parent_for_insertion(const key_type& key) const
316 {
317 auto current = root_;
318 auto parent = current;
319
320 while (current)
321 {
322 parent = current;
323 if (key_compare_(key, key_extractor_(current->value)))
324 current = current->left;
325 else if (key_compare_(key_extractor_(current->value), key))
326 current = current->right;
327 else
328 return current;
329 }
330
331 return parent;
332 }
333
334 node_type* delete_node(const node_type* n)
335 {
336 auto node = const_cast<node_type*>(n);
337 if (!node)
338 return nullptr;
339
340 --size_;
341
342 auto succ = node->successor();
343 if (node->left && node->right)
344 {
345 node->swap(succ);
346
347 // Succ has at most one child.
348 delete_node(succ);
349
350 return node;
351 }
352
353 auto child = node->right ? node->right : node->left;
354 if (!child)
355 {
356 // Simply remove the node.
357 // TODO: repair here too?
358 node->unlink();
359 delete node;
360 }
361 else
362 {
363 // Replace with the child.
364 child->parent = node->parent;
365 if (node->is_left_child())
366 child->parent->left = child;
367 else if (node->is_right_child())
368 child->parent->right = child;
369
370 // Repair if needed.
371 repair_after_erase_(node, child);
372 update_root_(child);
373
374 delete node;
375 }
376
377 return succ;
378 }
379
380 void insert_node(node_type* node, node_type* parent)
381 {
382 if (!node)
383 return;
384
385 ++size_;
386 if (!parent)
387 {
388 node->color = rbcolor::black;
389 root_ = node;
390 }
391 else
392 {
393 if (keys_comp(get_key(node->value), parent->value))
394 parent->add_left_child(node);
395 else
396 parent->add_right_child(node);
397
398 repair_after_insert_(node);
399 update_root_(node);
400 }
401 }
402
403 private:
404 node_type* root_;
405 size_type size_;
406 key_compare key_compare_;
407 key_extract key_extractor_;
408
409 node_type* find_(const key_type& key) const
410 {
411 auto current = root_;
412 while (current != nullptr)
413 {
414 if (key_compare_(key, key_extractor_(current->value)))
415 current = current->left;
416 else if (key_compare_(key_extractor_(current->value), key))
417 current = current->right;
418 else
419 return current;
420 }
421
422 return nullptr;
423 }
424
425 node_type* find_smallest_() const
426 {
427 if (root_)
428 return root_->find_smallest();
429 else
430 return nullptr;
431 }
432
433 node_type* find_largest_() const
434 {
435 if (root_)
436 return root_->find_largest();
437 else
438 return nullptr;
439 }
440
441 void update_root_(const node_type* node)
442 {
443 if (!node)
444 return;
445
446 root_ = const_cast<node_type*>(node);
447 while (root_->parent)
448 root_ = root_->parent;
449 }
450
451 void repair_after_insert_(const node_type* node)
452 {
453 // TODO: implement
454 }
455
456 void repair_after_erase_(const node_type* node, const node_type* child)
457 {
458 // TODO: implement
459 }
460
461 friend Policy;
462 };
463}
464
465#endif
Note: See TracBrowser for help on using the repository browser.