di 0.1.0
Loading...
Searching...
No Matches
rb_tree.h
Go to the documentation of this file.
1#pragma once
2
12#include "di/function/compare.h"
13#include "di/meta/compare.h"
14#include "di/meta/core.h"
15#include "di/util/create.h"
16#include "di/util/exchange.h"
18
19namespace di::container {
20namespace detail {
21 template<typename Value, typename Comp>
22 struct RBTreeValidForLookup {
23 template<typename U>
24 struct Type {
25 constexpr static bool value = concepts::StrictWeakOrder<Comp&, Value, U>;
26 };
27 };
28}
29
35template<typename Value, typename Comp, typename Tag, typename Interface, bool is_multi, typename Self = Void>
36class RBTree : public Interface {
37private:
38 using Node = RBTreeNode<Tag>;
39 using Iterator = RBTreeIterator<Value, Tag>;
40 using ConstIterator = container::ConstIteratorImpl<Iterator>;
41
42 using ConcreteNode = decltype(Tag::node_type(in_place_type<Value>));
43 using ConcreteSelf = meta::Conditional<concepts::SameAs<Void, Self>, RBTree, Self>;
44
45 constexpr auto down_cast_self() -> decltype(auto) {
46 if constexpr (concepts::SameAs<Void, Self>) {
47 return *this;
48 } else {
49 return static_cast<Self&>(*this);
50 }
51 }
52
53public:
54 RBTree() = default;
55 RBTree(RBTree const&) = delete;
56 auto operator=(RBTree const&) -> RBTree& = delete;
57
58 constexpr explicit RBTree(Comp comparator) : m_comparator(comparator) {}
59
60 constexpr RBTree(RBTree&& other)
61 : m_root(util::exchange(other.m_root, nullptr))
62 , m_minimum(util::exchange(other.m_minimum, nullptr))
63 , m_maximum(util::exchange(other.m_maximum, nullptr))
64 , m_size(util::exchange(other.m_size, 0))
65 , m_comparator(other.m_comparator) {}
66
67 constexpr auto operator=(RBTree&& other) -> RBTree& {
68 this->clear();
69 m_root = util::exchange(other.m_root, nullptr);
70 m_minimum = util::exchange(other.m_minimum, nullptr);
71 m_maximum = util::exchange(other.m_maximum, nullptr);
72 m_size = util::exchange(other.m_size, 0);
73 m_comparator = other.m_comparator;
74 return *this;
75 }
76
77 constexpr ~RBTree() { this->clear(); }
78
79 constexpr auto size() const -> usize { return m_size; }
80 constexpr auto empty() const -> bool { return !m_root; }
81
82 constexpr auto begin() -> Iterator { return unconst_iterator(util::as_const(*this).begin()); }
83 constexpr auto begin() const -> ConstIterator { return Iterator(m_minimum, !m_root); }
84 constexpr auto end() -> Iterator { return unconst_iterator(util::as_const(*this).end()); }
85 constexpr auto end() const -> ConstIterator { return Iterator(m_maximum, true); }
86
87 constexpr auto unconst_iterator(ConstIterator it) -> Iterator { return it.base(); }
88
89 constexpr auto insert_node(Node& node) {
90 auto position = this->insert_position(node_value(node));
91 if constexpr (!is_multi) {
92 if (position.parent && this->compare(node_value(*position.parent), node_value(node)) == 0) {
93 return Tuple(Iterator(position.parent, false), false);
94 }
95 }
96
97 this->insert_node(position, node);
98 if constexpr (!is_multi) {
99 return Tuple(Iterator(util::addressof(node), false), true);
100 } else {
101 return Iterator(util::addressof(node), false);
102 }
103 }
104
105 constexpr auto insert_node(ConstIterator, Node& node) {
106 auto position = this->insert_position(node_value(node));
107 if constexpr (!is_multi) {
108 if (position.parent && this->compare(node_value(*position.parent), node_value(node)) == 0) {
109 return Iterator(position.parent, false);
110 }
111 }
112
113 this->insert_node(position, node);
114 return Iterator(util::addressof(node), false);
115 }
116
117 constexpr auto erase_impl(ConstIterator position) -> Iterator {
118 DI_ASSERT(position != end());
119
120 auto result = container::next(position).base();
121 auto& node = position.base().node();
122 erase_node(node);
123
124 Tag::did_remove(down_cast_self(), static_cast<ConcreteNode&>(node));
125
126 return result;
127 }
128
129 template<typename U>
131 constexpr auto equal_range_impl(U&& needle) const {
132 return View<ConstIterator> { lower_bound_impl(needle), upper_bound_impl(needle) };
133 }
134
135 template<typename U>
137 constexpr auto lower_bound_impl(U&& needle) const -> ConstIterator {
138 Node* result = nullptr;
139 for (auto* node = m_root; node;) {
140 if (compare(node_value(*node), needle) < 0) {
141 node = node->right;
142 } else {
143 result = node;
144 node = node->left;
145 }
146 }
147 return result ? Iterator(result, false) : end();
148 }
149
150 template<typename U>
152 constexpr auto upper_bound_impl(U&& needle) const -> ConstIterator {
153 Node* result = nullptr;
154 for (auto* node = m_root; node;) {
155 if (compare(node_value(*node), needle) <= 0) {
156 node = node->right;
157 } else {
158 result = node;
159 node = node->left;
160 }
161 }
162 return result ? Iterator(result, false) : end();
163 }
164
165 template<typename U>
167 constexpr auto find_impl(U&& needle) const -> ConstIterator {
168 for (auto* node = m_root; node;) {
169 auto result = compare(needle, node_value(*node));
170 if (result == 0) {
171 return Iterator(node, false);
172 }
173 if (result < 0) {
174 node = node->left;
175 } else {
176 node = node->right;
177 }
178 }
179 return end();
180 }
181
182 constexpr void merge_impl(RBTree&& other) {
183 if (!m_root) {
184 *this = util::move(other);
185 return;
186 }
187
188 auto it = other.begin();
189 auto last = other.end();
190 while (it != last) {
191 auto save = it++;
192
193 auto position = insert_position(*save);
194 if (!is_multi && position.parent && compare(node_value(*position.parent), *save) == 0) {
195 it = other.erase_impl(save);
196 } else {
197 other.erase_node(save.node());
198 do_insert_node(position, save.node());
199 }
200 }
201 }
202
203protected:
204 constexpr auto node_value(Node& node) const -> Value& {
205 return Tag::down_cast(in_place_type<Value>, static_cast<ConcreteNode&>(node));
206 }
207 constexpr auto node_value(Node const& node) const -> Value const& {
208 return const_cast<RBTree&>(*this).node_value(const_cast<Node&>(node));
209 }
210
211 // Compute the color of a node, defaulting to Black.
212 constexpr auto node_color(Node* node) const -> Node::Color {
213 if (!node) {
214 return Node::Color::Black;
215 }
216 return node->color;
217 }
218
219 // Swaps the passed node with its right child in the tree.
220 constexpr void rotate_left(Node& x) {
221 DI_ASSERT(x.right);
222
223 auto& y = *x.right;
224 x.right = y.left;
225 if (y.left != nullptr) {
226 y.left->parent = &x;
227 }
228 y.parent = x.parent;
229 if (x.parent == nullptr) {
230 m_root = &y;
231 } else if (x.is_left_child()) {
232 x.parent->left = &y;
233 } else {
234 x.parent->right = &y;
235 }
236 y.left = &x;
237 x.parent = &y;
238 }
239
240 // Swaps the passed node with its left child in the tree.
241 constexpr void rotate_right(Node& y) {
242 DI_ASSERT(y.left);
243
244 auto& x = *y.left;
245 y.left = x.right;
246 if (y.left != nullptr) {
247 y.left->parent = &y;
248 }
249 x.parent = y.parent;
250 if (y.parent == nullptr) {
251 m_root = &x;
252 } else if (y.is_left_child()) {
253 y.parent->left = &x;
254 } else {
255 y.parent->right = &x;
256 }
257 x.right = &y;
258 y.parent = &x;
259 }
260
262 Node* parent { nullptr };
263 bool left { true };
264 };
265
266 template<typename U>
268 constexpr auto insert_position(U&& needle) const -> InsertPosition {
269 // Find the parent node to insert under.
270 Node* y = nullptr;
271 auto* x = m_root;
272 while (x != nullptr) {
273 y = x;
274
275 // Early return to the caller if we're inserting a duplicate, making
276 // sure to provide the caller a node that is equal to needle.
277 if constexpr (!is_multi) {
278 if (compare(needle, node_value(*x)) == 0) {
279 return InsertPosition { x, false };
280 }
281 }
282
283 if (compare(needle, node_value(*x)) < 0) {
284 x = x->left;
285 } else {
286 x = x->right;
287 }
288 }
289
290 if (!y) {
291 return InsertPosition {};
292 }
293 if (compare(needle, node_value(*y)) < 0) {
294 return InsertPosition { y, true };
295 }
296 return InsertPosition { y, false };
297 }
298
299 constexpr void insert_node(InsertPosition position, Node& to_insert) {
300 do_insert_node(position, to_insert);
301
302 Tag::did_insert(down_cast_self(), static_cast<ConcreteNode&>(to_insert));
303 }
304
305 constexpr void do_insert_node(InsertPosition position, Node& to_insert) {
306 // Step 1: check if inserting the first node.
307 if (position.parent == nullptr) {
308 m_root = m_minimum = m_maximum = &to_insert;
309 m_size = 1;
310 return;
311 }
312
313 // Step 2: actually insert the node.
314 auto& parent = *position.parent;
315 to_insert.parent = &parent;
316 if (position.left) {
317 parent.left = &to_insert;
318 } else {
319 parent.right = &to_insert;
320 }
321
322 // Step 3: maintain the Red-Black properties.
323 do_insert_rebalancing(&to_insert);
324
325 // Step 4: update cached values.
326 m_size++;
327 if (m_minimum->left) {
328 m_minimum = &to_insert;
329 }
330 if (m_maximum->right) {
331 m_maximum = &to_insert;
332 }
333 }
334
335 constexpr void do_insert_rebalancing(Node* node) {
336 DI_ASSERT(node);
337 while (node->parent && node->parent->parent && node->parent->color == Node::Color::Red) {
338 auto* grand_parent = node->parent->parent;
339 if (node->parent->is_right_child()) {
340 auto* uncle = grand_parent->left;
341 if (node_color(uncle) == Node::Color::Red) {
343 uncle->color = Node::Color::Black;
344 grand_parent->color = Node::Color::Red;
345 node = grand_parent;
346 } else {
347 if (node->is_left_child()) {
348 node = node->parent;
349 rotate_right(*node);
350 }
352 grand_parent->color = Node::Color::Red;
353 rotate_left(*grand_parent);
354 }
355 } else {
356 auto* uncle = grand_parent->right;
357 if (node_color(uncle) == Node::Color::Red) {
359 uncle->color = Node::Color::Black;
360 grand_parent->color = Node::Color::Red;
361 node = grand_parent;
362 } else {
363 if (node->is_right_child()) {
364 node = node->parent;
365 rotate_left(*node);
366 }
368 grand_parent->color = Node::Color::Red;
369 rotate_right(*grand_parent);
370 }
371 }
372 }
373 m_root->color = Node::Color::Black;
374 }
375
376 constexpr void transplant(Node& u, Node* v) {
377 if (u.parent == nullptr) {
378 m_root = v;
379 } else if (u.is_left_child()) {
380 u.parent->left = v;
381 } else {
382 u.parent->right = v;
383 }
384 if (v) {
385 v->parent = u.parent;
386 }
387 }
388
389 constexpr void erase_node(Node& to_delete) {
390 Node* x = nullptr;
391 auto* y = &to_delete;
392 auto y_color = y->color;
393
394 // Step 1: Update cached values.
395 m_size--;
396 if (m_minimum == &to_delete) {
397 m_minimum = to_delete.successor();
398 }
399 if (m_maximum == &to_delete) {
400 m_maximum = to_delete.predecessor();
401 }
402
403 // Step 2: actually remove the node from the tree.
404 if (to_delete.left == nullptr) {
405 // Case 1: there is no left child, so promote the right child.
406 x = to_delete.right;
407 transplant(to_delete, to_delete.right);
408 } else if (to_delete.right == nullptr) {
409 // Case 2: there is no right child, so promote the left child.
410 x = to_delete.left;
411 transplant(to_delete, to_delete.left);
412 } else {
413 // Case 3: promote this node's successor
414 y = to_delete.successor();
415 y_color = y->color;
416 x = y->right;
417
418 if (y->parent == &to_delete) {
419 if (x) {
420 x->parent = y;
421 }
422 } else {
423 transplant(*y, y->right);
424 y->right = to_delete.right;
425 y->right->parent = y;
426 }
427 transplant(to_delete, y);
428 y->left = to_delete.left;
429 y->left->parent = y;
430 y->color = to_delete.color;
431 }
432
433 // Step 3: maintain the Red-Black properties.
434 if (y_color == Node::Color::Black && x) {
436 }
437 }
438
439 constexpr void do_erase_rebalancing(Node* x) {
440 DI_ASSERT(x);
441 while (x != m_root && x->color == Node::Color::Black) {
442 if (x->is_left_child()) {
443 auto* w = x->parent->right;
444 // FIXME: this NULL check appears to be necessary, but is not part of the reference implementation.
445 if (!w) {
446 break;
447 }
448
449 if (w->color == Node::Color::Red) {
452 rotate_left(*x->parent);
453 }
454 if (node_color(w->left) == Node::Color::Black && node_color(w->right) == Node::Color::Black) {
455 w->color = Node::Color::Red;
456 x = x->parent;
457 } else {
458 if (node_color(w->right) == Node::Color::Black) {
459 w->left->color = Node::Color::Black;
460 w->color = Node::Color::Red;
461 rotate_right(*w);
462 w = x->parent->right;
463 }
464 w->color = x->parent->color;
466 if (w->right) {
467 w->right->color = Node::Color::Black;
468 }
469 rotate_left(*x->parent);
470 break;
471 }
472 } else {
473 auto* w = x->parent->left;
474 // FIXME: this NULL check appears to be necessary, but is not part of the reference implementation.
475 if (!w) {
476 break;
477 }
478
479 if (w->color == Node::Color::Red) {
482 rotate_right(*x->parent);
483 }
484 if (node_color(w->right) == Node::Color::Black && node_color(w->left) == Node::Color::Black) {
485 w->color = Node::Color::Red;
486 x = x->parent;
487 } else {
488 if (node_color(w->left) == Node::Color::Black) {
489 w->right->color = Node::Color::Black;
490 w->color = Node::Color::Red;
491 rotate_left(*w);
492 w = x->parent->left;
493 }
494 w->color = x->parent->color;
496 if (w->left) {
497 w->left->color = Node::Color::Black;
498 }
499 rotate_right(*x->parent);
500 break;
501 }
502 }
503 }
505 }
506
507 constexpr auto compare(Node const& a, Node const& b) const { return compare(node_value(a), node_value(b)); }
508
509 template<typename T, typename U>
511 constexpr auto compare(T const& a, U&& b) const {
512 return function::invoke(m_comparator, a, b);
513 }
514
515 constexpr friend auto operator==(ConcreteSelf const& a, ConcreteSelf const& b) -> bool
517 {
518 return container::equal(a, b);
519 }
520 constexpr friend auto operator<=>(ConcreteSelf const& a, ConcreteSelf const& b)
522 {
523 return container::compare(a, b);
524 }
525
526 Node* m_root { nullptr };
527 Node* m_minimum { nullptr };
528 Node* m_maximum { nullptr };
530 [[no_unique_address]] Comp m_comparator;
531};
532}
#define DI_ASSERT(...)
Definition assert_bool.h:7
Definition const_iterator_impl.h:19
Definition rb_tree_iterator.h:10
constexpr void do_erase_rebalancing(Node *x)
Definition rb_tree.h:439
constexpr auto node_color(Node *node) const -> Node::Color
Definition rb_tree.h:212
constexpr void do_insert_node(InsertPosition position, Node &to_insert)
Definition rb_tree.h:305
constexpr void transplant(Node &u, Node *v)
Definition rb_tree.h:376
constexpr auto equal_range_impl(U &&needle) const
Definition rb_tree.h:131
constexpr friend auto operator==(ConcreteSelf const &a, ConcreteSelf const &b) -> bool requires(concepts::EqualityComparable< Value >)
Definition rb_tree.h:515
auto operator=(RBTree const &) -> RBTree &=delete
constexpr auto operator=(RBTree &&other) -> RBTree &
Definition rb_tree.h:67
constexpr auto lower_bound_impl(U &&needle) const -> ConstIterator
Definition rb_tree.h:137
constexpr auto find_impl(U &&needle) const -> ConstIterator
Definition rb_tree.h:167
constexpr auto begin() -> Iterator
Definition rb_tree.h:82
constexpr auto insert_node(Node &node)
Definition rb_tree.h:89
constexpr auto compare(T const &a, U &&b) const
Definition rb_tree.h:511
constexpr void merge_impl(RBTree &&other)
Definition rb_tree.h:182
constexpr auto size() const -> usize
Definition rb_tree.h:79
constexpr friend auto operator<=>(ConcreteSelf const &a, ConcreteSelf const &b)
Definition rb_tree.h:520
constexpr auto upper_bound_impl(U &&needle) const -> ConstIterator
Definition rb_tree.h:152
constexpr auto empty() const -> bool
Definition rb_tree.h:80
constexpr RBTree(Comp comparator)
Definition rb_tree.h:58
constexpr ~RBTree()
Definition rb_tree.h:77
constexpr RBTree(RBTree &&other)
Definition rb_tree.h:60
constexpr auto end() -> Iterator
Definition rb_tree.h:84
constexpr auto insert_position(U &&needle) const -> InsertPosition
Definition rb_tree.h:268
constexpr auto erase_impl(ConstIterator position) -> Iterator
Definition rb_tree.h:117
constexpr auto end() const -> ConstIterator
Definition rb_tree.h:85
constexpr auto begin() const -> ConstIterator
Definition rb_tree.h:83
constexpr auto insert_node(ConstIterator, Node &node)
Definition rb_tree.h:105
constexpr void insert_node(InsertPosition position, Node &to_insert)
Definition rb_tree.h:299
constexpr auto unconst_iterator(ConstIterator it) -> Iterator
Definition rb_tree.h:87
constexpr void erase_node(Node &to_delete)
Definition rb_tree.h:389
constexpr void rotate_left(Node &x)
Definition rb_tree.h:220
constexpr auto node_value(Node const &node) const -> Value const &
Definition rb_tree.h:207
RBTree(RBTree const &)=delete
constexpr void do_insert_rebalancing(Node *node)
Definition rb_tree.h:335
constexpr auto node_value(Node &node) const -> Value &
Definition rb_tree.h:204
constexpr void rotate_right(Node &y)
Definition rb_tree.h:241
Definition view.h:35
Definition tuple.h:27
Definition compare.h:82
Definition core.h:114
Definition relation.h:31
Definition compare.h:91
Definition sequence.h:12
constexpr auto next
Definition next.h:35
constexpr auto equal
Definition equal.h:46
constexpr auto compare
Definition compare.h:40
constexpr auto end
Definition end.h:55
constexpr auto invoke
Definition invoke.h:100
detail::ConditionalHelper< value, T, U >::Type Conditional
Definition core.h:88
size_t usize
Definition integers.h:33
Definition vocab.h:96
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
constexpr auto exchange(T &object, U &&new_value) -> T
Definition exchange.h:8
constexpr auto in_place_type
Definition in_place_type.h:12
Definition rb_tree_node.h:9
constexpr auto successor() const -> RBTreeNode *
Definition rb_tree_node.h:48
constexpr auto is_right_child() const -> bool
Definition rb_tree_node.h:16
constexpr auto predecessor() const -> RBTreeNode *
Definition rb_tree_node.h:34
RBTreeNode * right
Definition rb_tree_node.h:65
RBTreeNode * left
Definition rb_tree_node.h:64
constexpr auto is_left_child() const -> bool
Definition rb_tree_node.h:15
RBTreeNode * parent
Definition rb_tree_node.h:63
Color
Definition rb_tree_node.h:11
@ Black
Definition rb_tree_node.h:11
@ Red
Definition rb_tree_node.h:11
Color color
Definition rb_tree_node.h:62
bool left
Definition rb_tree.h:263
Node * parent
Definition rb_tree.h:262