source: mainline/uspace/lib/cpp/include/internal/rbtree.hpp@ 369f5df

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

cpp: moved insert logic to policies, fixed delete

  • Property mode set to 100644
File size: 13.1 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,
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
[be9eb15]58 using reverse_iterator = std::reverse_iterator<iterator>;
59 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
60
[4d65515]61 using node_type = rbtree_node<value_type>;
62
[009d78b]63 // TODO: make find/bounds etc templated with key type
64 // for transparent comparators and leave their management for the
65 // outer containers
66
[4d65515]67 rbtree(const key_compare& kcmp = key_compare{})
68 : root_{nullptr}, size_{}, key_compare_{},
69 key_extractor_{}
70 { /* DUMMY BODY */ }
71
[009d78b]72 rbtree(const rbtree& other)
73 : rbtree{other.key_compare_}
74 {
75 for (const auto& x: other)
76 insert(x);
77 }
[be9eb15]78
79 rbtree(rbtree&& other)
80 : root_{other.root_}, size_{other.size_},
81 key_compare_{move(other.key_compare_)},
82 key_extractor_{move(other.key_extractor_)}
83 {
84 other.root_ = nullptr;
85 other.size_ = size_type{};
86 }
87
88 rbtree& operator=(const rbtree& other)
89 {
90 auto tmp{other};
91 tmp.swap(*this);
[4d65515]92
[be9eb15]93 return *this;
94 }
[4d65515]95
[be9eb15]96 rbtree& operator=(rbtree&& other)
97 {
98 rbtree tmp{move(other)};
99 tmp.swap(*this);
[4d65515]100
[be9eb15]101 return *this;
102 }
[4d65515]103
104 bool empty() const noexcept
105 {
106 return size_;
107 }
108
109 size_type size() const noexcept
110 {
111 return size_;
112 }
113
114 size_type max_size(allocator_type& alloc)
115 {
116 return allocator_traits<allocator_type>::max_size(alloc);
117 }
118
119 iterator begin()
120 {
121 return iterator{find_smallest_(), false};
122 }
123
124 const_iterator begin() const
125 {
126 return cbegin();
127 }
128
129 iterator end()
130 {
131 return iterator{find_largest_(), true};
132 }
133
134 const_iterator end() const
135 {
136 return cend();
137 }
138
[be9eb15]139 reverse_iterator rbegin()
140 {
141 return make_reverse_iterator(end());
142 }
143
144 const_reverse_iterator rbegin() const
145 {
146 return make_reverse_iterator(cend());
147 }
148
149 reverse_iterator rend()
150 {
151 return make_reverse_iterator(begin());
152 }
153
154 const_reverse_iterator rend() const
155 {
156 return make_reverse_iterator(cbegin());
157 }
158
[4d65515]159 const_iterator cbegin() const
160 {
161 return const_iterator{find_smallest_(), false};
162 }
163
164 const_iterator cend() const
165 {
166 return const_iterator{find_largest_(), true};
167 }
168
[be9eb15]169 const_reverse_iterator crbegin() const
170 {
171 return make_reverse_iterator(cend());
172 }
173
174 const_reverse_iterator crend() const
175 {
176 return make_reverse_iterator(cbegin());
177 }
178
[4d65515]179 template<class... Args>
[369f5df]180 auto emplace(Args&&... args)
[4d65515]181 {
[369f5df]182 return Policy::emplace(*this, forward<Args>(args)...);
[4d65515]183 }
184
[369f5df]185 auto insert(const value_type& val)
[4d65515]186 {
[369f5df]187 return Policy::insert(*this, val);
[4d65515]188 }
189
[369f5df]190 auto insert(value_type&& val)
[4d65515]191 {
[369f5df]192 return Policy::insert(*this, forward<value_type>(val));
[4d65515]193 }
194
195 size_type erase(const key_type& key)
196 {
[009d78b]197 return Policy::erase(*this, key);
[4d65515]198 }
199
200 iterator erase(const_iterator it)
201 {
[009d78b]202 if (it == cend())
203 return end();
204
205 auto node = const_cast<node_type*>(it.node());
206
[369f5df]207 node = delete_node(node);
208 return iterator{const_cast<node_type*>(node), node == nullptr};
[4d65515]209 }
210
211 void clear() noexcept
212 {
213 if (root_)
214 {
215 delete root_;
216 root_ = nullptr;
217 size_ = size_type{};
218 }
219 }
220
221 void swap(rbtree& other)
222 noexcept(allocator_traits<allocator_type>::is_always_equal::value &&
223 noexcept(swap(declval<KeyComp&>(), declval<KeyComp&>())))
224 {
225 std::swap(root_, other.root_);
226 std::swap(size_, other.size_);
227 std::swap(key_compare_, other.key_compare_);
228 std::swap(key_extractor_, other.key_extractor_);
229 }
230
231 key_compare key_comp() const
232 {
233 return key_compare_;
234 }
235
236 iterator find(const key_type& key)
237 {
[be9eb15]238 auto node = find_(key);
239 if (node)
240 return iterator{node, false};
241 else
242 return end();
[4d65515]243 }
244
[be9eb15]245 const_iterator find(const key_type& key) const
[4d65515]246 {
[be9eb15]247 auto node = find_(key);
248 if (node)
249 return const_iterator{node, false};
250 else
251 return end();
[4d65515]252 }
253
254 size_type count(const key_type& key) const
255 {
256 return Policy::count(*this, key);
257 }
258
259 iterator upper_bound(const key_type& key)
260 {
261 return Policy::upper_bound(*this, key);
262 }
263
264 const_iterator upper_bound(const key_type& key) const
265 {
266 return Policy::upper_bound_const(*this, key);
267 }
268
269 iterator lower_bound(const key_type& key)
270 {
271 return Policy::lower_bound(*this, key);
272 }
273
274 const_iterator lower_bound(const key_type& key) const
275 {
276 return Policy::lower_bound_const(*this, key);
277 }
278
279 pair<iterator, iterator> equal_range(const key_type& key)
280 {
281 return Policy::equal_range(*this, key);
282 }
283
284 pair<const_iterator, const_iterator> equal_range(const key_type& key) const
285 {
286 return Policy::equal_range_const(*this, key);
287 }
288
289 bool is_eq_to(const rbtree& other) const
290 {
[009d78b]291 if (size_ != other.size())
292 return false;
293
294 auto it1 = begin();
295 auto it2 = other.begin();
296
[369f5df]297 // TODO: this doesn't compare values :/
[009d78b]298 while (keys_equal(*it1++, *it2++))
299 { /* DUMMY BODY */ }
300
301 return (it1 == end()) && (it2 == other.end());
[4d65515]302 }
303
304 const key_type& get_key(const value_type& val) const
305 {
306 return key_extractor_(val);
307 }
308
309 bool keys_comp(const key_type& key, const value_type& val) const
310 {
311 return key_compare_(key, key_extractor_(val));
312 }
313
[009d78b]314 bool keys_equal(const key_type& k1, const key_type& k2) const
315 {
316 return !key_compare_(k1, k2) && !key_compare_(k2, k1);
317 }
318
[4d65515]319 node_type* find_parent_for_insertion(const value_type& val) const
320 {
321 auto current = root_;
322 auto parent = current;
323
324 while (current)
325 {
326 parent = current;
327 if (key_compare_(key_extractor_(val), key_extractor_(current->value)))
328 current = current->left;
329 else
330 current = current->right;
331 }
332
333 return parent;
334 }
335
[369f5df]336 node_type* delete_node(const node_type* n)
[009d78b]337 {
[369f5df]338 auto node = const_cast<node_type*>(n);
[009d78b]339 if (!node)
[369f5df]340 return nullptr;
[009d78b]341
342 --size_;
343
[369f5df]344 auto succ = node->successor();
[009d78b]345 if (node->left && node->right)
346 {
[369f5df]347 node->swap(succ);
[009d78b]348
[369f5df]349 // Succ has at most one child.
350 delete_node(succ);
[009d78b]351
[369f5df]352 return node;
[009d78b]353 }
354
355 auto child = node->right ? node->right : node->left;
356 if (!child)
357 {
358 // Simply remove the node.
[369f5df]359 // TODO: repair here too?
[009d78b]360 node->unlink();
361 delete node;
362 }
363 else
364 {
365 // Replace with the child.
366 child->parent = node->parent;
367 if (node->is_left_child())
368 child->parent->left = child;
[369f5df]369 else if (node->is_right_child())
[009d78b]370 child->parent->right = child;
371
372 // Repair if needed.
373 repair_after_erase_(node, child);
374 update_root_(child);
[369f5df]375
376 delete node;
[009d78b]377 }
[369f5df]378
379 return succ;
[009d78b]380 }
381
[4d65515]382 private:
383 node_type* root_;
384 size_type size_;
385 key_compare key_compare_;
386 key_extract key_extractor_;
387
[be9eb15]388 node_type* find_(const key_type& key) const
389 {
390 auto current = root_;
391 while (current != nullptr)
392 {
393 if (key_compare_(key, key_extractor_(current->value)))
394 current = current->left;
[009d78b]395 else if (key_compare_(key_extractor_(current->value), key))
[be9eb15]396 current = current->right;
[009d78b]397 else
398 return current;
[be9eb15]399 }
400
401 return nullptr;
402 }
403
[4d65515]404 node_type* find_smallest_() const
405 {
406 if (root_)
407 return root_->find_smallest();
408 else
409 return nullptr;
410 }
411
412 node_type* find_largest_() const
413 {
414 if (root_)
415 return root_->find_largest();
416 else
417 return nullptr;
418 }
419
[4f080f2a]420 void update_root_(const node_type* node)
[4d65515]421 {
422 if (!node)
423 return;
424
[4f080f2a]425 root_ = const_cast<node_type*>(node);
[4d65515]426 while (root_->parent)
427 root_ = root_->parent;
428 }
429
[4f080f2a]430 void repair_after_insert_(const node_type* node)
[4d65515]431 {
432 // TODO: implement
433 }
434
[4f080f2a]435 void repair_after_erase_(const node_type* node, const node_type* child)
[be9eb15]436 {
437 // TODO: implement
438 }
439
[4d65515]440 friend Policy;
441 };
442}
443
444#endif
Note: See TracBrowser for help on using the repository browser.