aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
AVLTree_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
44#include <functional>
45#include <sstream>
46#include <utility>
47
50
51#include <type_traits>
52
53#ifndef DOXYGEN_SHOULD_SKIP_THIS
54
55namespace gum {
56
57 // =========================================================================
58 // AVLTreeNode constructors
59 // =========================================================================
60
61 template < typename Val >
62 AVLTreeNode< Val >::AVLTreeNode(const Val& val) : value(val) {}
63
64 template < typename Val >
65 AVLTreeNode< Val >::AVLTreeNode(Val&& val) noexcept : value(std::move(val)) {}
66
67 template < typename Val >
68 template < typename... Args >
69 AVLTreeNode< Val >::AVLTreeNode(const Emplace& emplace, Args&&... args) :
70 value(std::forward< Args >(args)...) {}
71
72 template < typename Val >
73 AVLTreeNode< Val >::AVLTreeNode(const AVLTreeNode< Val >& from) :
74 parent(from.parent), left_child(from.left_child), right_child(from.right_child),
75 height(from.height), value(from.value) {}
76
77 template < typename Val >
78 AVLTreeNode< Val >::AVLTreeNode(AVLTreeNode< Val >&& from) noexcept :
79 parent(from.parent), left_child(from.left_child), right_child(from.right_child),
80 height(from.height), value(std::move(from.value)) {}
81
82 template < typename Val >
83 AVLTreeNode< Val >::~AVLTreeNode() {
84 GUM_DESTRUCTOR(AVLTreeNode);
85 }
86
87 template < typename Val >
88 bool AVLTreeNode< Val >::operator==(const AVLTreeNode< Val >& from) const {
89 return value == from.value;
90 }
91
92 template < typename Val >
93 std::ostream& operator<<(std::ostream& stream, const AVLTreeNode< Val >& node) {
94 return stream << '<' << node.value << '>';
95 }
96
98 template < typename Val, typename Cmp >
99 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::copySubtree_(const AVLNode* from_node,
100 AVLNode* new_parent) {
101 if (from_node == nullptr) return nullptr;
102
103 AVLNode* new_node = nullptr;
104 AVLNode* new_left_child = nullptr;
105 AVLNode* new_right_child;
106 try {
107 new_node = new AVLNode(from_node->value);
108
109 new_left_child = copySubtree_(from_node->left_child, new_node);
110 new_right_child = copySubtree_(from_node->right_child, new_node);
111
112 new_node->parent = new_parent;
113 new_node->left_child = new_left_child;
114 new_node->right_child = new_right_child;
115 new_node->height = from_node->height;
116
117 return new_node;
118 } catch (...) {
119 if (new_node != nullptr) delete new_node;
120 if (new_left_child != nullptr) deleteSubtree_(new_left_child);
121 // no need to delete new_right_child: if an exception was raised, it could not
122 // have been copied.
123 throw;
124 }
125 }
126
128 template < typename Val, typename Cmp >
129 void AVLTree< Val, Cmp >::deleteSubtree_(AVLNode* subtree_root_node) {
130 if (subtree_root_node == nullptr) return;
131
132 deleteSubtree_(subtree_root_node->left_child);
133 deleteSubtree_(subtree_root_node->right_child);
134 delete subtree_root_node;
135 }
136
138 template < typename Val, typename Cmp >
139 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::lowestNode_() const noexcept {
140 if (root_node_ == nullptr) return nullptr;
141
142 AVLNode* node = root_node_;
143 while (node->left_child != nullptr)
144 node = node->left_child;
145
146 return node;
147 }
148
150 template < typename Val, typename Cmp >
151 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::highestNode_() const noexcept {
152 if (root_node_ == nullptr) return nullptr;
153
154 AVLNode* node = root_node_;
155 while (node->right_child != nullptr)
156 node = node->right_child;
157
158 return node;
159 }
160
162 template < typename Val, typename Cmp >
163 AVLTree< Val, Cmp >::AVLTree(const Cmp& compare) : cmp_(compare) {
164 // for debugging purposes
165 GUM_CONSTRUCTOR(AVLTree);
166 }
167
169 template < typename Val, typename Cmp >
170 AVLTree< Val, Cmp >::AVLTree(std::initializer_list< Val > list) {
171 try {
172 for (const auto& val: list)
173 insert(val);
174 } catch (...) {
175 // if something went wrong, free all the memory allocated
176 deleteSubtree_(root_node_);
177
178 root_node_ = nullptr;
179 lowest_node_ = nullptr;
180 highest_node_ = nullptr;
181 nb_elements_ = Size(0);
182
183 throw;
184 }
185
186 // for debugging purposes
187 GUM_CONSTRUCTOR(AVLTree);
188 }
189
191 template < typename Val, typename Cmp >
192 AVLTree< Val, Cmp >::AVLTree(const AVLTree< Val, Cmp >& from) :
193 nb_elements_(from.nb_elements_), cmp_(from.cmp_) {
194 root_node_ = copySubtree_(from.root_node_, nullptr);
195 lowest_node_ = lowestNode_();
196 highest_node_ = highestNode_();
197
198 // for debugging purposes
199 GUM_CONS_CPY(AVLTree);
200 }
201
203 template < typename Val, typename Cmp >
204 AVLTree< Val, Cmp >::AVLTree(AVLTree< Val, Cmp >&& from) noexcept :
205 root_node_(from.root_node_), lowest_node_(from.lowest_node_),
206 highest_node_(from.highest_node_), nb_elements_(from.nb_elements_),
207 owns_nodes_(from.owns_nodes_), cmp_(std::move(from.cmp_)),
208 safe_iterators_(std::move(from.safe_iterators_)) {
209 from.root_node_ = nullptr;
210 from.lowest_node_ = nullptr;
211 from.highest_node_ = nullptr;
212
213 // update the tree_ field in the safe iterators
214 for (auto iter: safe_iterators_) {
215 iter->tree_ = this;
216 }
217
218 // for debugging purposes
219 GUM_CONS_CPY(AVLTree);
220 }
221
223 template < typename Val, typename Cmp >
224 AVLTree< Val, Cmp >::~AVLTree() {
225 if (owns_nodes_) deleteSubtree_(root_node_);
226
227 // make the safe iterators point to nothing
228 for (auto iter: safe_iterators_) {
229 iter->unregisterTree_();
230 }
231
232 // for debugging purposes
233 GUM_DESTRUCTOR(AVLTree);
234 }
235
237 template < typename Val, typename Cmp >
238 AVLTree< Val, Cmp >& AVLTree< Val, Cmp >::operator=(const AVLTree< Val, Cmp >& from) {
239 if (this != &from) {
240 if (!owns_nodes_) {
242 "It is forbidden to copy an AVLTree into a tree that does not own its nodes")
243 }
244
245 if (owns_nodes_) deleteSubtree_(root_node_);
246
247 // make the safe iterators point to end/rend
248 for (auto iter: safe_iterators_) {
249 iter->pointToEndRend_();
250 }
251
252 try {
253 root_node_ = copySubtree_(from.root_node_, nullptr);
254 lowest_node_ = lowestNode_();
255 highest_node_ = highestNode_();
256 nb_elements_ = from.nb_elements_;
257 cmp_ = from.cmp_;
258 } catch (...) {
259 root_node_ = nullptr;
260 lowest_node_ = nullptr;
261 highest_node_ = nullptr;
262 nb_elements_ = Size(0);
263
264 throw;
265 }
266 }
267
268 return *this;
269 }
270
272 template < typename Val, typename Cmp >
273 AVLTree< Val, Cmp >& AVLTree< Val, Cmp >::operator=(AVLTree< Val, Cmp >&& from) {
274 if (this != &from) {
275 if (!owns_nodes_) {
277 "It is forbidden to move an AVLTree into a tree that does not own its nodes")
278 }
279
280 if (owns_nodes_) deleteSubtree_(root_node_);
281
282 // make the safe iterators point to end/rend
283 for (auto iter: safe_iterators_) {
284 iter->pointToEndRend_();
285 }
286
287 root_node_ = from.root_node_;
288 lowest_node_ = from.lowest_node_;
289 highest_node_ = from.highest_node_;
290 nb_elements_ = from.nb_elements_;
291 cmp_ = std::move(from.cmp_);
292
293 // add the iterators of from to safe_iterators_
294 if (safe_iterators_.empty()) {
295 safe_iterators_ = std::move(from.safe_iterators_);
296 for (auto iter: safe_iterators_) {
297 iter->tree_ = this;
298 }
299 } else {
300 for (auto from_iter: from.safe_iterators_) {
301 safe_iterators_.push_back(from_iter);
302 safe_iterators_.back()->tree_ = this;
303 from.safe_iterators_.clear();
304 }
305 }
306
307 from.root_node_ = nullptr;
308 from.lowest_node_ = nullptr;
309 from.highest_node_ = nullptr;
310 }
311 }
312
314 template < typename Val, typename Cmp >
315 Size AVLTree< Val, Cmp >::size() const noexcept {
316 return nb_elements_;
317 }
318
320 template < typename Val, typename Cmp >
321 bool AVLTree< Val, Cmp >::empty() const noexcept {
322 return nb_elements_ == Size(0);
323 }
324
326 template < typename Val, typename Cmp >
327 bool AVLTree< Val, Cmp >::contains(const value_type& val) const {
328 AVLNode* node = root_node_;
329 while (node != nullptr) {
330 if (node->value == val) return true;
331 node = cmp_(val, node->value) ? node->left_child : node->right_child;
332 }
333 return false;
334 }
335
337 template < typename Val, typename Cmp >
338 bool AVLTree< Val, Cmp >::exists(const value_type& val) const {
339 return contains(val);
340 }
341
343 template < typename Val, typename Cmp >
344 const typename AVLTree< Val, Cmp >::value_type& AVLTree< Val, Cmp >::highestValue() const {
345 if (highest_node_ == nullptr) {
346 GUM_ERROR(NotFound, "an empty AVL tree has no highest element");
347 }
348 return highest_node_->value;
349 }
350
352 template < typename Val, typename Cmp >
353 const typename AVLTree< Val, Cmp >::value_type& AVLTree< Val, Cmp >::lowestValue() const {
354 if (lowest_node_ == nullptr) { GUM_ERROR(NotFound, "an empty AVL tree has no lowest element"); }
355 return lowest_node_->value;
356 }
357
359 /*
360 // q p
361 // / \ / \
362 // / \ right rotation / \
363 // / / \ --------------> / \ \
364 // p / W \ / U \ q
365 // / \ +---+ +---+ / \
366 // / \ <-------------- / \
367 // / \ / \ left rotation / \ / \
368 // / U \ / V \ / V \ / W \
369 // +---+ +---+ +---+ +---+
370 */
371 template < typename Val, typename Cmp >
372 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::rightRotation_(AVLNode* node_q) {
373 AVLNode* node_p = node_q->left_child;
374 AVLNode* parent_q = node_q->parent;
375 AVLNode* subtree_u = node_p->left_child;
376 AVLNode* subtree_v = node_p->right_child;
377 AVLNode* subtree_w = node_q->right_child;
378
379 // rotate p and q
380 node_p->right_child = node_q;
381 node_q->parent = node_p;
382
383 node_p->parent = parent_q;
384 if (parent_q != nullptr) {
385 if (parent_q->left_child == node_q) parent_q->left_child = node_p;
386 else parent_q->right_child = node_p;
387 }
388 node_q->left_child = subtree_v;
389 if (subtree_v != nullptr) subtree_v->parent = node_q;
390
391 // update the heights
392 const int height_u = subtree_u != nullptr ? subtree_u->height : 0;
393 const int height_v = subtree_v != nullptr ? subtree_v->height : 0;
394 const int height_w = subtree_w != nullptr ? subtree_w->height : 0;
395 node_q->height = std::max(height_v, height_w) + 1;
396 node_p->height = std::max(node_q->height, height_u) + 1;
397
398 // return the new root
399 return node_p;
400 }
401
403 /*
404 // q p
405 // / \ / \
406 // / \ right rotation / \
407 // / / \ --------------> / \ \
408 // p / W \ / U \ q
409 // / \ +---+ +---+ / \
410 // / \ <-------------- / \
411 // / \ / \ left rotation / \ / \
412 // / U \ / V \ / V \ / W \
413 // +---+ +---+ +---+ +---+
414 */
415 template < typename Val, typename Cmp >
416 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::leftRotation_(AVLNode* node_p) {
417 AVLNode* node_q = node_p->right_child;
418 AVLNode* parent_p = node_p->parent;
419 AVLNode* subtree_u = node_p->left_child;
420 AVLNode* subtree_v = node_q->left_child;
421 AVLNode* subtree_w = node_q->right_child;
422
423 // rotate p and q
424 node_q->left_child = node_p;
425 node_p->parent = node_q;
426
427 node_q->parent = parent_p;
428 if (parent_p != nullptr) {
429 if (parent_p->left_child == node_p) parent_p->left_child = node_q;
430 else parent_p->right_child = node_q;
431 }
432
433 node_p->right_child = subtree_v;
434 if (subtree_v != nullptr) subtree_v->parent = node_p;
435
436 // update the heights
437 const int height_u = subtree_u != nullptr ? subtree_u->height : 0;
438 const int height_v = subtree_v != nullptr ? subtree_v->height : 0;
439 const int height_w = subtree_w != nullptr ? subtree_w->height : 0;
440 node_p->height = std::max(height_u, height_v) + 1;
441 node_q->height = std::max(node_p->height, height_w) + 1;
442
443 // return the new root
444 return node_q;
445 }
446
448 template < typename Val, typename Cmp >
449 void AVLTree< Val, Cmp >::rebalanceTree_(AVLNode* node) {
450 AVLNode* top_node = nullptr;
451 while (node != nullptr) {
452 const int left_height = node->left_child != nullptr ? node->left_child->height : 0;
453 const int right_height = node->right_child != nullptr ? node->right_child->height : 0;
454 node->height = 1 + std::max(left_height, right_height);
455
456 // if the node becomes unbalanced, rebalance it
457 if (left_height > right_height + 1) {
458 // here, the left subtree of node is higher than the right subtree
459 AVLNode* left_child = node->left_child;
460 const int left_left_height
461 = left_child->left_child != nullptr ? left_child->left_child->height : 0;
462 const int left_right_height
463 = left_child->right_child != nullptr ? left_child->right_child->height : 0;
464 if (left_left_height < left_right_height) {
465 // here, the left subtree of node is higher than the right subtree and
466 // the right subtree of node's left child is also higher than the left subtree.
467 // So we need a double rotation
468 leftRotation_(left_child);
469 }
470 top_node = rightRotation_(node);
471 } else if (right_height > left_height + 1) {
472 // here, the right subtree of node is higher than the left subtree
473 AVLNode* right_child = node->right_child;
474 const int right_left_height
475 = right_child->left_child != nullptr ? right_child->left_child->height : 0;
476 const int right_right_height
477 = right_child->right_child != nullptr ? right_child->right_child->height : 0;
478 if (right_left_height > right_right_height) {
479 // here, the right subtree of node is higher than the left subtree and
480 // the left subtree of node's right child is also higher than the right subtree.
481 // So we need a double rotation
482 rightRotation_(right_child);
483 }
484 top_node = leftRotation_(node);
485 } else {
486 top_node = node;
487 }
488
489 // move up to rebalance the nodes closer to the top of the tree
490 node = top_node->parent;
491 }
492
493 // here, top_node is the root node. Since it my differ from the root node before
494 // the insertion, we update root_node_, just in case
495 root_node_ = top_node;
496 }
497
499 template < typename Val, typename Cmp >
500 const typename AVLTree< Val, Cmp >::value_type& AVLTree< Val, Cmp >::insert_(AVLNode* new_node) {
501 // if the tree is empty, just create a new node
502 if (root_node_ == nullptr) {
503 new_node->parent = nullptr;
504 root_node_ = new_node;
505 lowest_node_ = root_node_;
506 highest_node_ = root_node_;
507 ++nb_elements_;
508 return new_node->value;
509 }
510
511 // here, the tree is not empty, so add the new node as a leaf without
512 // balancing the tree for the moment
513 const Val& value = new_node->value;
514 AVLNode* node = root_node_;
515 AVLNode* parent_node = nullptr;
516 while (node != nullptr) {
517 parent_node = node;
518 node = cmp_(value, node->value) ? node->left_child : node->right_child;
519 }
520
521 // here, parent_node should be the parent of our new leaf
522 new_node->parent = parent_node;
523 if (cmp_(new_node->value, parent_node->value)) {
524 parent_node->left_child = new_node;
525 if (lowest_node_ == parent_node) lowest_node_ = new_node;
526 } else {
527 parent_node->right_child = new_node;
528 if (highest_node_ == parent_node) highest_node_ = new_node;
529 }
530 ++nb_elements_;
531
532 // update the parent node and rebalance the tree
533 rebalanceTree_(parent_node);
534 return new_node->value;
535 }
536
538 template < typename Val, typename Cmp >
539 const typename AVLTree< Val, Cmp >::value_type&
540 AVLTree< Val, Cmp >::insert(typename AVLTree< Val, Cmp >::value_type&& value) {
541 return insert_(new AVLNode(std::move(value)));
542 }
543
545 template < typename Val, typename Cmp >
546 const typename AVLTree< Val, Cmp >::value_type&
547 AVLTree< Val, Cmp >::insert(const typename AVLTree< Val, Cmp >::value_type& val) {
548 return insert_(new AVLNode(val));
549 }
550
552 template < typename Val, typename Cmp >
553 template < typename... Args >
554 const typename AVLTree< Val, Cmp >::value_type& AVLTree< Val, Cmp >::emplace(Args&&... args) {
555 return insert_(new AVLNode(AVLNode::Emplace::EMPLACE, std::forward< Args >(args)...));
556 }
557
559 template < typename Val, typename Cmp >
560 typename AVLTree< Val, Cmp >::AVLNode* AVLTree< Val, Cmp >::removeNodeFromTree_(AVLNode* node) {
561 // if val cannot be found, do nothing
562 if (node == nullptr) return nullptr;
563
564 // here, node contains the value to be removed
565 AVLNode* parent_node = node->parent;
566
567 // if node has exactly two children, swap node with its successor in the right
568 // subtree, i.e., the leftmost leaf in the right subtree. This one is guaranteed
569 // to have at most only one child (the right one)
570 if ((node->left_child != nullptr) && (node->right_child != nullptr)) {
571 // find the successor
572 AVLNode* successor = node->right_child;
573 while (successor->left_child != nullptr)
574 successor = successor->left_child;
575
576 // remove the successor from the tree: its right child, if any, should now
577 // be the child of the parent of successor
578 AVLNode* successor_parent = successor->parent;
579 if (successor_parent->left_child == successor) {
580 // here, successor is not the right child of node
581 successor_parent->left_child = successor->right_child;
582 } else {
583 // here, successor is the right child of node
584 successor_parent->right_child = successor->right_child;
585 }
586 if (successor->right_child != nullptr) successor->right_child->parent = successor_parent;
587
588 // now, remove node from the tree: to do so, just swap node and its successor
589 AVLNode *removed_node, *kept_node;
590 if (owns_nodes_) {
591 // here, we perform the swap just by swapping the contents of the nodes
592 std::swap(node->value, successor->value);
593
594 // keep track of the node that will be freed from memory and the one remaining
595 removed_node = successor;
596 kept_node = node;
597 } else {
598 // here, we perform the swap by updating the parents/children of the nodes
599 successor->parent = node->parent;
600 if (node->parent != nullptr) {
601 if (node->parent->right_child == node) node->parent->right_child = successor;
602 else node->parent->left_child = successor;
603 }
604 successor->right_child = node->right_child;
605 if (node->right_child != nullptr) node->right_child->parent = successor;
606 successor->left_child = node->left_child;
607 if (node->left_child != nullptr) node->left_child->parent = successor;
608
609 // keep track of the node that will be freed from memory and the one remaining
610 removed_node = node;
611 kept_node = successor;
612 }
613 --nb_elements_;
614
615 // rebalance the tree (it also recomputes the root node)
616 // here, we should rebalance from the parent that successor had before we removed
617 // node, i.e., from successor_parent. However, if this parent was equal to node,
618 // we cannot do this since node has been removed from the tree. In such a case,
619 // this node has been substituted by kept_node. Hence we should rebalance the
620 // tree from kept_node
621 rebalanceTree_(successor_parent != node ? successor_parent : kept_node);
622
623 // if the successor was the highest node, we must update the highest_node_ field
624 // so that it still points to a node containing the value that successor had
625 // before we removed node. This corresponds precisely to kept_node. Note that
626 // there is no need to update the lowest node because we did not change the
627 // left subtree of node
628 if (highest_node_ == successor) { highest_node_ = kept_node; }
629
630 // if there are safe iterators, update their content:
631 // a1/ if their node_ field points to node, then make them point on nullptr
632 // a2/ if their node_ field points to successor, make them point to kept_node
633 // b1/ if their next_node_ points to node, make them point to kept_node
634 // b2/ if their next_node_ points to successor, make them point to the new
635 // successor of the kept_node
636 // c1/ if their preceding_node_ points to node, make them point to the new
637 // predecessor of kept_node
638 // c2/ if their preceding_node_ points to successor, make them point to kept_node
639 if (!safe_iterators_.empty()) {
640 AVLNode *new_predecessor = nullptr, *new_successor = nullptr;
641 for (auto iter: safe_iterators_) {
642 if (iter->node_ == node) { // cases a1/ and b2/
643 // here, compute once and for all, the new successor for b2/
644 if (new_successor == nullptr) { new_successor = iter->nextNode_(kept_node); }
645 iter->node_ = nullptr;
646 iter->next_node_ = new_successor;
647 } else if (iter->node_ == successor) { // cases a2/ and c1/
648 // here, compute once and for all, the new predecessor for c1/
649 if (new_predecessor == nullptr) { new_predecessor = iter->precedingNode_(kept_node); }
650 iter->node_ = kept_node;
651 iter->preceding_node_ = new_predecessor;
652 } else if (iter->next_node_ == node) { // case b1/
653 iter->next_node_ = kept_node;
654 } else if (iter->preceding_node_ == successor) { // case c2/
655 iter->preceding_node_ = kept_node;
656 }
657 }
658 }
659
660 return removed_node;
661 }
662
663 // here, node contains at most one child
664 AVLNode* child = node->left_child == nullptr ? node->right_child : node->left_child;
665
666 // if there are safe iterators, update their content:
667 // * here, if the node_ field points to node, make it point to nullptr
668 // * if preceding_node_ points to node, make it point to the predecessor
669 // of node
670 // * if next_node_ points to node, make it point to the new successor
671 // of node
672 if (!safe_iterators_.empty()) {
673 AVLNode *new_predecessor = nullptr, *new_successor = nullptr;
674 for (auto iter: safe_iterators_) {
675 if (iter->node_ == node) {
676 iter->node_ = nullptr;
677 } else if (iter->preceding_node_ == node) {
678 if (new_predecessor == nullptr) { new_predecessor = iter->precedingNode_(node); }
679 iter->preceding_node_ = new_predecessor;
680 } else if (iter->next_node_ == node) {
681 if (new_successor == nullptr) { new_successor = iter->nextNode_(node); }
682 iter->next_node_ = new_successor;
683 }
684 }
685 }
686
687 if (child == nullptr) { // here, node has no children
688 // simply remove node and indicate to its parent that node disappeared
689 if (parent_node != nullptr) {
690 if (parent_node->left_child == node) {
691 parent_node->left_child = nullptr;
692 if (node == lowest_node_) lowest_node_ = parent_node;
693 } else {
694 parent_node->right_child = nullptr;
695 if (node == highest_node_) highest_node_ = parent_node;
696 }
697
698 --nb_elements_;
699 } else {
700 // here, the parent dos not exist. So, the tree becomes empty
701 root_node_ = nullptr;
702 lowest_node_ = nullptr;
703 highest_node_ = nullptr;
704
705 --nb_elements_;
706 return node;
707 }
708 } else { // here, node has precisely one child
709 // so substitute node by its child in the tree
710 --nb_elements_;
711
712 if (parent_node != nullptr) {
713 if (parent_node->left_child == node) {
714 parent_node->left_child = child;
715 child->parent = parent_node;
716 if (node == lowest_node_) {
717 // if node is the lowest node of the tree, it has no left child. But
718 // since, here, it has a child, this one must be a right child. This
719 // child cannot have a left child, else the tree would have been
720 // imbalanced (because node would have a height of 0 on the left and
721 // of at least 2 on the right). Therefore, child is now the lowest node
722 lowest_node_ = child;
723 }
724 } else {
725 parent_node->right_child = child;
726 child->parent = parent_node;
727 if (node == highest_node_) highest_node_ = child;
728 }
729 } else {
730 // here, the parent does not exist. Hence, the new root node should
731 // be child. But we may need to recompute the lowest or the highest node
732 root_node_ = child;
733 child->parent = nullptr;
734
735 if (node == lowest_node_) {
736 // here, necessarily, child was the right child of node. We should
737 // therefore find the leftmost leaf of child's subtree
738 lowest_node_ = child;
739 while (lowest_node_->left_child != nullptr)
740 lowest_node_ = lowest_node_->left_child;
741 }
742 if (node == highest_node_) {
743 highest_node_ = child;
744 while (highest_node_->right_child != nullptr)
745 highest_node_ = highest_node_->right_child;
746 }
747
748 // no need to rebalance the tree
749 return node;
750 }
751 }
752
753 rebalanceTree_(parent_node);
754 return node;
755 }
756
758 template < typename Val, typename Cmp >
759 void AVLTree< Val, Cmp >::erase_(AVLNode* node) {
760 AVLNode* removed_node = removeNodeFromTree_(node);
761 if (removed_node != nullptr) delete removed_node;
762 }
763
765 template < typename Val, typename Cmp >
766 void AVLTree< Val, Cmp >::erase(const value_type& val) {
767 // find a node in which val is located
768 AVLNode* node = root_node_;
769 while (node != nullptr) {
770 if (node->value == val) break;
771 node = cmp_(val, node->value) ? node->left_child : node->right_child;
772 }
773 erase_(node);
774 }
775
777 template < typename Val, typename Cmp >
778 void AVLTree< Val, Cmp >::erase(typename AVLTree< Val, Cmp >::iterator_safe& iter) {
779 erase_(iter.node_);
780 }
781
783 template < typename Val, typename Cmp >
784 void AVLTree< Val, Cmp >::erase(typename AVLTree< Val, Cmp >::reverse_iterator_safe& iter) {
785 erase_(iter.node_);
786 }
787
789 template < typename Val, typename Cmp >
790 void AVLTree< Val, Cmp >::clear() {
791 // remove the elements from memory
792 if (owns_nodes_) deleteSubtree_(root_node_);
793 root_node_ = nullptr;
794 lowest_node_ = nullptr;
795 highest_node_ = nullptr;
796 nb_elements_ = Size(0);
797
798 // make all the safe iterators point to end/rend
799 for (auto iter: safe_iterators_) {
800 iter->pointToEndRend_();
801 }
802 }
803
805 template < typename Val, typename Cmp >
806 typename AVLTree< Val, Cmp >::iterator AVLTree< Val, Cmp >::begin() const {
807 return AVLTreeIterator(*this);
808 }
809
811 template < typename Val, typename Cmp >
812 constexpr const typename AVLTree< Val, Cmp >::iterator& AVLTree< Val, Cmp >::end() const {
813 return *(reinterpret_cast< const iterator* >(_AVLTree_end_));
814 }
815
817 template < typename Val, typename Cmp >
818 typename AVLTree< Val, Cmp >::reverse_iterator AVLTree< Val, Cmp >::rbegin() const {
819 return AVLTreeReverseIterator(*this, true);
820 }
821
823 template < typename Val, typename Cmp >
824 constexpr const typename AVLTree< Val, Cmp >::reverse_iterator&
825 AVLTree< Val, Cmp >::rend() const {
826 return *(reinterpret_cast< const reverse_iterator* >(_AVLTree_rend_));
827 }
828
830 template < typename Val, typename Cmp >
831 typename AVLTree< Val, Cmp >::iterator_safe AVLTree< Val, Cmp >::beginSafe() {
832 return AVLTreeIteratorSafe(*this);
833 }
834
836 template < typename Val, typename Cmp >
837 constexpr const typename AVLTree< Val, Cmp >::iterator_safe&
838 AVLTree< Val, Cmp >::endSafe() const {
839 return *(reinterpret_cast< const iterator_safe* >(_AVLTree_end_safe_));
840 }
841
843 template < typename Val, typename Cmp >
844 typename AVLTree< Val, Cmp >::reverse_iterator_safe AVLTree< Val, Cmp >::rbeginSafe() {
845 return AVLTreeReverseIteratorSafe(*this, true);
846 }
847
849 template < typename Val, typename Cmp >
850 constexpr const typename AVLTree< Val, Cmp >::reverse_iterator_safe&
851 AVLTree< Val, Cmp >::rendSafe() const {
852 return *(reinterpret_cast< const reverse_iterator_safe* >(_AVLTree_rend_safe_));
853 }
854
856 template < typename Val, typename Cmp >
857 void AVLTree< Val, Cmp >::insertIntoSafeList_(typename AVLTree< Val, Cmp >::iterator_safe* iter) {
858 safe_iterators_.push_back(iter);
859 }
860
862 template < typename Val, typename Cmp >
863 void AVLTree< Val, Cmp >::removeFromSafeList_(typename AVLTree< Val, Cmp >::iterator_safe* iter) {
864 const Size len = safe_iterators_.size();
865 for (Size i = Size(0); i < len; ++i) {
866 if (safe_iterators_[i] == iter) {
867 safe_iterators_[i] = safe_iterators_[len - 1];
868 safe_iterators_.pop_back();
869 return;
870 }
871 }
872 }
873
875 template < typename Val, typename Cmp >
876 std::string AVLTree< Val, Cmp >::toString() const {
877 std::stringstream str;
878 str << '{';
879 bool first = true;
880 for (const auto& val: *this) {
881 if (!first) str << " , ";
882 else first = false;
883 str << val;
884 }
885 str << '}';
886 return str.str();
887 }
888
890
892 template < typename Val, typename Cmp >
893 typename AVLTreeIterator< Val, Cmp >::AVLNode*
894 AVLTreeIterator< Val, Cmp >::nextNode_(AVLNode* node) const noexcept {
895 if (node != nullptr) {
896 // here, the iterator points toward an element of the tree
897
898 if (node->right_child != nullptr) {
899 // here, node has a right child, hence the next element is the leftmost
900 // leaf of this child
901 AVLNode* next_node = node->right_child;
902 while (next_node->left_child != nullptr)
903 next_node = next_node->left_child;
904 return next_node;
905 } else {
906 // if node is the highest node of the tree, we go to the end iterator, else
907 // we are guaranteed that node has a successor
908 if (node == tree_->highest_node_) { return nullptr; }
909
910 // if node has no right child, we need to move up int the tree until we get a
911 // node that is on a right upper edge. This is our next node
912 AVLNode* current_node = node;
913 AVLNode* next_node = node->parent;
914
915 while (next_node->right_child == current_node) {
916 current_node = next_node;
917 next_node = next_node->parent;
918 }
919
920 return next_node;
921 }
922 } else {
923 return nullptr;
924 }
925 }
926
928 template < typename Val, typename Cmp >
929 typename AVLTreeIterator< Val, Cmp >::AVLNode*
930 AVLTreeIterator< Val, Cmp >::precedingNode_(AVLNode* node) const noexcept {
931 if (node != nullptr) {
932 // here, the iterator points toward an element of the tree
933
934 if (node->left_child != nullptr) {
935 // here, node has a left child, hence the next element is the rightmost
936 // leaf of this child
937 AVLNode* next_node = node->left_child;
938 while (next_node->right_child != nullptr)
939 next_node = next_node->right_child;
940 return next_node;
941 } else {
942 // if node is the lowest node of the tree, we go to the rend iterator, else
943 // we are guaranteed that node has a predecessor
944 if (node == tree_->lowest_node_) { return nullptr; }
945
946 // if node has no left child, we need to move up int the tree until we get a
947 // node that is on a left upper edge. This is our next node
948 AVLNode* current_node = node;
949 AVLNode* next_node = node->parent;
950
951 while (next_node->left_child == current_node) {
952 current_node = next_node;
953 next_node = next_node->parent;
954 }
955
956 return next_node;
957 }
958 } else {
959 return nullptr;
960 }
961 }
962
964 template < typename Val, typename Cmp >
965 AVLTreeIterator< Val, Cmp >::AVLTreeIterator(const AVLTree< Val, Cmp >& tree,
966 const bool begin) noexcept :
967 tree_(const_cast< AVLTree< Val, Cmp >* >(&tree)),
968 node_(begin ? tree.lowest_node_ : tree.highest_node_) {
969 next_node_ = nextNode_(node_);
970 preceding_node_ = precedingNode_(node_);
971
972 GUM_CONSTRUCTOR(AVLTreeIterator)
973 }
974
976 template < typename Val, typename Cmp >
977 AVLTreeIterator< Val, Cmp >::AVLTreeIterator(const AVLTreeIterator< Val, Cmp >& from) noexcept :
978 tree_(from.tree_), node_(from.node_), next_node_(from.next_node_),
979 preceding_node_(from.preceding_node_) {
980 GUM_CONS_CPY(AVLTreeIterator)
981 }
982
984 template < typename Val, typename Cmp >
985 AVLTreeIterator< Val, Cmp >::AVLTreeIterator(AVLTreeIterator< Val, Cmp >&& from) noexcept :
986 tree_(from.tree_), node_(from.node_), next_node_(from.next_node_),
987 preceding_node_(from.preceding_node_) {
988 GUM_CONS_MOV(AVLTreeIterator)
989 }
990
992 template < typename Val, typename Cmp >
993 AVLTreeIterator< Val, Cmp >::~AVLTreeIterator() noexcept {
994 GUM_DESTRUCTOR(AVLTreeIterator);
995 }
996
998 template < typename Val, typename Cmp >
999 AVLTreeIterator< Val, Cmp >&
1000 AVLTreeIterator< Val, Cmp >::operator=(const AVLTreeIterator< Val, Cmp >& from) noexcept
1001 = default;
1002
1004 template < typename Val, typename Cmp >
1005 AVLTreeIterator< Val, Cmp >&
1006 AVLTreeIterator< Val, Cmp >::operator=(AVLTreeIterator< Val, Cmp >&& from) noexcept {
1007 tree_ = from.tree_;
1008 node_ = from.node_;
1009 next_node_ = from.next_node_;
1010 preceding_node_ = from.preceding_node_;
1011 return *this;
1012 }
1013
1015 template < typename Val, typename Cmp >
1016 bool AVLTreeIterator< Val, Cmp >::operator==(const AVLTreeIterator< Val, Cmp >& from) const {
1017 // when node_ is different from nullptr, testing whether "this" is equal to from
1018 // simply amounts to comparing their node_ fields. However, due to erasures in
1019 // the tree, it may happen that two iterators pointing to different nodes have
1020 // a nullptr node_ field. In this case, they will be equal if and only if their
1021 // next_node_ fields are equal. Here, it is important to use the next_node_
1022 // rather than their preceding_node_ field because the end iterator has nullptr
1023 // as the value of its preceding_node_ while an iterator moving by ++ operators
1024 // up to the end will not have this value for its preceding_node_. However, it
1025 // will have a next_node_ equal to nullptr, exactly as the end iterator.
1026 return (node_ == from.node_) && (next_node_ == from.next_node_);
1027 }
1028
1030 template < typename Val, typename Cmp >
1031 bool AVLTreeIterator< Val, Cmp >::operator!=(const AVLTreeIterator< Val, Cmp >& from) const {
1032 // for the reason of this or test, see operator== above.
1033 return (node_ != from.node_) || (next_node_ != from.next_node_);
1034 }
1035
1037 template < typename Val, typename Cmp >
1038 AVLTreeIterator< Val, Cmp >& AVLTreeIterator< Val, Cmp >::operator++() noexcept {
1039 preceding_node_ = node_;
1040 node_ = next_node_;
1041 next_node_ = nextNode_(node_);
1042 return *this;
1043 }
1044
1046 template < typename Val, typename Cmp >
1047 AVLTreeIterator< Val, Cmp >& AVLTreeIterator< Val, Cmp >::operator+=(const Size k) noexcept {
1048 for (Size i = 0; i < k; ++i) {
1049 AVLTreeIterator< Val, Cmp >::operator++();
1050 }
1051 return *this;
1052 }
1053
1055 template < typename Val, typename Cmp >
1056 AVLTreeIterator< Val, Cmp >& AVLTreeIterator< Val, Cmp >::operator--() noexcept {
1057 next_node_ = node_;
1058 node_ = preceding_node_;
1059 preceding_node_ = precedingNode_(node_);
1060 return *this;
1061 }
1062
1064 template < typename Val, typename Cmp >
1065 AVLTreeIterator< Val, Cmp >& AVLTreeIterator< Val, Cmp >::operator-=(const Size k) noexcept {
1066 for (Size i = 0; i < k; ++i) {
1067 AVLTreeIterator< Val, Cmp >::operator--();
1068 }
1069 return *this;
1070 }
1071
1073 template < typename Val, typename Cmp >
1074 void AVLTreeIterator< Val, Cmp >::unregisterTree_() noexcept {
1075 tree_ = nullptr;
1076 node_ = nullptr;
1077 preceding_node_ = nullptr;
1078 next_node_ = nullptr;
1079 }
1080
1082 template < typename Val, typename Cmp >
1083 void AVLTreeIterator< Val, Cmp >::pointToEndRend_() noexcept {
1084 node_ = nullptr;
1085 preceding_node_ = nullptr;
1086 next_node_ = nullptr;
1087 }
1088
1090 template < typename Val, typename Cmp >
1091 typename AVLTreeIterator< Val, Cmp >::const_reference
1092 AVLTreeIterator< Val, Cmp >::operator*() const {
1093 if (node_ != nullptr) return node_->value;
1094 else {
1095 if ((next_node_ == nullptr) || (preceding_node_ == nullptr)) {
1096 GUM_ERROR(NotFound, "an end/rend AVLTree iterator does not contain any value")
1097 } else {
1098 GUM_ERROR(NotFound, "the AVLTree iterator points to an erased value")
1099 }
1100 }
1101 }
1102
1104
1106 template < typename Val, typename Cmp >
1107 AVLTreeIteratorSafe< Val, Cmp >::AVLTreeIteratorSafe(AVLTree< Val, Cmp >& tree,
1108 const bool rbegin) :
1109 AVLTreeIterator< Val, Cmp >(tree, rbegin) {
1110 tree.insertIntoSafeList_(this);
1111 GUM_CONSTRUCTOR(AVLTreeIteratorSafe)
1112 }
1113
1115 template < typename Val, typename Cmp >
1116 AVLTreeIteratorSafe< Val, Cmp >::AVLTreeIteratorSafe(
1117 const AVLTreeIteratorSafe< Val, Cmp >& from) : AVLTreeIterator< Val, Cmp >(from) {
1118 if (this->tree_ != nullptr) this->tree_->insertIntoSafeList_(this);
1119 GUM_CONS_CPY(AVLTreeIteratorSafe)
1120 }
1121
1123 template < typename Val, typename Cmp >
1124 AVLTreeIteratorSafe< Val, Cmp >::AVLTreeIteratorSafe(AVLTreeIteratorSafe< Val, Cmp >&& from) :
1125 AVLTreeIterator< Val, Cmp >(std::move(from)) {
1126 if (this->tree_ != nullptr) {
1127 this->tree_->insertIntoSafeList_(this);
1128 this->tree_->removeFromSafeList_(&from);
1129 }
1130 GUM_CONS_MOV(AVLTreeIteratorSafe)
1131 }
1132
1134 template < typename Val, typename Cmp >
1135 AVLTreeIteratorSafe< Val, Cmp >::~AVLTreeIteratorSafe() noexcept {
1136 if (this->tree_ != nullptr) { this->tree_->removeFromSafeList_(this); }
1137 GUM_DESTRUCTOR(AVLTreeIteratorSafe)
1138 }
1139
1141 template < typename Val, typename Cmp >
1142 AVLTreeIteratorSafe< Val, Cmp >&
1143 AVLTreeIteratorSafe< Val, Cmp >::operator=(const AVLTreeIteratorSafe< Val, Cmp >& from) {
1144 if (this != &from) {
1145 if (from.tree_ != this->tree_) {
1146 if (this->tree_ != nullptr) { this->tree_->removeFromSafeList_(this); }
1147 if (from.tree_ != nullptr) { from.tree_->insertIntoSafeList_(this); }
1148 }
1149 AVLTreeIterator< Val, Cmp >::operator=(from);
1150 }
1151 return *this;
1152 }
1153
1155 template < typename Val, typename Cmp >
1156 AVLTreeIteratorSafe< Val, Cmp >&
1157 AVLTreeIteratorSafe< Val, Cmp >::operator=(AVLTreeIteratorSafe< Val, Cmp >&& from) {
1158 if (this != &from) {
1159 if (from.tree_ != this->tree_) {
1160 if (this->tree_ != nullptr) { this->tree_->removeFromSafeList_(this); }
1161 if (from.tree_ != nullptr) { from.tree_->insertIntoSafeList_(this); }
1162 }
1163 AVLTreeIterator< Val, Cmp >::operator=(std::move(from));
1164 }
1165 return *this;
1166 }
1167
1169 template < typename Val, typename Cmp >
1170 bool AVLTreeIteratorSafe< Val, Cmp >::operator==(
1171 const AVLTreeIteratorSafe< Val, Cmp >& from) const {
1172 return AVLTreeIterator< Val, Cmp >::operator==(from);
1173 }
1174
1176 template < typename Val, typename Cmp >
1177 bool AVLTreeIteratorSafe< Val, Cmp >::operator!=(
1178 const AVLTreeIteratorSafe< Val, Cmp >& from) const {
1179 return AVLTreeIterator< Val, Cmp >::operator!=(from);
1180 }
1181
1183 template < typename Val, typename Cmp >
1184 AVLTreeIteratorSafe< Val, Cmp >& AVLTreeIteratorSafe< Val, Cmp >::operator++() noexcept {
1185 AVLTreeIterator< Val, Cmp >::operator++();
1186 return *this;
1187 }
1188
1190 template < typename Val, typename Cmp >
1191 AVLTreeIteratorSafe< Val, Cmp >&
1192 AVLTreeIteratorSafe< Val, Cmp >::operator+=(const Size k) noexcept {
1193 AVLTreeIterator< Val, Cmp >::operator+=(k);
1194 return *this;
1195 }
1196
1198 template < typename Val, typename Cmp >
1199 AVLTreeIteratorSafe< Val, Cmp >& AVLTreeIteratorSafe< Val, Cmp >::operator--() noexcept {
1200 AVLTreeIterator< Val, Cmp >::operator--();
1201 return *this;
1202 }
1203
1205 template < typename Val, typename Cmp >
1206 AVLTreeIteratorSafe< Val, Cmp >&
1207 AVLTreeIteratorSafe< Val, Cmp >::operator-=(const Size k) noexcept {
1208 AVLTreeIterator< Val, Cmp >::operator-=(k);
1209 return *this;
1210 }
1211
1213
1215 template < typename Val, typename Cmp >
1216 AVLTreeReverseIterator< Val, Cmp >::AVLTreeReverseIterator(const AVLTree< Val, Cmp >& tree,
1217 const bool rbegin) noexcept :
1218 AVLTreeIterator< Val, Cmp >(tree, !rbegin) {
1219 GUM_CONSTRUCTOR(AVLTreeReverseIterator)
1220 }
1221
1223 template < typename Val, typename Cmp >
1224 AVLTreeReverseIterator< Val, Cmp >::AVLTreeReverseIterator(
1225 const AVLTreeReverseIterator< Val, Cmp >& from) noexcept : AVLTreeIterator< Val, Cmp >(from) {
1226 GUM_CONS_CPY(AVLTreeReverseIterator)
1227 }
1228
1230 template < typename Val, typename Cmp >
1231 AVLTreeReverseIterator< Val, Cmp >::AVLTreeReverseIterator(
1232 AVLTreeReverseIterator< Val, Cmp >&& from) noexcept :
1233 AVLTreeIterator< Val, Cmp >(std::move(from)) {
1234 GUM_CONS_MOV(AVLTreeReverseIterator)
1235 }
1236
1238 template < typename Val, typename Cmp >
1239 AVLTreeReverseIterator< Val, Cmp >::~AVLTreeReverseIterator() noexcept {
1240 GUM_DESTRUCTOR(AVLTreeReverseIterator)
1241 }
1242
1244 template < typename Val, typename Cmp >
1245 AVLTreeReverseIterator< Val, Cmp >& AVLTreeReverseIterator< Val, Cmp >::operator=(
1246 const AVLTreeReverseIterator< Val, Cmp >& from) noexcept {
1247 AVLTreeIterator< Val, Cmp >::operator=(from);
1248 return *this;
1249 }
1250
1252 template < typename Val, typename Cmp >
1253 AVLTreeReverseIterator< Val, Cmp >& AVLTreeReverseIterator< Val, Cmp >::operator=(
1254 AVLTreeReverseIterator< Val, Cmp >&& from) noexcept {
1255 AVLTreeIterator< Val, Cmp >::operator=(std::move(from));
1256 return *this;
1257 }
1258
1260 template < typename Val, typename Cmp >
1261 bool AVLTreeReverseIterator< Val, Cmp >::operator==(
1262 const AVLTreeReverseIterator< Val, Cmp >& from) const {
1263 // when node_ is different from nullptr, testing whether "this" is equal to from
1264 // simply amounts to comparing their node_ fields. However, due to erasures in
1265 // the tree, it may happen that two iterators pointing to different nodes have
1266 // a nullptr node_ field. In this case, they will be equal if and only if their
1267 // preceding_node_ fields are equal. Here, it is important to use the preceding_node_
1268 // rather than their next_node_ field because the rend iterator has nullptr
1269 // as the value of its next_node_ while a reverse iterator moving by ++ operators
1270 // up to the end will not have this value for its next_node_. However, it
1271 // will have a preceding_node_ equal to nullptr, exactly as the end iterator.
1272 return (this->node_ == from.node_) && (this->preceding_node_ == from.preceding_node_);
1273 }
1274
1276 template < typename Val, typename Cmp >
1277 bool AVLTreeReverseIterator< Val, Cmp >::operator!=(
1278 const AVLTreeReverseIterator< Val, Cmp >& from) const {
1279 // for the reason of this or test, see operator== above.
1280 return (this->node_ != from.node_) || (this->preceding_node_ != from.preceding_node_);
1281 }
1282
1284 template < typename Val, typename Cmp >
1285 AVLTreeReverseIterator< Val, Cmp >& AVLTreeReverseIterator< Val, Cmp >::operator++() noexcept {
1286 AVLTreeIterator< Val, Cmp >::operator--();
1287 return *this;
1288 }
1289
1291 template < typename Val, typename Cmp >
1292 AVLTreeReverseIterator< Val, Cmp >&
1293 AVLTreeReverseIterator< Val, Cmp >::operator+=(const Size k) noexcept {
1294 for (Size i = 0; i < k; ++i) {
1295 AVLTreeReverseIterator< Val, Cmp >::operator++();
1296 }
1297 return *this;
1298 }
1299
1301 template < typename Val, typename Cmp >
1302 AVLTreeReverseIterator< Val, Cmp >& AVLTreeReverseIterator< Val, Cmp >::operator--() noexcept {
1303 AVLTreeIterator< Val, Cmp >::operator++();
1304 return *this;
1305 }
1306
1308 template < typename Val, typename Cmp >
1309 AVLTreeReverseIterator< Val, Cmp >&
1310 AVLTreeReverseIterator< Val, Cmp >::operator-=(const Size k) noexcept {
1311 for (Size i = 0; i < k; ++i) {
1312 AVLTreeReverseIterator< Val, Cmp >::operator--();
1313 }
1314 return *this;
1315 }
1316
1318
1320 template < typename Val, typename Cmp >
1321 AVLTreeReverseIteratorSafe< Val, Cmp >::AVLTreeReverseIteratorSafe(AVLTree< Val, Cmp >& tree,
1322 const bool rbegin) :
1323 AVLTreeIteratorSafe< Val, Cmp >(tree, !rbegin) {
1324 GUM_CONSTRUCTOR(AVLTreeReverseIteratorSafe)
1325 }
1326
1328 template < typename Val, typename Cmp >
1329 AVLTreeReverseIteratorSafe< Val, Cmp >::AVLTreeReverseIteratorSafe(
1330 const AVLTreeReverseIteratorSafe< Val, Cmp >& from) : AVLTreeIteratorSafe< Val, Cmp >(from) {
1331 GUM_CONS_CPY(AVLTreeReverseIteratorSafe)
1332 }
1333
1335 template < typename Val, typename Cmp >
1336 AVLTreeReverseIteratorSafe< Val, Cmp >::AVLTreeReverseIteratorSafe(
1337 AVLTreeReverseIteratorSafe< Val, Cmp >&& from) :
1338 AVLTreeIteratorSafe< Val, Cmp >(std::move(from)) {
1339 GUM_CONS_MOV(AVLTreeReverseIteratorSafe)
1340 }
1341
1343 template < typename Val, typename Cmp >
1344 AVLTreeReverseIteratorSafe< Val, Cmp >::~AVLTreeReverseIteratorSafe() noexcept {
1345 GUM_DESTRUCTOR(AVLTreeReverseIteratorSafe)
1346 }
1347
1349 template < typename Val, typename Cmp >
1350 AVLTreeReverseIteratorSafe< Val, Cmp >& AVLTreeReverseIteratorSafe< Val, Cmp >::operator=(
1351 const AVLTreeReverseIteratorSafe< Val, Cmp >& from) {
1352 AVLTreeIteratorSafe< Val, Cmp >::operator=(from);
1353 return *this;
1354 }
1355
1357 template < typename Val, typename Cmp >
1358 AVLTreeReverseIteratorSafe< Val, Cmp >& AVLTreeReverseIteratorSafe< Val, Cmp >::operator=(
1359 AVLTreeReverseIteratorSafe< Val, Cmp >&& from) {
1360 AVLTreeIteratorSafe< Val, Cmp >::operator=(std::move(from));
1361 return *this;
1362 }
1363
1365 template < typename Val, typename Cmp >
1366 bool AVLTreeReverseIteratorSafe< Val, Cmp >::operator==(
1367 const AVLTreeReverseIteratorSafe< Val, Cmp >& from) const {
1368 // when node_ is different from nullptr, testing whether "this" is equal to from
1369 // simply amounts to comparing their node_ fields. However, due to erasures in
1370 // the tree, it may happen that two iterators pointing to different nodes have
1371 // a nullptr node_ field. In this case, they will be equal if and only if their
1372 // preceding_node_ fields are equal. Here, it is important to use the preceding_node_
1373 // rather than their next_node_ field because the rend iterator has nullptr
1374 // as the value of its next_node_ while a reverse iterator moving by ++ operators
1375 // up to the end will not have this value for its next_node_. However, it
1376 // will have a preceding_node_ equal to nullptr, exactly as the end iterator.
1377 return (this->node_ == from.node_) && (this->preceding_node_ == from.preceding_node_);
1378 }
1379
1381 template < typename Val, typename Cmp >
1382 bool AVLTreeReverseIteratorSafe< Val, Cmp >::operator!=(
1383 const AVLTreeReverseIteratorSafe< Val, Cmp >& from) const {
1384 // for the reason of this or test, see operator== above.
1385 return (this->node_ != from.node_) || (this->preceding_node_ != from.preceding_node_);
1386 }
1387
1389 template < typename Val, typename Cmp >
1390 AVLTreeReverseIteratorSafe< Val, Cmp >&
1391 AVLTreeReverseIteratorSafe< Val, Cmp >::operator++() noexcept {
1392 AVLTreeIteratorSafe< Val, Cmp >::operator--();
1393 return *this;
1394 }
1395
1397 template < typename Val, typename Cmp >
1398 AVLTreeReverseIteratorSafe< Val, Cmp >&
1399 AVLTreeReverseIteratorSafe< Val, Cmp >::operator+=(const Size k) noexcept {
1400 for (Size i = 0; i < k; ++i) {
1401 AVLTreeReverseIteratorSafe< Val, Cmp >::operator++();
1402 }
1403 return *this;
1404 }
1405
1407 template < typename Val, typename Cmp >
1408 AVLTreeReverseIteratorSafe< Val, Cmp >&
1409 AVLTreeReverseIteratorSafe< Val, Cmp >::operator--() noexcept {
1410 AVLTreeIteratorSafe< Val, Cmp >::operator++();
1411 return *this;
1412 }
1413
1415 template < typename Val, typename Cmp >
1416 AVLTreeReverseIteratorSafe< Val, Cmp >&
1417 AVLTreeReverseIteratorSafe< Val, Cmp >::operator-=(const Size k) noexcept {
1418 for (Size i = 0; i < k; ++i) {
1419 AVLTreeReverseIteratorSafe< Val, Cmp >::operator--();
1420 }
1421 return *this;
1422 }
1423
1424 template < typename Val, typename Cmp >
1425 std::ostream& operator<<(std::ostream& stream, const AVLTree< Val, Cmp >& tree) {
1426 return stream << tree.toString();
1427 }
1428
1429 // HashFunc specialization for AVLTreeNode
1430 template < typename Val >
1431 Size HashFunc< AVLTreeNode< Val > >::operator()(const AVLTreeNode< Val >& key) const {
1432 return HashFunc< Val >::operator()(key.value);
1433 }
1434
1435} // namespace gum
1436
1437#endif // DOXYGEN_SHOULD_SKIP_THIS
AVL binary search trees.
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
aGrUM's exceptions
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
bool contains(std::string_view s, std::string_view needle)
true if needle in s
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
STL namespace.
std::ostream & operator<<(std::ostream &out, const TiXmlNode &base)
Definition tinyxml.cpp:1516