2 An OrderedCollectionLib instance that provides a red-black tree
3 implementation, and allocates and releases tree nodes with
6 This library instance is useful when a fast associative container is needed.
7 Worst case time complexity is O(log n) for Find(), Next(), Prev(), Min(),
8 Max(), Insert(), and Delete(), where "n" is the number of elements in the
9 tree. Complete ordered traversal takes O(n) time.
11 The implementation is also useful as a fast priority queue.
13 Copyright (C) 2014, Red Hat, Inc.
14 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
16 SPDX-License-Identifier: BSD-2-Clause-Patent
19 #include <Library/OrderedCollectionLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
26 } RED_BLACK_TREE_COLOR
;
29 // Incomplete types and convenience typedefs are present in the library class
30 // header. Beside completing the types, we introduce typedefs here that reflect
31 // the implementation closely.
33 typedef ORDERED_COLLECTION RED_BLACK_TREE
;
34 typedef ORDERED_COLLECTION_ENTRY RED_BLACK_TREE_NODE
;
35 typedef ORDERED_COLLECTION_USER_COMPARE RED_BLACK_TREE_USER_COMPARE
;
36 typedef ORDERED_COLLECTION_KEY_COMPARE RED_BLACK_TREE_KEY_COMPARE
;
38 struct ORDERED_COLLECTION
{
39 RED_BLACK_TREE_NODE
*Root
;
40 RED_BLACK_TREE_USER_COMPARE UserStructCompare
;
41 RED_BLACK_TREE_KEY_COMPARE KeyCompare
;
44 struct ORDERED_COLLECTION_ENTRY
{
46 RED_BLACK_TREE_NODE
*Parent
;
47 RED_BLACK_TREE_NODE
*Left
;
48 RED_BLACK_TREE_NODE
*Right
;
49 RED_BLACK_TREE_COLOR Color
;
53 Retrieve the user structure linked by the specified tree node.
57 @param[in] Node Pointer to the tree node whose associated user structure we
58 want to retrieve. The caller is responsible for passing a
61 @return Pointer to user structure linked by Node.
65 OrderedCollectionUserStruct (
66 IN CONST RED_BLACK_TREE_NODE
*Node
69 return Node
->UserStruct
;
73 A slow function that asserts that the tree is a valid red-black tree, and
74 that it orders user structures correctly.
78 This function uses the stack for recursion and is not recommended for
81 @param[in] Tree The tree to validate.
84 RedBlackTreeValidate (
85 IN CONST RED_BLACK_TREE
*Tree
89 Allocate and initialize the RED_BLACK_TREE structure.
91 Allocation occurs via MemoryAllocationLib's AllocatePool() function.
93 @param[in] UserStructCompare This caller-provided function will be used to
94 order two user structures linked into the
95 tree, during the insertion procedure.
97 @param[in] KeyCompare This caller-provided function will be used to
98 order the standalone search key against user
99 structures linked into the tree, during the
102 @retval NULL If allocation failed.
104 @return Pointer to the allocated, initialized RED_BLACK_TREE structure,
109 OrderedCollectionInit (
110 IN RED_BLACK_TREE_USER_COMPARE UserStructCompare
,
111 IN RED_BLACK_TREE_KEY_COMPARE KeyCompare
114 RED_BLACK_TREE
*Tree
;
116 Tree
= AllocatePool (sizeof *Tree
);
122 Tree
->UserStructCompare
= UserStructCompare
;
123 Tree
->KeyCompare
= KeyCompare
;
125 if (FeaturePcdGet (PcdValidateOrderedCollection
)) {
126 RedBlackTreeValidate (Tree
);
133 Check whether the tree is empty (has no nodes).
137 @param[in] Tree The tree to check for emptiness.
139 @retval TRUE The tree is empty.
141 @retval FALSE The tree is not empty.
145 OrderedCollectionIsEmpty (
146 IN CONST RED_BLACK_TREE
*Tree
149 return (BOOLEAN
)(Tree
->Root
== NULL
);
153 Uninitialize and release an empty RED_BLACK_TREE structure.
155 Read-write operation.
157 Release occurs via MemoryAllocationLib's FreePool() function.
159 It is the caller's responsibility to delete all nodes from the tree before
160 calling this function.
162 @param[in] Tree The empty tree to uninitialize and release.
166 OrderedCollectionUninit (
167 IN RED_BLACK_TREE
*Tree
170 ASSERT (OrderedCollectionIsEmpty (Tree
));
175 Look up the tree node that links the user structure that matches the
176 specified standalone key.
180 @param[in] Tree The tree to search for StandaloneKey.
182 @param[in] StandaloneKey The key to locate among the user structures linked
183 into Tree. StandaloneKey will be passed to
186 @retval NULL StandaloneKey could not be found.
188 @return The tree node that links to the user structure matching
189 StandaloneKey, otherwise.
191 RED_BLACK_TREE_NODE
*
193 OrderedCollectionFind (
194 IN CONST RED_BLACK_TREE
*Tree
,
195 IN CONST VOID
*StandaloneKey
198 RED_BLACK_TREE_NODE
*Node
;
201 while (Node
!= NULL
) {
204 Result
= Tree
->KeyCompare (StandaloneKey
, Node
->UserStruct
);
209 Node
= (Result
< 0) ? Node
->Left
: Node
->Right
;
216 Find the tree node of the minimum user structure stored in the tree.
220 @param[in] Tree The tree to return the minimum node of. The user structure
221 linked by the minimum node compares less than all other user
222 structures in the tree.
224 @retval NULL If Tree is empty.
226 @return The tree node that links the minimum user structure, otherwise.
228 RED_BLACK_TREE_NODE
*
230 OrderedCollectionMin (
231 IN CONST RED_BLACK_TREE
*Tree
234 RED_BLACK_TREE_NODE
*Node
;
241 while (Node
->Left
!= NULL
) {
249 Find the tree node of the maximum user structure stored in the tree.
253 @param[in] Tree The tree to return the maximum node of. The user structure
254 linked by the maximum node compares greater than all other
255 user structures in the tree.
257 @retval NULL If Tree is empty.
259 @return The tree node that links the maximum user structure, otherwise.
261 RED_BLACK_TREE_NODE
*
263 OrderedCollectionMax (
264 IN CONST RED_BLACK_TREE
*Tree
267 RED_BLACK_TREE_NODE
*Node
;
274 while (Node
->Right
!= NULL
) {
282 Get the tree node of the least user structure that is greater than the one
287 @param[in] Node The node to get the successor node of.
289 @retval NULL If Node is NULL, or Node is the maximum node of its containing
290 tree (ie. Node has no successor node).
292 @return The tree node linking the least user structure that is greater
293 than the one linked by Node, otherwise.
295 RED_BLACK_TREE_NODE
*
297 OrderedCollectionNext (
298 IN CONST RED_BLACK_TREE_NODE
*Node
301 RED_BLACK_TREE_NODE
*Walk
;
302 CONST RED_BLACK_TREE_NODE
*Child
;
309 // If Node has a right subtree, then the successor is the minimum node of
314 while (Walk
->Left
!= NULL
) {
322 // Otherwise we have to ascend as long as we're our parent's right child (ie.
323 // ascending to the left).
326 Walk
= Child
->Parent
;
327 while (Walk
!= NULL
&& Child
== Walk
->Right
) {
329 Walk
= Child
->Parent
;
336 Get the tree node of the greatest user structure that is less than the one
341 @param[in] Node The node to get the predecessor node of.
343 @retval NULL If Node is NULL, or Node is the minimum node of its containing
344 tree (ie. Node has no predecessor node).
346 @return The tree node linking the greatest user structure that is less
347 than the one linked by Node, otherwise.
349 RED_BLACK_TREE_NODE
*
351 OrderedCollectionPrev (
352 IN CONST RED_BLACK_TREE_NODE
*Node
355 RED_BLACK_TREE_NODE
*Walk
;
356 CONST RED_BLACK_TREE_NODE
*Child
;
363 // If Node has a left subtree, then the predecessor is the maximum node of
368 while (Walk
->Right
!= NULL
) {
376 // Otherwise we have to ascend as long as we're our parent's left child (ie.
377 // ascending to the right).
380 Walk
= Child
->Parent
;
381 while (Walk
!= NULL
&& Child
== Walk
->Left
) {
383 Walk
= Child
->Parent
;
390 Rotate tree nodes around Pivot to the right.
396 LeftChild Node1 ---> Node2 Pivot
398 Node2 LeftRightChild LeftRightChild Node1
400 The ordering Node2 < LeftChild < LeftRightChild < Pivot < Node1 is kept
401 intact. Parent (if any) is either at the left extreme or the right extreme of
402 this ordering, and that relation is also kept intact.
404 Edges marked with a dot (".") don't change during rotation.
406 Internal read-write operation.
408 @param[in,out] Pivot The tree node to rotate other nodes right around. It
409 is the caller's responsibility to ensure that
410 Pivot->Left is not NULL.
412 @param[out] NewRoot If Pivot has a parent node on input, then the
413 function updates Pivot's original parent on output
414 according to the rotation, and NewRoot is not
417 If Pivot has no parent node on input (ie. Pivot is
418 the root of the tree), then the function stores the
419 new root node of the tree in NewRoot.
422 RedBlackTreeRotateRight (
423 IN OUT RED_BLACK_TREE_NODE
*Pivot
,
424 OUT RED_BLACK_TREE_NODE
**NewRoot
427 RED_BLACK_TREE_NODE
*Parent
;
428 RED_BLACK_TREE_NODE
*LeftChild
;
429 RED_BLACK_TREE_NODE
*LeftRightChild
;
431 Parent
= Pivot
->Parent
;
432 LeftChild
= Pivot
->Left
;
433 LeftRightChild
= LeftChild
->Right
;
435 Pivot
->Left
= LeftRightChild
;
436 if (LeftRightChild
!= NULL
) {
437 LeftRightChild
->Parent
= Pivot
;
440 LeftChild
->Parent
= Parent
;
441 if (Parent
== NULL
) {
442 *NewRoot
= LeftChild
;
444 if (Pivot
== Parent
->Left
) {
445 Parent
->Left
= LeftChild
;
447 Parent
->Right
= LeftChild
;
451 LeftChild
->Right
= Pivot
;
452 Pivot
->Parent
= LeftChild
;
456 Rotate tree nodes around Pivot to the left.
462 Node1 RightChild ---> Pivot Node2
464 RightLeftChild Node2 Node1 RightLeftChild
466 The ordering Node1 < Pivot < RightLeftChild < RightChild < Node2 is kept
467 intact. Parent (if any) is either at the left extreme or the right extreme of
468 this ordering, and that relation is also kept intact.
470 Edges marked with a dot (".") don't change during rotation.
472 Internal read-write operation.
474 @param[in,out] Pivot The tree node to rotate other nodes left around. It
475 is the caller's responsibility to ensure that
476 Pivot->Right is not NULL.
478 @param[out] NewRoot If Pivot has a parent node on input, then the
479 function updates Pivot's original parent on output
480 according to the rotation, and NewRoot is not
483 If Pivot has no parent node on input (ie. Pivot is
484 the root of the tree), then the function stores the
485 new root node of the tree in NewRoot.
488 RedBlackTreeRotateLeft (
489 IN OUT RED_BLACK_TREE_NODE
*Pivot
,
490 OUT RED_BLACK_TREE_NODE
**NewRoot
493 RED_BLACK_TREE_NODE
*Parent
;
494 RED_BLACK_TREE_NODE
*RightChild
;
495 RED_BLACK_TREE_NODE
*RightLeftChild
;
497 Parent
= Pivot
->Parent
;
498 RightChild
= Pivot
->Right
;
499 RightLeftChild
= RightChild
->Left
;
501 Pivot
->Right
= RightLeftChild
;
502 if (RightLeftChild
!= NULL
) {
503 RightLeftChild
->Parent
= Pivot
;
506 RightChild
->Parent
= Parent
;
507 if (Parent
== NULL
) {
508 *NewRoot
= RightChild
;
510 if (Pivot
== Parent
->Left
) {
511 Parent
->Left
= RightChild
;
513 Parent
->Right
= RightChild
;
517 RightChild
->Left
= Pivot
;
518 Pivot
->Parent
= RightChild
;
522 Insert (link) a user structure into the tree.
524 Read-write operation.
526 This function allocates the new tree node with MemoryAllocationLib's
527 AllocatePool() function.
529 @param[in,out] Tree The tree to insert UserStruct into.
531 @param[out] Node The meaning of this optional, output-only
532 parameter depends on the return value of the
535 When insertion is successful (RETURN_SUCCESS),
536 Node is set on output to the new tree node that
537 now links UserStruct.
539 When insertion fails due to lack of memory
540 (RETURN_OUT_OF_RESOURCES), Node is not changed.
542 When insertion fails due to key collision (ie.
543 another user structure is already in the tree that
544 compares equal to UserStruct), with return value
545 RETURN_ALREADY_STARTED, then Node is set on output
546 to the node that links the colliding user
547 structure. This enables "find-or-insert" in one
548 function call, or helps with later removal of the
551 @param[in] UserStruct The user structure to link into the tree.
552 UserStruct is ordered against in-tree user
553 structures with the Tree->UserStructCompare()
556 @retval RETURN_SUCCESS Insertion successful. A new tree node has
557 been allocated, linking UserStruct. The new
558 tree node is reported back in Node (if the
559 caller requested it).
561 Existing RED_BLACK_TREE_NODE pointers into
562 Tree remain valid. For example, on-going
563 iterations in the caller can continue with
564 OrderedCollectionNext() /
565 OrderedCollectionPrev(), and they will
566 return the new node at some point if user
567 structure order dictates it.
569 @retval RETURN_OUT_OF_RESOURCES AllocatePool() failed to allocate memory for
570 the new tree node. The tree has not been
571 changed. Existing RED_BLACK_TREE_NODE
572 pointers into Tree remain valid.
574 @retval RETURN_ALREADY_STARTED A user structure has been found in the tree
575 that compares equal to UserStruct. The node
576 linking the colliding user structure is
577 reported back in Node (if the caller
578 requested it). The tree has not been
579 changed. Existing RED_BLACK_TREE_NODE
580 pointers into Tree remain valid.
584 OrderedCollectionInsert (
585 IN OUT RED_BLACK_TREE
*Tree
,
586 OUT RED_BLACK_TREE_NODE
**Node OPTIONAL
,
590 RED_BLACK_TREE_NODE
*Tmp
;
591 RED_BLACK_TREE_NODE
*Parent
;
593 RETURN_STATUS Status
;
594 RED_BLACK_TREE_NODE
*NewRoot
;
601 // First look for a collision, saving the last examined node for the case
602 // when there's no collision.
604 while (Tmp
!= NULL
) {
605 Result
= Tree
->UserStructCompare (UserStruct
, Tmp
->UserStruct
);
611 Tmp
= (Result
< 0) ? Tmp
->Left
: Tmp
->Right
;
619 Status
= RETURN_ALREADY_STARTED
;
624 // no collision, allocate a new node
626 Tmp
= AllocatePool (sizeof *Tmp
);
628 Status
= RETURN_OUT_OF_RESOURCES
;
637 // reference the user structure from the node
639 Tmp
->UserStruct
= UserStruct
;
642 // Link the node as a child to the correct side of the parent.
643 // If there's no parent, the new node is the root node in the tree.
645 Tmp
->Parent
= Parent
;
648 if (Parent
== NULL
) {
650 Tmp
->Color
= RedBlackTreeBlack
;
651 Status
= RETURN_SUCCESS
;
661 Tmp
->Color
= RedBlackTreeRed
;
664 // Red-black tree properties:
666 // #1 Each node is either red or black (RED_BLACK_TREE_NODE.Color).
668 // #2 Each leaf (ie. a pseudo-node pointed-to by a NULL valued
669 // RED_BLACK_TREE_NODE.Left or RED_BLACK_TREE_NODE.Right field) is black.
671 // #3 Each red node has two black children.
673 // #4 For any node N, and for any leaves L1 and L2 reachable from N, the
674 // paths N..L1 and N..L2 contain the same number of black nodes.
676 // #5 The root node is black.
678 // By replacing a leaf with a red node above, only property #3 may have been
679 // broken. (Note that this is the only edge across which property #3 might
680 // not hold in the entire tree.) Restore property #3.
683 NewRoot
= Tree
->Root
;
684 while (Tmp
!= NewRoot
&& Parent
->Color
== RedBlackTreeRed
) {
685 RED_BLACK_TREE_NODE
*GrandParent
;
686 RED_BLACK_TREE_NODE
*Uncle
;
689 // Tmp is not the root node. Tmp is red. Tmp's parent is red. (Breaking
692 // Due to property #5, Tmp's parent cannot be the root node, hence Tmp's
693 // grandparent exists.
695 // Tmp's grandparent is black, because property #3 is only broken between
696 // Tmp and Tmp's parent.
698 GrandParent
= Parent
->Parent
;
700 if (Parent
== GrandParent
->Left
) {
701 Uncle
= GrandParent
->Right
;
702 if ((Uncle
!= NULL
) && (Uncle
->Color
== RedBlackTreeRed
)) {
704 // GrandParent (black)
706 // Parent (red) Uncle (red)
711 Parent
->Color
= RedBlackTreeBlack
;
712 Uncle
->Color
= RedBlackTreeBlack
;
713 GrandParent
->Color
= RedBlackTreeRed
;
718 // Parent (black) Uncle (black)
722 // We restored property #3 between Tmp and Tmp's parent, without
723 // breaking property #4. However, we may have broken property #3
724 // between Tmp's grandparent and Tmp's great-grandparent (if any), so
725 // repeat the loop for Tmp's grandparent.
727 // If Tmp's grandparent has no parent, then the loop will terminate,
728 // and we will have broken property #5, by coloring the root red. We'll
729 // restore property #5 after the loop, without breaking any others.
732 Parent
= Tmp
->Parent
;
735 // Tmp's uncle is black (satisfied by the case too when Tmp's uncle is
736 // NULL, see property #2).
739 if (Tmp
== Parent
->Right
) {
741 // GrandParent (black): D
743 // Parent (red): A Uncle (black): E
749 // Rotate left, pivoting on node A. This keeps the breakage of
750 // property #3 in the same spot, and keeps other properties intact
751 // (because both Tmp and its parent are red).
754 RedBlackTreeRotateLeft (Tmp
, &NewRoot
);
755 Parent
= Tmp
->Parent
;
758 // With the rotation we reached the same configuration as if Tmp had
759 // been a left child to begin with.
761 // GrandParent (black): D
763 // Parent (red): B Uncle (black): E
765 // Tmp (red): A black: C
767 ASSERT (GrandParent
== Parent
->Parent
);
770 Parent
->Color
= RedBlackTreeBlack
;
771 GrandParent
->Color
= RedBlackTreeRed
;
774 // Property #3 is now restored, but we've broken property #4. Namely,
775 // paths going through node E now see a decrease in black count, while
776 // paths going through node B don't.
778 // GrandParent (red): D
780 // Parent (black): B Uncle (black): E
782 // Tmp (red): A black: C
785 RedBlackTreeRotateRight (GrandParent
, &NewRoot
);
788 // Property #4 has been restored for node E, and preserved for others.
792 // Tmp (red): A [GrandParent] (red): D
794 // black: C [Uncle] (black): E
796 // This configuration terminates the loop because Tmp's parent is now
802 // Symmetrical to the other branch.
804 Uncle
= GrandParent
->Left
;
805 if ((Uncle
!= NULL
) && (Uncle
->Color
== RedBlackTreeRed
)) {
806 Parent
->Color
= RedBlackTreeBlack
;
807 Uncle
->Color
= RedBlackTreeBlack
;
808 GrandParent
->Color
= RedBlackTreeRed
;
810 Parent
= Tmp
->Parent
;
812 if (Tmp
== Parent
->Left
) {
814 RedBlackTreeRotateRight (Tmp
, &NewRoot
);
815 Parent
= Tmp
->Parent
;
816 ASSERT (GrandParent
== Parent
->Parent
);
819 Parent
->Color
= RedBlackTreeBlack
;
820 GrandParent
->Color
= RedBlackTreeRed
;
821 RedBlackTreeRotateLeft (GrandParent
, &NewRoot
);
826 NewRoot
->Color
= RedBlackTreeBlack
;
827 Tree
->Root
= NewRoot
;
828 Status
= RETURN_SUCCESS
;
831 if (FeaturePcdGet (PcdValidateOrderedCollection
)) {
832 RedBlackTreeValidate (Tree
);
839 Check if a node is black, allowing for leaf nodes (see property #2).
841 This is a convenience shorthand.
843 param[in] Node The node to check. Node may be NULL, corresponding to a leaf.
845 @return If Node is NULL or colored black.
849 IN CONST RED_BLACK_TREE_NODE
*Node
852 return (BOOLEAN
)(Node
== NULL
|| Node
->Color
== RedBlackTreeBlack
);
856 Delete a node from the tree, unlinking the associated user structure.
858 Read-write operation.
860 @param[in,out] Tree The tree to delete Node from.
862 @param[in] Node The tree node to delete from Tree. The caller is
863 responsible for ensuring that Node belongs to
864 Tree, and that Node is non-NULL and valid. Node is
865 typically an earlier return value, or output
868 - OrderedCollectionFind(), for deleting a node by
871 - OrderedCollectionMin() / OrderedCollectionMax(),
872 for deleting the minimum / maximum node,
874 - OrderedCollectionNext() /
875 OrderedCollectionPrev(), for deleting a node
876 found during an iteration,
878 - OrderedCollectionInsert() with return value
879 RETURN_ALREADY_STARTED, for deleting a node
880 whose linked user structure caused collision
883 Given a non-empty Tree, Tree->Root is also a valid
884 Node argument (typically used for simplicity in
885 loops that empty the tree completely).
887 Node is released with MemoryAllocationLib's
890 Existing RED_BLACK_TREE_NODE pointers (ie.
891 iterators) *different* from Node remain valid. For
894 - OrderedCollectionNext() /
895 OrderedCollectionPrev() iterations in the caller
896 can be continued from Node, if
897 OrderedCollectionNext() or
898 OrderedCollectionPrev() is called on Node
899 *before* OrderedCollectionDelete() is. That is,
900 fetch the successor / predecessor node first,
903 - On-going iterations in the caller that would
904 have otherwise returned Node at some point, as
905 dictated by user structure order, will correctly
906 reflect the absence of Node after
907 OrderedCollectionDelete() is called
910 @param[out] UserStruct If the caller provides this optional output-only
911 parameter, then on output it is set to the user
912 structure originally linked by Node (which is now
915 This is a convenience that may save the caller a
916 OrderedCollectionUserStruct() invocation before
917 calling OrderedCollectionDelete(), in order to
918 retrieve the user structure being unlinked.
922 OrderedCollectionDelete (
923 IN OUT RED_BLACK_TREE
*Tree
,
924 IN RED_BLACK_TREE_NODE
*Node
,
925 OUT VOID
**UserStruct OPTIONAL
928 RED_BLACK_TREE_NODE
*NewRoot
;
929 RED_BLACK_TREE_NODE
*OrigLeftChild
;
930 RED_BLACK_TREE_NODE
*OrigRightChild
;
931 RED_BLACK_TREE_NODE
*OrigParent
;
932 RED_BLACK_TREE_NODE
*Child
;
933 RED_BLACK_TREE_NODE
*Parent
;
934 RED_BLACK_TREE_COLOR ColorOfUnlinked
;
936 NewRoot
= Tree
->Root
;
937 OrigLeftChild
= Node
->Left
,
938 OrigRightChild
= Node
->Right
,
939 OrigParent
= Node
->Parent
;
941 if (UserStruct
!= NULL
) {
942 *UserStruct
= Node
->UserStruct
;
946 // After this block, no matter which branch we take:
947 // - Child will point to the unique (or NULL) original child of the node that
948 // we will have unlinked,
949 // - Parent will point to the *position* of the original parent of the node
950 // that we will have unlinked.
952 if ((OrigLeftChild
== NULL
) || (OrigRightChild
== NULL
)) {
954 // Node has at most one child. We can connect that child (if any) with
955 // Node's parent (if any), unlinking Node. This will preserve ordering
956 // because the subtree rooted in Node's child (if any) remains on the same
957 // side of Node's parent (if any) that Node was before.
960 Child
= (OrigLeftChild
!= NULL
) ? OrigLeftChild
: OrigRightChild
;
961 ColorOfUnlinked
= Node
->Color
;
964 Child
->Parent
= Parent
;
967 if (OrigParent
== NULL
) {
970 if (Node
== OrigParent
->Left
) {
971 OrigParent
->Left
= Child
;
973 OrigParent
->Right
= Child
;
978 // Node has two children. We unlink Node's successor, and then link it into
979 // Node's place, keeping Node's original color. This preserves ordering
981 // - Node's left subtree is less than Node, hence less than Node's
983 // - Node's right subtree is greater than Node. Node's successor is the
984 // minimum of that subtree, hence Node's successor is less than Node's
985 // right subtree with its minimum removed.
986 // - Node's successor is in Node's subtree, hence it falls on the same side
987 // of Node's parent as Node itself. The relinking doesn't change this
990 RED_BLACK_TREE_NODE
*ToRelink
;
992 ToRelink
= OrigRightChild
;
993 if (ToRelink
->Left
== NULL
) {
995 // OrigRightChild itself is Node's successor, it has no left child:
1001 // OrigLeftChild: A OrigRightChild: E <--- Parent, ToRelink
1005 Parent
= OrigRightChild
;
1006 Child
= OrigRightChild
->Right
;
1009 ToRelink
= ToRelink
->Left
;
1010 } while (ToRelink
->Left
!= NULL
);
1013 // Node's successor is the minimum of OrigRightChild's proper subtree:
1019 // OrigLeftChild: A OrigRightChild: E <--- Parent
1024 Parent
= ToRelink
->Parent
;
1025 Child
= ToRelink
->Right
;
1028 // Unlink Node's successor (ie. ToRelink):
1034 // OrigLeftChild: A OrigRightChild: E <--- Parent
1040 Parent
->Left
= Child
;
1041 if (Child
!= NULL
) {
1042 Child
->Parent
= Parent
;
1046 // We start to link Node's unlinked successor into Node's place:
1050 // Node: B C <--- ToRelink
1052 // OrigLeftChild: A OrigRightChild: E <--- Parent
1058 ToRelink
->Right
= OrigRightChild
;
1059 OrigRightChild
->Parent
= ToRelink
;
1063 // The rest handles both cases, attaching ToRelink (Node's original
1064 // successor) to OrigLeftChild and OrigParent.
1067 // OrigParent ToRelink OrigParent
1069 // Node: B | Node: B Parent
1071 // OrigRightChild: E C <--- ToRelink |
1073 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E
1078 ToRelink
->Left
= OrigLeftChild
;
1079 OrigLeftChild
->Parent
= ToRelink
;
1082 // Node's color must be preserved in Node's original place.
1084 ColorOfUnlinked
= ToRelink
->Color
;
1085 ToRelink
->Color
= Node
->Color
;
1088 // Finish linking Node's unlinked successor into Node's place.
1091 // Node: B ToRelink Node: B
1093 // OrigParent | OrigParent Parent
1095 // OrigRightChild: E C <--- ToRelink |
1097 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E
1102 ToRelink
->Parent
= OrigParent
;
1103 if (OrigParent
== NULL
) {
1106 if (Node
== OrigParent
->Left
) {
1107 OrigParent
->Left
= ToRelink
;
1109 OrigParent
->Right
= ToRelink
;
1117 // If the node that we unlinked from its original spot (ie. Node itself, or
1118 // Node's successor), was red, then we broke neither property #3 nor property
1119 // #4: we didn't create any red-red edge between Child and Parent, and we
1120 // didn't change the black count on any path.
1122 if (ColorOfUnlinked
== RedBlackTreeBlack
) {
1124 // However, if the unlinked node was black, then we have to transfer its
1125 // "black-increment" to its unique child (pointed-to by Child), lest we
1126 // break property #4 for its ancestors.
1128 // If Child is red, we can simply color it black. If Child is black
1129 // already, we can't technically transfer a black-increment to it, due to
1132 // In the following loop we ascend searching for a red node to color black,
1133 // or until we reach the root (in which case we can drop the
1134 // black-increment). Inside the loop body, Child has a black value of 2,
1135 // transitorily breaking property #1 locally, but maintaining property #4
1138 // Rotations in the loop preserve property #4.
1140 while (Child
!= NewRoot
&& NodeIsNullOrBlack (Child
)) {
1141 RED_BLACK_TREE_NODE
*Sibling
;
1142 RED_BLACK_TREE_NODE
*LeftNephew
;
1143 RED_BLACK_TREE_NODE
*RightNephew
;
1145 if (Child
== Parent
->Left
) {
1146 Sibling
= Parent
->Right
;
1148 // Sibling can never be NULL (ie. a leaf).
1150 // If Sibling was NULL, then the black count on the path from Parent to
1151 // Sibling would equal Parent's black value, plus 1 (due to property
1152 // #2). Whereas the black count on the path from Parent to any leaf via
1153 // Child would be at least Parent's black value, plus 2 (due to Child's
1154 // black value of 2). This would clash with property #4.
1156 // (Sibling can be black of course, but it has to be an internal node.
1157 // Internality allows Sibling to have children, bumping the black
1158 // counts of paths that go through it.)
1160 ASSERT (Sibling
!= NULL
);
1161 if (Sibling
->Color
== RedBlackTreeRed
) {
1163 // Sibling's red color implies its children (if any), node C and node
1164 // E, are black (property #3). It also implies that Parent is black.
1166 // grandparent grandparent
1170 // Child,2b:A Sibling,r:D ---> Parent,r:B b:E
1172 // b:C b:E Child,2b:A Sibling,b:C
1174 Sibling
->Color
= RedBlackTreeBlack
;
1175 Parent
->Color
= RedBlackTreeRed
;
1176 RedBlackTreeRotateLeft (Parent
, &NewRoot
);
1177 Sibling
= Parent
->Right
;
1179 // Same reasoning as above.
1181 ASSERT (Sibling
!= NULL
);
1185 // Sibling is black, and not NULL. (Ie. Sibling is a black internal
1188 ASSERT (Sibling
->Color
== RedBlackTreeBlack
);
1189 LeftNephew
= Sibling
->Left
;
1190 RightNephew
= Sibling
->Right
;
1191 if (NodeIsNullOrBlack (LeftNephew
) &&
1192 NodeIsNullOrBlack (RightNephew
))
1195 // In this case we can "steal" one black value from Child and Sibling
1196 // each, and pass it to Parent. "Stealing" means that Sibling (black
1197 // value 1) becomes red, Child (black value 2) becomes singly-black,
1198 // and Parent will have to be examined if it can eat the
1201 // Sibling is allowed to become red because both of its children are
1202 // black (property #3).
1204 // grandparent Parent
1206 // Parent,x:B Child,x:B
1208 // Child,2b:A Sibling,b:D ---> b:A r:D
1210 // LeftNephew,b:C RightNephew,b:E b:C b:E
1212 Sibling
->Color
= RedBlackTreeRed
;
1214 Parent
= Parent
->Parent
;
1216 // Continue ascending.
1220 // At least one nephew is red.
1222 if (NodeIsNullOrBlack (RightNephew
)) {
1224 // Since the right nephew is black, the left nephew is red. Due to
1225 // property #3, LeftNephew has two black children, hence node E is
1228 // Together with the rotation, this enables us to color node F red
1229 // (because property #3 will be satisfied). We flip node D to black
1230 // to maintain property #4.
1232 // grandparent grandparent
1234 // Parent,x:B Parent,x:B
1236 // Child,2b:A Sibling,b:F ---> Child,2b:A Sibling,b:D
1238 // LeftNephew,r:D RightNephew,b:G b:C RightNephew,r:F
1242 LeftNephew
->Color
= RedBlackTreeBlack
;
1243 Sibling
->Color
= RedBlackTreeRed
;
1244 RedBlackTreeRotateRight (Sibling
, &NewRoot
);
1245 Sibling
= Parent
->Right
;
1246 RightNephew
= Sibling
->Right
;
1248 // These operations ensure that...
1253 // ... RightNephew is definitely red here, plus Sibling is (still)
1254 // black and non-NULL.
1256 ASSERT (RightNephew
!= NULL
);
1257 ASSERT (RightNephew
->Color
== RedBlackTreeRed
);
1258 ASSERT (Sibling
!= NULL
);
1259 ASSERT (Sibling
->Color
== RedBlackTreeBlack
);
1261 // In this case we can flush the extra black-increment immediately,
1262 // restoring property #1 for Child (node A): we color RightNephew
1263 // (node E) from red to black.
1265 // In order to maintain property #4, we exchange colors between
1266 // Parent and Sibling (nodes B and D), and rotate left around Parent
1267 // (node B). The transformation doesn't change the black count
1268 // increase incurred by each partial path, eg.
1269 // - ascending from node A: 2 + x == 1 + 1 + x
1270 // - ascending from node C: y + 1 + x == y + 1 + x
1271 // - ascending from node E: 0 + 1 + x == 1 + x
1273 // The color exchange is valid, because even if x stands for red,
1274 // both children of node D are black after the transformation
1275 // (preserving property #3).
1277 // grandparent grandparent
1281 // Child,2b:A Sibling,b:D ---> b:B b:E
1283 // y:C RightNephew,r:E b:A y:C
1286 Sibling
->Color
= Parent
->Color
;
1287 Parent
->Color
= RedBlackTreeBlack
;
1288 RightNephew
->Color
= RedBlackTreeBlack
;
1289 RedBlackTreeRotateLeft (Parent
, &NewRoot
);
1292 // This terminates the loop.
1297 // Mirrors the other branch.
1299 Sibling
= Parent
->Left
;
1300 ASSERT (Sibling
!= NULL
);
1301 if (Sibling
->Color
== RedBlackTreeRed
) {
1302 Sibling
->Color
= RedBlackTreeBlack
;
1303 Parent
->Color
= RedBlackTreeRed
;
1304 RedBlackTreeRotateRight (Parent
, &NewRoot
);
1305 Sibling
= Parent
->Left
;
1306 ASSERT (Sibling
!= NULL
);
1309 ASSERT (Sibling
->Color
== RedBlackTreeBlack
);
1310 RightNephew
= Sibling
->Right
;
1311 LeftNephew
= Sibling
->Left
;
1312 if (NodeIsNullOrBlack (RightNephew
) &&
1313 NodeIsNullOrBlack (LeftNephew
))
1315 Sibling
->Color
= RedBlackTreeRed
;
1317 Parent
= Parent
->Parent
;
1319 if (NodeIsNullOrBlack (LeftNephew
)) {
1320 RightNephew
->Color
= RedBlackTreeBlack
;
1321 Sibling
->Color
= RedBlackTreeRed
;
1322 RedBlackTreeRotateLeft (Sibling
, &NewRoot
);
1323 Sibling
= Parent
->Left
;
1324 LeftNephew
= Sibling
->Left
;
1327 ASSERT (LeftNephew
!= NULL
);
1328 ASSERT (LeftNephew
->Color
== RedBlackTreeRed
);
1329 ASSERT (Sibling
!= NULL
);
1330 ASSERT (Sibling
->Color
== RedBlackTreeBlack
);
1331 Sibling
->Color
= Parent
->Color
;
1332 Parent
->Color
= RedBlackTreeBlack
;
1333 LeftNephew
->Color
= RedBlackTreeBlack
;
1334 RedBlackTreeRotateRight (Parent
, &NewRoot
);
1340 if (Child
!= NULL
) {
1341 Child
->Color
= RedBlackTreeBlack
;
1345 Tree
->Root
= NewRoot
;
1347 if (FeaturePcdGet (PcdValidateOrderedCollection
)) {
1348 RedBlackTreeValidate (Tree
);
1353 Recursively check the red-black tree properties #1 to #4 on a node.
1355 @param[in] Node The root of the subtree to validate.
1357 @retval The black-height of Node's parent.
1360 RedBlackTreeRecursiveCheck (
1361 IN CONST RED_BLACK_TREE_NODE
*Node
1377 ASSERT (Node
->Color
== RedBlackTreeRed
|| Node
->Color
== RedBlackTreeBlack
);
1382 if (Node
->Color
== RedBlackTreeRed
) {
1383 ASSERT (NodeIsNullOrBlack (Node
->Left
));
1384 ASSERT (NodeIsNullOrBlack (Node
->Right
));
1390 LeftHeight
= RedBlackTreeRecursiveCheck (Node
->Left
);
1391 RightHeight
= RedBlackTreeRecursiveCheck (Node
->Right
);
1392 ASSERT (LeftHeight
== RightHeight
);
1394 return (Node
->Color
== RedBlackTreeBlack
) + LeftHeight
;
1398 A slow function that asserts that the tree is a valid red-black tree, and
1399 that it orders user structures correctly.
1401 Read-only operation.
1403 This function uses the stack for recursion and is not recommended for
1406 @param[in] Tree The tree to validate.
1409 RedBlackTreeValidate (
1410 IN CONST RED_BLACK_TREE
*Tree
1414 UINT32 ForwardCount
;
1415 UINT32 BackwardCount
;
1416 CONST RED_BLACK_TREE_NODE
*Last
;
1417 CONST RED_BLACK_TREE_NODE
*Node
;
1419 DEBUG ((DEBUG_VERBOSE
, "%a: Tree=%p\n", __FUNCTION__
, Tree
));
1424 ASSERT (NodeIsNullOrBlack (Tree
->Root
));
1427 // check the other properties
1429 BlackHeight
= RedBlackTreeRecursiveCheck (Tree
->Root
) - 1;
1434 Last
= OrderedCollectionMin (Tree
);
1435 ForwardCount
= (Last
!= NULL
);
1436 for (Node
= OrderedCollectionNext (Last
); Node
!= NULL
;
1437 Node
= OrderedCollectionNext (Last
))
1439 ASSERT (Tree
->UserStructCompare (Last
->UserStruct
, Node
->UserStruct
) < 0);
1445 // backward ordering
1447 Last
= OrderedCollectionMax (Tree
);
1448 BackwardCount
= (Last
!= NULL
);
1449 for (Node
= OrderedCollectionPrev (Last
); Node
!= NULL
;
1450 Node
= OrderedCollectionPrev (Last
))
1452 ASSERT (Tree
->UserStructCompare (Last
->UserStruct
, Node
->UserStruct
) > 0);
1457 ASSERT (ForwardCount
== BackwardCount
);
1461 "%a: Tree=%p BlackHeight=%Ld Count=%Ld\n",