source: mainline/uspace/lib/cpp/include/internal/rbtree.hpp@ 27f1bc0

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

cpp: revamped rbtree so that it now stores equivalent keys in a list

  • Property mode set to 100644
File size: 14.2 KB
RevLine 
[4d65515]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,
[73e3791]43 class Policy, class Node
[4d65515]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
[73e3791]55 using iterator = Iterator;
56 using const_iterator = ConstIterator;
[4d65515]57
[be9eb15]58 using reverse_iterator = std::reverse_iterator<iterator>;
59 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
60
[73e3791]61 using node_type = Node;
[4d65515]62
63 rbtree(const key_compare& kcmp = key_compare{})
64 : root_{nullptr}, size_{}, key_compare_{},
65 key_extractor_{}
66 { /* DUMMY BODY */ }
67
[009d78b]68 rbtree(const rbtree& other)
69 : rbtree{other.key_compare_}
70 {
71 for (const auto& x: other)
72 insert(x);
73 }
[be9eb15]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);
[4d65515]88
[be9eb15]89 return *this;
90 }
[4d65515]91
[be9eb15]92 rbtree& operator=(rbtree&& other)
93 {
94 rbtree tmp{move(other)};
95 tmp.swap(*this);
[4d65515]96
[be9eb15]97 return *this;
98 }
[4d65515]99
100 bool empty() const noexcept
101 {
[73e3791]102 return size_ == 0U;
[4d65515]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
[be9eb15]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
[4d65515]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
[be9eb15]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
[4d65515]175 template<class... Args>
[369f5df]176 auto emplace(Args&&... args)
[4d65515]177 {
[369f5df]178 return Policy::emplace(*this, forward<Args>(args)...);
[4d65515]179 }
180
[369f5df]181 auto insert(const value_type& val)
[4d65515]182 {
[369f5df]183 return Policy::insert(*this, val);
[4d65515]184 }
185
[369f5df]186 auto insert(value_type&& val)
[4d65515]187 {
[369f5df]188 return Policy::insert(*this, forward<value_type>(val));
[4d65515]189 }
190
191 size_type erase(const key_type& key)
192 {
[009d78b]193 return Policy::erase(*this, key);
[4d65515]194 }
195
196 iterator erase(const_iterator it)
197 {
[009d78b]198 if (it == cend())
199 return end();
200
201 auto node = const_cast<node_type*>(it.node());
202
[369f5df]203 node = delete_node(node);
[73e3791]204 if (!node)
205 return iterator{find_largest_(), true};
206 else
207 return iterator{const_cast<node_type*>(node), false};
[4d65515]208 }
209
210 void clear() noexcept
211 {
212 if (root_)
213 {
214 delete root_;
215 root_ = nullptr;
216 size_ = size_type{};
217 }
218 }
219
220 void swap(rbtree& other)
221 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
222 noexcept(swap(declval<KeyComp&>(), declval<KeyComp&>())))
223 {
224 std::swap(root_, other.root_);
225 std::swap(size_, other.size_);
226 std::swap(key_compare_, other.key_compare_);
227 std::swap(key_extractor_, other.key_extractor_);
228 }
229
230 key_compare key_comp() const
231 {
232 return key_compare_;
233 }
234
235 iterator find(const key_type& key)
236 {
[be9eb15]237 auto node = find_(key);
238 if (node)
239 return iterator{node, false};
240 else
241 return end();
[4d65515]242 }
243
[be9eb15]244 const_iterator find(const key_type& key) const
[4d65515]245 {
[be9eb15]246 auto node = find_(key);
247 if (node)
248 return const_iterator{node, false};
249 else
250 return end();
[4d65515]251 }
252
253 size_type count(const key_type& key) const
254 {
255 return Policy::count(*this, key);
256 }
257
258 iterator upper_bound(const key_type& key)
259 {
260 return Policy::upper_bound(*this, key);
261 }
262
263 const_iterator upper_bound(const key_type& key) const
264 {
265 return Policy::upper_bound_const(*this, key);
266 }
267
268 iterator lower_bound(const key_type& key)
269 {
270 return Policy::lower_bound(*this, key);
271 }
272
273 const_iterator lower_bound(const key_type& key) const
274 {
275 return Policy::lower_bound_const(*this, key);
276 }
277
278 pair<iterator, iterator> equal_range(const key_type& key)
279 {
280 return Policy::equal_range(*this, key);
281 }
282
283 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
284 {
285 return Policy::equal_range_const(*this, key);
286 }
287
288 bool is_eq_to(const rbtree& other) const
289 {
[009d78b]290 if (size_ != other.size())
291 return false;
292
293 auto it1 = begin();
294 auto it2 = other.begin();
295
[369f5df]296 // TODO: this doesn't compare values :/
[009d78b]297 while (keys_equal(*it1++, *it2++))
298 { /* DUMMY BODY */ }
299
300 return (it1 == end()) && (it2 == other.end());
[4d65515]301 }
302
303 const key_type& get_key(const value_type& val) const
304 {
305 return key_extractor_(val);
306 }
307
308 bool keys_comp(const key_type& key, const value_type& val) const
309 {
310 return key_compare_(key, key_extractor_(val));
311 }
312
[009d78b]313 bool keys_equal(const key_type& k1, const key_type& k2) const
314 {
315 return !key_compare_(k1, k2) && !key_compare_(k2, k1);
316 }
317
[48f09f2f]318 node_type* find_parent_for_insertion(const key_type& key) const
[4d65515]319 {
320 auto current = root_;
321 auto parent = current;
322
323 while (current)
324 {
325 parent = current;
[48f09f2f]326 if (key_compare_(key, key_extractor_(current->value)))
[73e3791]327 current = current->left();
[71cde76]328 else if (key_compare_(key_extractor_(current->value), key))
[73e3791]329 current = current->right();
[71cde76]330 else
331 return current;
[4d65515]332 }
333
334 return parent;
335 }
336
[369f5df]337 node_type* delete_node(const node_type* n)
[009d78b]338 {
[369f5df]339 auto node = const_cast<node_type*>(n);
[009d78b]340 if (!node)
[369f5df]341 return nullptr;
[73e3791]342 if (auto tmp = node->get_node_for_deletion(); tmp != nullptr)
343 {
344 /**
345 * This will kick in multi containers,
346 * we popped one node from a list of nodes
347 * with equivalent keys and we can delete it
348 * and return the original as it is still
349 * in place.
350 */
351 delete tmp;
352
353 return node;
354 }
[009d78b]355
356 --size_;
357
[73e3791]358 if (node == root_)
[009d78b]359 {
[73e3791]360 delete node;
361 root_ = nullptr;
[009d78b]362
[73e3791]363 return nullptr;
364 }
[009d78b]365
[73e3791]366 auto succ = node->successor();
367 if (node->left() && node->right())
368 {
369 node->swap(succ);
370 if (succ && !succ->parent())
371 root_ = succ;
372
373 // Node now has at most one child.
374 // Also: If succ was nullptr, the swap
375 // didn't do anything and we can
376 // safely delete node.
377 return delete_node(node);
[009d78b]378 }
379
[73e3791]380 auto child = node->right() ? node->right() : node->left();
[009d78b]381 if (!child)
382 {
383 // Simply remove the node.
[369f5df]384 // TODO: repair here too?
[009d78b]385 node->unlink();
386 delete node;
387 }
388 else
389 {
390 // Replace with the child.
[73e3791]391 child->parent(node->parent());
[009d78b]392 if (node->is_left_child())
[73e3791]393 child->parent()->left(child);
[369f5df]394 else if (node->is_right_child())
[73e3791]395 child->parent()->right(child);
[009d78b]396
397 // Repair if needed.
398 repair_after_erase_(node, child);
399 update_root_(child);
[369f5df]400
401 delete node;
[009d78b]402 }
[369f5df]403
404 return succ;
[009d78b]405 }
406
[7644d6e]407 void insert_node(node_type* node, node_type* parent)
408 {
[73e3791]409 Policy::insert(*this, node, parent);
[7644d6e]410 }
411
[4d65515]412 private:
413 node_type* root_;
414 size_type size_;
415 key_compare key_compare_;
416 key_extract key_extractor_;
417
[be9eb15]418 node_type* find_(const key_type& key) const
419 {
420 auto current = root_;
421 while (current != nullptr)
422 {
423 if (key_compare_(key, key_extractor_(current->value)))
[73e3791]424 current = current->left();
[009d78b]425 else if (key_compare_(key_extractor_(current->value), key))
[73e3791]426 current = current->right();
[009d78b]427 else
428 return current;
[be9eb15]429 }
430
431 return nullptr;
432 }
433
[4d65515]434 node_type* find_smallest_() const
435 {
436 if (root_)
437 return root_->find_smallest();
438 else
439 return nullptr;
440 }
441
442 node_type* find_largest_() const
443 {
444 if (root_)
445 return root_->find_largest();
446 else
447 return nullptr;
448 }
449
[4f080f2a]450 void update_root_(const node_type* node)
[4d65515]451 {
452 if (!node)
453 return;
454
[4f080f2a]455 root_ = const_cast<node_type*>(node);
[73e3791]456 while (root_->parent())
457 root_ = root_->parent();
[4d65515]458 }
459
[4f080f2a]460 void repair_after_insert_(const node_type* node)
[4d65515]461 {
462 // TODO: implement
463 }
464
[4f080f2a]465 void repair_after_erase_(const node_type* node, const node_type* child)
[be9eb15]466 {
467 // TODO: implement
468 }
469
[4d65515]470 friend Policy;
471 };
472}
473
474#endif
Note: See TracBrowser for help on using the repository browser.