Intrusive Containers
Loading...
Searching...
No Matches
TreeIn.hpp
Go to the documentation of this file.
1#ifndef TreeIn_HPP
2#define TreeIn_HPP
3
4/**
5@file TreeIn.hpp
6@brief Intrusive Binary Tree (unbalenced), Implementation.
7
8This file defines a pair of templates (TreeInRoot and TreeInNode) that
9implement an intrusive binary tree.
10
11@copyright (c) 2014-2024 Richard Damon
12@parblock
13MIT License:
14
15Permission is hereby granted, free of charge, to any person obtaining a copy
16of this software and associated documentation files (the "Software"), to deal
17in the Software without restriction, including without limitation the rights
18to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19copies of the Software, and to permit persons to whom the Software is
20furnished to do so, subject to the following conditions:
21
22The above copyright notice and this permission notice shall be included in
23all copies or substantial portions of the Software.
24
25THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31THE SOFTWARE.
32@endparblock
33
34@see TreeIn.h
35@ingroup IntrusiveContainers
36*/
37
38#include "TreeIn.h"
39
40#define TREEIN_CHECK_ASSERT 0x02 ///< @todo Implement conditional assertions
41#define TREEIN_CHECK_AUTO 0x04
42/// Define Non-Zero to perform frequent Invariants Checks
43#ifndef TREEIN_CHECK
44/**
45 * TreeChecking
46 * 0 = Disable Checking
47 * +2 to check with asserts
48 * +4 to check after operations
49 *
50 */
51#define TREEIN_CHECK 0
52#endif
53
54#if TREEIN_CHECK
55#include "FreeRTOS.h"
56
57#if TREEIN_CHECK & TREEIN_CHECK_ASSERT
58#define TREEIN_ASSERT(cond) configASSERT(cond)
59#else
60#define TREEIN_ASSERT(cond) if(!(cond)) { readUnlock(save); return false; }
61#endif
62
63#endif
64
65
66/******************************************************************************************
67Implementation
68
69Note that when we need to convert a List or Node pointer/reference to a TreeInRoot/ListInNode
70pointer/reference we need to do an explicit static_cast, to avoid ambiquity in the case of
71classes deriving from multiple versions of TreeInRoot/ListInNode
72*/
73
74#if TREEIN_CHECK
75/**
76 * Tree Integrity check.
77 *
78 * Constraints Checked:
79 * + All Node in a tree point to the Root structure for that tree
80 * + Check that Node with Parent = NULL is pointed to be its Root
81 * + All other Nodes point to the same Root as their Parent
82 * + or if not in a tree, have no connections at all
83 * + Linkage forms a tree
84 * + Check that all nodes are pointed to by the left or right of their parent
85 * + Nodes are sorted Properly
86 * + Our Left Node is less than us
87 * + The Largest Node under our Left Node (right most child) is less than us
88 * + Our Right Node is greater than us
89 * + The Smallest Node under our Right Node (left most child) is greter than us
90 */
91template <class R, class N, class K, ContainerThreadSafety s, int n>
92inline bool TreeInNode<R, N, K, s, n>::check() const {
93 N const* me = static_cast<N const*>(this);
94 unsigned save = readLock(false);
95 if (m_root) {
96 Root* myroot = m_root;
97 if (m_parent == nullptr) {
98 TREEIN_ASSERT(static_cast<Root*>(m_root)->m_base == me);
99 } else {
100 Node* myparent = m_parent;
101 TREEIN_ASSERT(myparent->m_left == me || myparent->m_right == me);
102 TREEIN_ASSERT(myparent->m_root == m_root);
103 }
104
105 if (m_left) {
106 Node* myleft = m_left;
107 TREEIN_ASSERT(myleft->m_parent == me);
108 TREEIN_ASSERT(myroot->compare(*me, *m_left) <= 0);
109 TREEIN_ASSERT(myroot->compare(*m_left, *me) >= 0);
110 if(myleft->m_right) {
111 // Travese to find right-most child
112 while(myleft->m_right) {
113 myleft = myleft->m_right;
114 }
115 N const* rightmost = static_cast<N const*>(myleft);
116 TREEIN_ASSERT(myroot->compare(*me, *rightmost) <= 0);
117 TREEIN_ASSERT(myroot->compare(*rightmost, *me) >= 0);
118 }
119 }
120
121 if (m_right) {
122 Node* myright = m_right;
123 TREEIN_ASSERT(myright->m_parent == me);
124 TREEIN_ASSERT(myroot->compare(*me, *m_right) >= 0);
125 TREEIN_ASSERT(myroot->compare(*m_right, *me) <= 0);
126 if(myright->m_left) {
127 // Travers to find left-most child
128 while(myright->m_left) {
129 myright = myright->m_left;
130 }
131 N const* leftmost = static_cast<N const*>(myright);
132 TREEIN_ASSERT(myroot->compare(*me, *leftmost) >= 0);
133 TREEIN_ASSERT(myroot->compare(*leftmost, *me) <= 0);
134 }
135 }
136 } else {
137 // root == 0 means we must be disconnected.
138 TREEIN_ASSERT(m_parent == nullptr);
139 TREEIN_ASSERT(m_left == nullptr);
140 TREEIN_ASSERT(m_right == nullptr);
141 }
142 readUnlock(save);
143 return true;
144}
145
146template <class R, class N, class K, ContainerThreadSafety s, int n>
147inline bool TreeInRoot<R, N, K, s, n>::check() const {
148 R const* me = static_cast<R const*>(this);
149 bool flag = true;
150 unsigned save = readLock(false);
151 if (m_base) {
152 Node const* node = m_base;
153 TREEIN_ASSERT(node->m_root == me);
154 TREEIN_ASSERT(node->m_parent == nullptr);
155 while(node) {
156 flag = node->check();
157 if(!flag) {
158 readUnlock(save);
159 return 0;
160 } else if(node->m_left != nullptr) {
161 node = node->m_left;
162 } else if(node->m_right != nullptr) {
163 node = node->m_right;
164 } else {
165 while(node->m_parent) {
166 Node* parent = node->m_parent;
167 if(parent->m_left == node && parent->m_right){
168 node = parent->m_right;
169 break;
170 }
171 node = parent;
172 }
173 }
174 }
175 }
176 readUnlock(save);
177 return flag;
178}
179#else
180// Simple versions that bypass checking.
181
182template <class R, class N, class K, ContainerThreadSafety s, int n> inline bool TreeInNode<R, N, K, s, n>::check() const {
183 return true;
184}
185template <class R, class N, class K, ContainerThreadSafety s, int n> inline bool TreeInRoot<R, N, K, s, n>::check() const {
186 return true;
187}
188#endif
189
190/**
191Return node next in sort sequence.
192*/
193template <class R, class N, class K, ContainerThreadSafety s, int n>
195 N* node;
196 Node* mynode;
197 unsigned save = readLock(false);
198 if (m_right) {
199 // Node has a right child, next will be leftmost child of right child
200 node = m_right;
201 mynode = node;
202 while (mynode->m_left) {
203 node = mynode->m_left;
204 mynode = node;
205 }
206 readUnlock(save);
207 return node;
208 }
209 // Node does not have a right child, accend parents chain until we reach a parent we are left linked to.
210 mynode = const_cast<Node *>(this);
211 node = static_cast<N*>(mynode);
212 while (mynode->m_parent) {
213 N* myparent = mynode->m_parent;
214 mynode = myparent;
215 if (mynode->m_left == node) {
216 readUnlock(save);
217 return myparent;
218 }
219 node = myparent;
220 }
221 readUnlock(save);
222 return nullptr;
223}
224
225/**
226Return previous node in sort sequence.
227*/
228template <class R, class N, class K, ContainerThreadSafety s, int n>
230 N* node;
231 Node* mynode;
232 unsigned save = readLock(false);
233 if (m_left) {
234 // Node has a left child, prev will be rightmost child of left child
235 node = m_left;
236 mynode = node;
237 while (mynode->m_right) {
238 node = mynode->m_right;
239 mynode = node;
240 }
241 readUnlock(save);
242 return node;
243 }
244 // Node does not have a right child, ascend parents chain until we reach a parent we are left linked to.
245 mynode = const_cast<Node*>(this);
246 node = static_cast<N*>(mynode);
247 while (mynode->m_parent) {
248 N* myparent = mynode->m_parent;
249 mynode = myparent;
250 if (mynode->m_right == node) {
251 readUnlock(save);
252 return myparent;
253 }
254 node = myparent;
255 }
256 readUnlock(save);
257 return nullptr;
258}
259
260template <class R, class N, class K, ContainerThreadSafety s, int n>
262 unsigned save = readLock(false);
263 if (m_base == nullptr) return nullptr;
264 N* node = m_base;
265 Node* mynode = node;
266 while (mynode->m_left) {
267 node = mynode->m_left;
268 mynode = node;
269 }
270 readUnlock(save);
271 return node;
272}
273
274
275template <class R, class N, class K, ContainerThreadSafety s, int n>
277 if (m_base == 0) return 0;
278 unsigned save = readLock();
279 N* node = m_base;
280 Node* mynode = node;
281 while (mynode->m_right) {
282 node = mynode->m_right;
283 mynode = node;
284 }
285 readUnlock(save);
286 return node;
287}
288
289/**
290 * Remove node from whatever tree it is on, if it is on a tree.
291 * @verbatim
292
293 Delete Node N
294
295 Simple Cases, Not both childern (x is empty link)
296
297 P P P P P P
298 | => x | => | | => |
299 N N L N R
300 x x / x \
301 L R
302
303 Rebalance at P
304
305More Complicated, as we have both childern
306
307 More Complicated Special Case
308
309 P P P P
310 | => | | => |
311 N D N L
312 / \ / \ / \ / \
313 L R L R L R A R
314 \ \ / x
315 A A A
316 \ \
317 B B
318 \ \
319 D C
320 / x
321 C
322
323 Rebalance at B. D might be L if it had no right child in which case rebalance at L
324
325 L < A < B < C < D < N < R
326
327 Link to P either a left or right, or Root if P is NULL.
328 x indicates NULL links
329
330 @endverbatim
331 *
332 */
333
334template <class R, class N, class K, ContainerThreadSafety s,int n>
336 if (m_root) {
337 Root* root = m_root;
338#if TREEIN_CHECK & TREEIN_CHECK_AUTO
339 root->check();
340#endif
341 unsigned save = writeLock(false);
342
343 Node* myparent = m_parent;
344 N* newLink = nullptr;
345 if (m_left == nullptr) {
346 if (m_right == nullptr) {
347 // We are child node, we can just unlink
348 } else {
349 // Only have right, link our parent to right
350 newLink = m_right;
351 }
352 } else {
353 if (m_right == nullptr) {
354 // Only have left, link our parent to left
355 newLink = m_left;
356 } else {
357 // Have both left and right children, rotate our "previous" into our spot.
358 newLink = prev();
359 Node* nl = newLink;
360 // Our previous node should have its right linked to our right.
361 // Our previous node's right will be null since it is below us
362 nl->m_right = m_right;
363 static_cast<Node*>(m_right)->m_parent = newLink;
364
365 if (newLink != m_left){
366 // if our previous is not our direct left, unlink it from its parent
367 // linking in its stead it left.
368
369 static_cast<Node*>(nl->m_parent)->m_right = nl->m_left;
370 if (nl->m_left){
371 static_cast<Node*>(nl->m_left)->m_parent = nl->m_parent;
372 }
373 // Link our left into our previous left now that it is open.
374
375 nl->m_left = m_left;
376 static_cast<Node*>(m_left)->m_parent = newLink;
377
378 }
379 }
380 }
381 // link our replacement to our parent.
382 if (newLink) {
383 static_cast<Node*>(newLink)->m_parent = m_parent;
384 }
385 // update our parent (or root) to point to our replacement (newLink)
386 if (myparent) {
387 if (myparent->m_left == static_cast<N*>(this)) {
388 myparent->m_left = newLink;
389 } else /*if (parent->m_right == static_cast<N*>(this))*/ {
390 myparent->m_right = newLink;
391 }
392 } else {
393 static_cast<Root*>(m_root)->m_base = newLink;
394 }
395#if TREEIN_CHECK & TREEIN_CHECK_AUTO
396 static_cast<Root*>(m_root)->check();
397#endif
398 setRoot(nullptr);
399 m_parent = nullptr;
400 m_left = nullptr;
401 m_right = nullptr;
402 root->writeUnlock(save);
403 rebalance(); // rebalence to update to being a "free" node.
404#if TREEIN_CHECK & TREEIN_CHECK_AUTO
405 check();
406#endif
407 }
408}
409
410/**
411Remove Node from List
412
413@param node node to be removed.
414If node is not on this list, nothing will be done.
415*/
416template <class R, class N, class K, ContainerThreadSafety s, int n>
418 Node& mynode = node;
419 unsigned save = writeLock(false);
420 if (mynode.m_root == this) {
421 // Only remove if node is on this list.
422 mynode.remove();
423 }
424 writeUnlock(save);
425}
426
427
428/**
429Remove Node from List
430
431@param node Pointer to node to be removed.
432If node is null, operation will be ignored.
433If node is not on this list, nothing will be done.
434*/
435template <class R, class N, class K, ContainerThreadSafety s, int n_>
437 if (node != nullptr) remove(*node);
438}
439
440/**
441 * Add node to our tree, note trees are sorted by the compare member function which needs to be implemented by the user.
442 *
443 * @param node The node to add to the list
444 * If node is currently on a different list it is removed before being added to the list.
445 *
446 * If node is on the requested list, do nothing. If trying to change value and position, use resort
447 */
448
449template<class R, class N, class K, ContainerThreadSafety s,int n>
450inline void TreeInRoot<R, N, K, s, n>::add(N& node) {
451 Node& mynode = node;
452 if (mynode.m_root == this) return; // if already here, do nothing.
453 if (mynode.m_root != nullptr) mynode.remove(); // if on a different tree, remove.
454 unsigned save = writeLock(false);
455 if (m_base) {
456 N* nodebase = m_base;
457 while (1) {
458 Node* mynodebase = nodebase;
459 int cmp = compare(*nodebase, node);
460 if (cmp < 0) {
461 if (mynodebase->m_left) {
462 nodebase = mynodebase->m_left;
463 } else {
464 mynodebase->m_left = &node;
465 mynode.m_parent = nodebase;
466 break;
467 }
468 } else {
469 if (mynodebase->m_right) {
470 nodebase = mynodebase->m_right;
471 } else {
472 mynodebase->m_right = &node;
473 mynode.m_parent = nodebase;
474 break;
475 }
476 }
477 }
478 } else {
479 // Tree Empty, so simple to add
480 m_base = &node;
481 mynode.m_parent = nullptr;
482 }
483 mynode.setRoot(static_cast<R*>(this));
484 mynode.m_left = nullptr;
485 mynode.m_right = nullptr;
486 writeUnlock(save);
487 mynode.rebalance();
488#if TREEIN_CHECK & TREEIN_CHECK_AUTO
489 check();
490#endif
491}
492
493/**
494Add node to our tree.
495
496@param node The node to add to the list
497If node is null, Nothing is done.
498If node is currently on a list (even us) it is removed before being added to the list
499*/
500template<class R, class N, class K, ContainerThreadSafety s, int n_>
502 if (node != nullptr) add(*node);
503}
504
505/**
506Add ourself to a tree.
507
508@param myroot Tree to add to.
509*/
510
511
512template<class R, class N, class K, ContainerThreadSafety s, int n>
514 // Defer the add to the Tree which knows the sort
515 static_cast<Root&>(myroot).add(*static_cast<N*>(this));
516}
517
518
519/**
520Add ourself to a tree
521
522@param myroot Tree to add to.
523*/
524
525template<class R, class N, class K, ContainerThreadSafety s, int n>
527 if (myroot) {
528 addTo(*myroot);
529 } else {
530 remove();
531 }
532}
533
534/**
535 * find a node
536 */
537
538template<class R, class N, class K, ContainerThreadSafety s, int n>
540 N* node = base();
541 unsigned save = readLock(false);
542 while(node) {
543 int cmp = compareKey(*node, key);
544 if(cmp == 0) break; // Found the node, return it
545 if(cmp < 0) {
546 node = static_cast<Node*>(node)->m_left;
547 } else {
548 node = static_cast<Node*>(node)->m_right;
549 }
550 }
551 readUnlock(save);
552 return node;
553}
554/**
555 * find a node, or the node that would be just lower than this node
556 */
557
558template<class R, class N, class K, ContainerThreadSafety s, int n>
560 N* node = base();
561 N* cursor = node;
562 unsigned save = readLock(false);
563 while(cursor) {
564 int cmp = compareKey(*cursor, key);
565 if(cmp == 0) {
566 node = cursor;
567 break; // Found the node, return it
568 }
569 if(cmp < 0) {
570 node = cursor;
571 cursor = static_cast<Node*>(cursor)->m_left;
572 } else {
573 cursor = static_cast<Node*>(cursor)->m_right;
574 }
575 }
576 readUnlock(save);
577 return node;
578}
579
580/**
581 * find a node, r the node that would be just above this node.
582 */
583
584template<class R, class N, class K, ContainerThreadSafety s, int n>
586 N* node = base();
587 N* cursor = node;
588 unsigned save = readLock(false);
589 while(cursor) {
590 int cmp = compareKey(*cursor, key);
591 if(cmp == 0) {
592 node = cursor;
593 break; // Found the node, return it
594 }
595 if(cmp < 0) {
596 cursor = static_cast<Node*>(cursor)->m_left;
597 } else {
598 node = cursor;
599 cursor = static_cast<Node*>(cursor)->m_right;
600 }
601 }
602 readUnlock(save);
603 return node;
604}
605
606
607/**
608Constructor.
609
610Starts us as an empty list.
611*/
612template <class R, class N, class K, ContainerThreadSafety s, int n>
614m_base(nullptr)
615{}
616
617/**
618Destructor.
619
620Removes all nodes attached to us.
621
622Doesn't actually call remove on every node to avoid possible unneeded rebalencing, just
623manually unlinks all nodes.
624*/
625template <class R, class N, class K, ContainerThreadSafety s, int n>
627 Node* node = m_base;
628 while (node) {
629 if (node->m_left) {
630 node = node->m_left;
631 } else if (node->m_right) {
632 node = node->m_right;
633 } else {
634 Node* parent = node->m_parent;
635 node->m_left = nullptr;
636 node->m_right = nullptr;
637 node->m_parent = nullptr;
638 if (parent) {
639 if (parent->m_left == node) {
640 parent->m_left = nullptr;
641 }
642 if (parent->m_right == node) {
643 parent->m_right = nullptr;
644 }
645 }
646 node = parent;
647 }
648 }
649 m_base = nullptr;
650}
651
652/**
653Constructor.
654
655*/
656template <class R, class N, class K, ContainerThreadSafety s,int n>
658ContainerNode<s>(nullptr),
659m_root(nullptr),
660m_parent(nullptr),
661m_left(nullptr),
662m_right(nullptr) {
663}
664
665/**
666Destructor.
667
668Remove us from we are on, if any.
669*/
670template <class R, class N, class K, ContainerThreadSafety s,int n>
674#endif
Intrusive Binary Tree (unbalanced).
Base Container Node Class.
Definition Container.h:255
bool check() const override
Definition TreeIn.hpp:182
virtual ~TreeInNode()
Destructor.
Definition TreeIn.hpp:671
N * prev() const
Return previous node in sort sequence.
Definition TreeIn.hpp:229
virtual void remove()
Remove node from whatever tree it is on, if it is on a tree.
Definition TreeIn.hpp:335
class TreeInNode< R, N, K, s, n > Node
Type of DListIInNode.
Definition TreeIn.h:280
N * next() const
Return node next in sort sequence.
Definition TreeIn.hpp:194
void addTo(R &root)
Add ourself to a tree.
Definition TreeIn.hpp:513
class TreeInRoot< R, N, K, s, n > Root
Type of TreeInRoot.
Definition TreeIn.h:279
TreeInNode()
Constructor.
Definition TreeIn.hpp:657
N * last() const
Definition TreeIn.hpp:276
void remove(N &node)
Remove Node from List.
Definition TreeIn.hpp:417
virtual ~TreeInRoot()
Destructor.
Definition TreeIn.hpp:626
N * find(K key) const
find a node
Definition TreeIn.hpp:539
class TreeInNode< R, N, K, s, n > Node
Type of DListIInNode.
Definition TreeIn.h:158
bool check() const override
Definition TreeIn.hpp:185
TreeInRoot()
Constructor.
Definition TreeIn.hpp:613
N * findMinus(K key) const
find a node, or the node that would be just lower than this node
Definition TreeIn.hpp:559
N * first() const
Definition TreeIn.hpp:261
N * findPlus(K key) const
find a node, r the node that would be just above this node.
Definition TreeIn.hpp:585
virtual void add(N &node)
Add node to our tree, note trees are sorted by the compare member function which needs to be implemen...
Definition TreeIn.hpp:450