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