CookMem 1.4.0
A C++ memory context / allocator
Loading...
Searching...
No Matches
rbtree.h
1/*
2 * Copyright (c) 2018-2026 Heng Yuan
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#ifndef COOK_MEM_RBTREE_H
17#define COOK_MEM_RBTREE_H
18
19#include <cstddef>
20
21#include "exception.h"
22
24// Marks a private field that is intentionally never used, so that compilers
25// do not warn about it.
26#if defined(__GNUC__)
27#define COOKMEM_UNUSED_FIELD __attribute__ ((unused))
28#else
29#define COOKMEM_UNUSED_FIELD
30#endif
32
33namespace cookmem
34{
35
48{
49public:
53 typedef std::size_t ValueType;
54
63 void
65 {
66 m_size = value;
67 m_parent = parentNode;
68 m_children[0] = nullptr;
69 m_children[1] = nullptr;
70 m_next = nullptr;
71 m_red = true;
72 m_inList = false;
73 }
74
77 getValue () const
78 {
79 return m_size;
80 }
81
83 SelfType**
85 {
86 return m_children;
87 }
88
90 SelfType* const *
91 getChildren () const
92 {
93 return m_children;
94 }
95
99 {
100 return m_children[0];
101 }
102
104 const SelfType*
105 getLeft () const
106 {
107 return m_children[0];
108 }
109
111 void
113 {
114 m_children[0] = left;
115 }
116
118 SelfType*
120 {
121 return m_children[1];
122 }
123
125 const SelfType*
126 getRight () const
127 {
128 return m_children[1];
129 }
130
132 void
134 {
135 m_children[1] = right;
136 }
137
139 SelfType*
141 {
142 return m_parent;
143 }
144
146 const SelfType*
147 getParent () const
148 {
149 return m_parent;
150 }
151
153 void
155 {
156 m_parent = parentNode;
157 }
158
166 void
168 {
169 other->m_next = m_next;
170 other->m_children[0] = this;
171 other->m_inList = true;
172 if (m_next != nullptr)
173 {
174 m_next->m_children[0] = other;
175 }
176 m_next = other;
177 }
178
180 bool
181 hasList () const
182 {
183 return m_next != nullptr;
184 }
185
190 bool
191 isInList () const
192 {
193 return m_inList;
194 }
195
197 SelfType*
199 {
200 return m_next;
201 }
202
204 const SelfType*
205 getNext () const
206 {
207 return m_next;
208 }
209
216 SelfType*
218 {
219 SelfType* retNode = m_next;
220 SelfType* nextNode = retNode->m_next;
221 m_next = nextNode;
222 if (nextNode != nullptr)
223 {
224 nextNode->m_children[0] = this;
225 }
226 retNode->m_next = nullptr;
227 retNode->m_inList = false;
228
229 return retNode;
230 }
231
235 void
237 {
238 COOKMEM_ASSERT (m_inList);
239
240 SelfType* prevNode = m_children[0];
241 SelfType* nextNode = m_next;
242 prevNode->m_next = nextNode;
243 if (nextNode != nullptr)
244 {
245 nextNode->m_children[0] = prevNode;
246 }
247 m_next = nullptr;
248 m_inList = false;
249 }
250
258 SelfType*
260 {
261 SelfType* replacementNode = m_next;
262
263 // The rest of the list stays attached to replacementNode, and the
264 // first node of the rest already points back to replacementNode.
265 replacementNode->m_parent = m_parent;
266 replacementNode->m_children[0] = m_children[0];
267 replacementNode->m_children[1] = m_children[1];
268 replacementNode->m_red = m_red;
269 replacementNode->m_inList = false;
270
271 m_next = nullptr;
272 return replacementNode;
273 }
274
276 bool
277 isRed () const
278 {
279 return m_red;
280 }
281
283 void
284 setRed (bool red)
285 {
286 m_red = red;
287 }
288
289private:
294 std::size_t m_reserved COOKMEM_UNUSED_FIELD;
296 std::size_t m_size;
298 SelfType* m_children[2];
300 SelfType* m_parent;
302 SelfType* m_next;
304 bool m_red;
306 bool m_inList;
307};
308
315template<class Node>
317{
318public:
320 typedef Node NodeType;
322 typedef typename NodeType::ValueType ValueType;
323
324public:
325 RedBlackTree ()
326 : m_root (nullptr)
327 {
328 }
329
340 void
342 {
343 NodeType* parentNode = searchClosest (value);
344 NodeType* newNode = reinterpret_cast<NodeType*>(ptr);
345 newNode->init (value, parentNode);
346
347 if (parentNode == nullptr)
348 {
349 m_root = newNode;
350 }
351 else if (value < parentNode->getValue ())
352 {
353 parentNode->setLeft (newNode);
354 }
355 else if (value > parentNode->getValue ())
356 {
357 parentNode->setRight (newNode);
358 }
359 else // value == parentNode->getValue ()
360 {
361 // Equal values are kept in a list and do not affect tree balance.
362 parentNode->addList (newNode);
363 return;
364 }
365
366 if (newNode->getParent () == nullptr)
367 {
368 newNode->setRed (false);
369 return;
370 }
371 if (newNode->getParent ()->getParent () == nullptr)
372 {
373 return;
374 }
375
376 balanceInsert (newNode);
377 }
384 {
385 return this->m_root;
386 }
387
401 NodeType*
402 remove (ValueType& size, ValueType limit = ~static_cast<ValueType> (0))
403 {
404 NodeType* lastBigNode = nullptr;
405 NodeType* node = m_root;
406
407 while (node != nullptr)
408 {
409 if (node->getValue () < size)
410 {
411 node = node->getRight ();
412 }
413 else if (node->getValue () > size)
414 {
415 lastBigNode = node;
416 node = node->getLeft ();
417 }
418 else
419 {
420 break;
421 }
422 }
423
424 if (node == nullptr)
425 {
426 if (lastBigNode == nullptr)
427 {
428 return nullptr;
429 }
430 else
431 {
432 node = lastBigNode;
433 }
434 }
435
436 if (node->getValue () >= limit)
437 {
438 return nullptr;
439 }
440
441 if (node->hasList ())
442 {
443 NodeType* listNode = node->removeFromList ();
444 size = node->getValue ();
445 return listNode;
446 }
447
448 size = node->getValue ();
449 removeNode (node);
450
451 return node;
452 }
453
460 void
461 remove (void* ptr)
462 {
463 NodeType* targetNode = reinterpret_cast<NodeType*>(ptr);
464
465 if (targetNode->isInList ())
466 {
467 // The node is in the DLL of a tree node. Just unlink it.
468 targetNode->unlinkFromList ();
469 return;
470 }
471
472 // The node is in the tree. Since nodes have parent pointers, there
473 // is no need to search from the root.
474 removeNode (targetNode);
475 }
476
483 bool
484 contains (void* ptr)
485 {
486 if (m_root == nullptr)
487 {
488 return false;
489 }
490
491 NodeType* node2 = reinterpret_cast<NodeType*>(ptr);
492 const ValueType value = node2->getValue ();
493
494 NodeType* node = m_root;
495 while (node != nullptr)
496 {
497 if (value < node->getValue ())
498 {
499 node = node->getLeft ();
500 }
501 else if (value > node->getValue ())
502 {
503 node = node->getRight ();
504 }
505 else
506 {
507 do
508 {
509 if (node == node2)
510 {
511 return true;
512 }
513 node = node->getNext ();
514 }
515 while (node != nullptr);
516 }
517 }
518 return false;
519 }
520
532 bool
534 {
535 NodeType* node = reinterpret_cast<NodeType*>(ptr);
536
537 // All nodes in a list must have the same value.
538 if (node->isInList () || node->hasList ())
539 {
540 return false;
541 }
542
543 // The new value must stay below the value of the next larger node.
544 if (node->getRight () != nullptr)
545 {
546 return newValue < getLeftMostNode (node->getRight ())->getValue ();
547 }
548
549 NodeType* parentNode = node->getParent ();
550 while (parentNode != nullptr && node == parentNode->getRight ())
551 {
552 node = parentNode;
553 parentNode = node->getParent ();
554 }
555 return parentNode == nullptr || newValue < parentNode->getValue ();
556 }
557
563 bool
564 isEmpty () const
565 {
566 return m_root == nullptr;
567 }
568
569private:
570
571 void
573 {
574 NodeType* parentNode = oldChildNode->getParent ();
575 if (parentNode == nullptr)
576 {
577 m_root = newChildNode;
578 }
579 else if (oldChildNode == parentNode->getLeft ())
580 {
581 parentNode->setLeft (newChildNode);
582 }
583 else if (oldChildNode == parentNode->getRight ())
584 {
585 parentNode->setRight (newChildNode);
586 }
587 else
588 {
589 COOKMEM_ASSERT (false);
590 }
591 if (newChildNode != nullptr)
592 {
593 newChildNode->setParent (parentNode);
594 }
595 }
596
597 NodeType*
598 getLeftMostNode (NodeType* node)
599 {
600 while (node->getLeft () != nullptr)
601 {
602 node = node->getLeft ();
603 }
604 return node;
605 }
606
613 NodeType*
614 searchClosest (ValueType key)
615 {
616 if (m_root == nullptr)
617 {
618 return nullptr;
619 }
620
621 NodeType* node = m_root;
622
623 for (;;)
624 {
625 if (key < node->getValue ())
626 {
627 if (node->getLeft () == nullptr)
628 {
629 return node;
630 }
631 else
632 {
633 node = node->getLeft ();
634 }
635 }
636 else if (key > node->getValue ())
637 {
638 if (node->getRight () == nullptr)
639 {
640 return node;
641 }
642 else
643 {
644 node = node->getRight ();
645 }
646 }
647 else
648 {
649 return node;
650 }
651 }
652 }
653
654 void
655 balanceInsert (NodeType* node)
656 {
657 while (node != m_root &&
658 node->getParent ()->isRed ())
659 {
660 NodeType* grandParentNode = node->getParent ()->getParent ();
661 if (node->getParent () == grandParentNode->getLeft ())
662 {
663 NodeType* uncleNode = grandParentNode->getRight ();
664 if (uncleNode != nullptr &&
665 uncleNode->isRed ())
666 {
667 uncleNode->setRed (false);
668 node->getParent ()->setRed (false);
669 grandParentNode->setRed (true);
670 node = node->getParent ()->getParent ();
671 }
672 else
673 {
674 if (node == node->getParent ()->getRight ())
675 {
676 node = node->getParent ();
677 doLeftRotation(node);
678 }
679 node->getParent ()->setRed (false);
680 node->getParent ()->getParent ()->setRed (true);
681 doRightRotation (node->getParent ()->getParent ());
682 }
683 }
684 else
685 {
686 NodeType* uncleNode = grandParentNode->getLeft ();
687 if (uncleNode != nullptr &&
688 uncleNode->isRed ())
689 {
690 uncleNode->setRed (false);
691 node->getParent ()->setRed (false);
692 grandParentNode->setRed (true);
693 node = node->getParent ()->getParent ();
694 }
695 else
696 {
697 if (node == node->getParent ()->getLeft ())
698 {
699 node = node->getParent ();
700 doRightRotation (node);
701 }
702 node->getParent ()->setRed (false);
703 node->getParent ()->getParent ()->setRed (true);
704 doLeftRotation (node->getParent ()->getParent ());
705 }
706 }
707
708 if (node == m_root)
709 {
710 break;
711 }
712 }
713
714 m_root->setRed (false);
715 }
716
717 void
718 removeNode (NodeType* node)
719 {
720 if (node->hasList ())
721 {
722 // Replace the node with the first node of its list. The tree
723 // structure and colors do not change.
724 NodeType* replacementNode = node->promoteFirstListNode ();
725 if (replacementNode->getLeft () != nullptr)
726 {
727 replacementNode->getLeft ()->setParent (replacementNode);
728 }
729 if (replacementNode->getRight () != nullptr)
730 {
731 replacementNode->getRight ()->setParent (replacementNode);
732 }
733 updateParent (replacementNode, node);
734 return;
735 }
736
737 NodeType* replacementNode = node;
738 bool replacementWasRed = replacementNode->isRed ();
739 NodeType* childNode;
740 NodeType* childParentNode;
741
742 if (node->getLeft () == nullptr)
743 {
744 childNode = node->getRight ();
745 childParentNode = node->getParent ();
746 updateParent (childNode, node);
747 }
748 else if (node->getRight () == nullptr)
749 {
750 childNode = node->getLeft ();
751 childParentNode = node->getParent ();
752 updateParent (childNode, node);
753 }
754 else
755 {
756 replacementNode = getLeftMostNode (node->getRight ());
757 replacementWasRed = replacementNode->isRed ();
758 childNode = replacementNode->getRight ();
759
760 if (replacementNode->getParent () == node)
761 {
762 childParentNode = replacementNode;
763 if (childNode != nullptr)
764 {
765 childNode->setParent (replacementNode);
766 }
767 }
768 else
769 {
770 childParentNode = replacementNode->getParent ();
771 updateParent (childNode, replacementNode);
772 replacementNode->setRight (node->getRight ());
773 replacementNode->getRight ()->setParent (replacementNode);
774 }
775
776 updateParent (replacementNode, node);
777 replacementNode->setLeft (node->getLeft ());
778 replacementNode->getLeft ()->setParent (replacementNode);
779 replacementNode->setRed (node->isRed ());
780 }
781
782 if (!replacementWasRed)
783 {
784 balanceRemove (childNode, childParentNode);
785 }
786 if (childNode != nullptr)
787 {
788 childNode->setRed (false);
789 }
790 if (m_root != nullptr)
791 {
792 m_root->setRed (false);
793 }
794 }
795
796 static bool
797 isBlack (const NodeType* node)
798 {
799 return node == nullptr || !node->isRed ();
800 }
801
802 void
803 balanceRemove (NodeType* node, NodeType* parentNode)
804 {
805 while (node != m_root && isBlack (node))
806 {
807 if (parentNode == nullptr)
808 {
809 break;
810 }
811
812 if (node == parentNode->getLeft ())
813 {
814 NodeType* siblingNode = parentNode->getRight ();
815 if (siblingNode != nullptr && siblingNode->isRed ())
816 {
817 siblingNode->setRed (false);
818 parentNode->setRed (true);
819 doLeftRotation (parentNode);
820 siblingNode = parentNode->getRight ();
821 }
822
823 if (siblingNode == nullptr ||
824 (isBlack (siblingNode->getLeft ()) &&
825 isBlack (siblingNode->getRight ())))
826 {
827 if (siblingNode != nullptr)
828 {
829 siblingNode->setRed (true);
830 }
831 node = parentNode;
832 parentNode = node->getParent ();
833 }
834 else
835 {
836 if (isBlack (siblingNode->getRight ()))
837 {
838 if (siblingNode->getLeft () != nullptr)
839 {
840 siblingNode->getLeft ()->setRed (false);
841 }
842 siblingNode->setRed (true);
843 doRightRotation (siblingNode);
844 siblingNode = parentNode->getRight ();
845 }
846 siblingNode->setRed (parentNode->isRed ());
847 parentNode->setRed (false);
848 if (siblingNode->getRight () != nullptr)
849 {
850 siblingNode->getRight ()->setRed (false);
851 }
852 doLeftRotation (parentNode);
853 node = m_root;
854 parentNode = nullptr;
855 }
856 }
857 else
858 {
859 NodeType* siblingNode = parentNode->getLeft ();
860 if (siblingNode != nullptr && siblingNode->isRed ())
861 {
862 siblingNode->setRed (false);
863 parentNode->setRed (true);
864 doRightRotation (parentNode);
865 siblingNode = parentNode->getLeft ();
866 }
867
868 if (siblingNode == nullptr ||
869 (isBlack (siblingNode->getLeft ()) &&
870 isBlack (siblingNode->getRight ())))
871 {
872 if (siblingNode != nullptr)
873 {
874 siblingNode->setRed (true);
875 }
876 node = parentNode;
877 parentNode = node->getParent ();
878 }
879 else
880 {
881 if (isBlack (siblingNode->getLeft ()))
882 {
883 if (siblingNode->getRight () != nullptr)
884 {
885 siblingNode->getRight ()->setRed (false);
886 }
887 siblingNode->setRed (true);
888 doLeftRotation (siblingNode);
889 siblingNode = parentNode->getLeft ();
890 }
891 siblingNode->setRed (parentNode->isRed ());
892 parentNode->setRed (false);
893 if (siblingNode->getLeft () != nullptr)
894 {
895 siblingNode->getLeft ()->setRed (false);
896 }
897 doRightRotation (parentNode);
898 node = m_root;
899 parentNode = nullptr;
900 }
901 }
902 }
903
904 if (node != nullptr)
905 {
906 node->setRed (false);
907 }
908 }
909
927 void
928 doLeftRotation (NodeType* nodeA)
929 {
930 NodeType* nodeC = nodeA->getRight ();
931
932 NodeType* nodeD = nodeC->getLeft ();
933 nodeA->setRight (nodeD);
934 if (nodeD != nullptr)
935 {
936 nodeD->setParent (nodeA);
937 }
938
939 updateParent (nodeC, nodeA);
940
941 nodeC->setLeft (nodeA);
942 nodeA->setParent (nodeC);
943 }
944
962 void
963 doRightRotation (NodeType* nodeA)
964 {
965 NodeType* nodeB = nodeA->getLeft ();
966
967 NodeType* nodeE = nodeB->getRight ();
968 nodeA->setLeft (nodeE);
969 if (nodeE != nullptr)
970 {
971 nodeE->setParent (nodeA);
972 }
973
974 updateParent (nodeB, nodeA);
975
976 nodeB->setRight (nodeA);
977 nodeA->setParent (nodeB);
978 }
979
980private:
981 NodeType *m_root;
982};
983
989
990} // namespace cookmem
991
992#endif // COOK_MEM_RBTREE_H
Definition allocator.h:39
Definition rbtree.h:48
const SelfType * getParent() const
Definition rbtree.h:147
bool isRed() const
Definition rbtree.h:277
void setRight(SelfType *right)
Definition rbtree.h:133
void addList(SelfType *other)
Definition rbtree.h:167
SelfType * getParent()
Definition rbtree.h:140
SelfType * promoteFirstListNode()
Definition rbtree.h:259
void setParent(SelfType *parentNode)
Definition rbtree.h:154
const SelfType * getNext() const
Definition rbtree.h:205
SelfType * getRight()
Definition rbtree.h:119
const SelfType * getLeft() const
Definition rbtree.h:105
void init(ValueType value, SelfType *parentNode)
Definition rbtree.h:64
SelfType * getLeft()
Definition rbtree.h:98
SelfType ** getChildren()
Definition rbtree.h:84
SelfType *const * getChildren() const
Definition rbtree.h:91
const SelfType * getRight() const
Definition rbtree.h:126
bool isInList() const
Definition rbtree.h:191
SelfType * removeFromList()
Definition rbtree.h:217
bool hasList() const
Definition rbtree.h:181
std::size_t ValueType
Definition rbtree.h:53
ValueType getValue() const
Definition rbtree.h:77
void setRed(bool red)
Definition rbtree.h:284
PtrRBNode SelfType
Definition rbtree.h:51
void unlinkFromList()
Definition rbtree.h:236
void setLeft(SelfType *left)
Definition rbtree.h:112
SelfType * getNext()
Definition rbtree.h:198
Definition rbtree.h:317
void add(void *ptr, ValueType value)
Definition rbtree.h:341
void remove(void *ptr)
Definition rbtree.h:461
bool isEmpty() const
Definition rbtree.h:564
NodeType::ValueType ValueType
Definition rbtree.h:322
bool canGrowInPlace(void *ptr, ValueType newValue)
Definition rbtree.h:533
NodeType * remove(ValueType &size, ValueType limit=~static_cast< ValueType >(0))
Definition rbtree.h:402
NodeType * getRoot()
Definition rbtree.h:383
Node NodeType
Definition rbtree.h:320
bool contains(void *ptr)
Definition rbtree.h:484
Definition allocator.h:29
RedBlackTree< PtrRBNode > PtrRBTree
Definition rbtree.h:988