]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.c
MdePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdePkg / Library / BaseOrderedCollectionRedBlackTreeLib / BaseOrderedCollectionRedBlackTreeLib.c
CommitLineData
cf556c6a
LE
1/** @file\r
2 An OrderedCollectionLib instance that provides a red-black tree\r
3 implementation, and allocates and releases tree nodes with\r
4 MemoryAllocationLib.\r
5\r
6 This library instance is useful when a fast associative container is needed.\r
7 Worst case time complexity is O(log n) for Find(), Next(), Prev(), Min(),\r
8 Max(), Insert(), and Delete(), where "n" is the number of elements in the\r
9 tree. Complete ordered traversal takes O(n) time.\r
10\r
11 The implementation is also useful as a fast priority queue.\r
12\r
13 Copyright (C) 2014, Red Hat, Inc.\r
64fabae5 14 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
cf556c6a 15\r
9344f092 16 SPDX-License-Identifier: BSD-2-Clause-Patent\r
cf556c6a
LE
17**/\r
18\r
19#include <Library/OrderedCollectionLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22\r
23typedef enum {\r
24 RedBlackTreeRed,\r
25 RedBlackTreeBlack\r
26} RED_BLACK_TREE_COLOR;\r
27\r
28//\r
29// Incomplete types and convenience typedefs are present in the library class\r
30// header. Beside completing the types, we introduce typedefs here that reflect\r
31// the implementation closely.\r
32//\r
33typedef ORDERED_COLLECTION RED_BLACK_TREE;\r
34typedef ORDERED_COLLECTION_ENTRY RED_BLACK_TREE_NODE;\r
35typedef ORDERED_COLLECTION_USER_COMPARE RED_BLACK_TREE_USER_COMPARE;\r
36typedef ORDERED_COLLECTION_KEY_COMPARE RED_BLACK_TREE_KEY_COMPARE;\r
37\r
38struct ORDERED_COLLECTION {\r
39 RED_BLACK_TREE_NODE *Root;\r
40 RED_BLACK_TREE_USER_COMPARE UserStructCompare;\r
41 RED_BLACK_TREE_KEY_COMPARE KeyCompare;\r
42};\r
43\r
44struct ORDERED_COLLECTION_ENTRY {\r
45 VOID *UserStruct;\r
46 RED_BLACK_TREE_NODE *Parent;\r
47 RED_BLACK_TREE_NODE *Left;\r
48 RED_BLACK_TREE_NODE *Right;\r
49 RED_BLACK_TREE_COLOR Color;\r
50};\r
51\r
52\r
53/**\r
54 Retrieve the user structure linked by the specified tree node.\r
55\r
56 Read-only operation.\r
57\r
58 @param[in] Node Pointer to the tree node whose associated user structure we\r
59 want to retrieve. The caller is responsible for passing a\r
60 non-NULL argument.\r
61\r
62 @return Pointer to user structure linked by Node.\r
63**/\r
64VOID *\r
65EFIAPI\r
66OrderedCollectionUserStruct (\r
67 IN CONST RED_BLACK_TREE_NODE *Node\r
68 )\r
69{\r
70 return Node->UserStruct;\r
71}\r
72\r
64fabae5
ED
73/**\r
74 A slow function that asserts that the tree is a valid red-black tree, and\r
75 that it orders user structures correctly.\r
cf556c6a 76\r
64fabae5
ED
77 Read-only operation.\r
78\r
79 This function uses the stack for recursion and is not recommended for\r
80 "production use".\r
81\r
82 @param[in] Tree The tree to validate.\r
83**/\r
cf556c6a
LE
84VOID\r
85RedBlackTreeValidate (\r
86 IN CONST RED_BLACK_TREE *Tree\r
87 );\r
88\r
89\r
90/**\r
91 Allocate and initialize the RED_BLACK_TREE structure.\r
92\r
93 Allocation occurs via MemoryAllocationLib's AllocatePool() function.\r
94\r
95 @param[in] UserStructCompare This caller-provided function will be used to\r
96 order two user structures linked into the\r
97 tree, during the insertion procedure.\r
98\r
99 @param[in] KeyCompare This caller-provided function will be used to\r
100 order the standalone search key against user\r
101 structures linked into the tree, during the\r
102 lookup procedure.\r
103\r
104 @retval NULL If allocation failed.\r
105\r
106 @return Pointer to the allocated, initialized RED_BLACK_TREE structure,\r
107 otherwise.\r
108**/\r
109RED_BLACK_TREE *\r
110EFIAPI\r
111OrderedCollectionInit (\r
112 IN RED_BLACK_TREE_USER_COMPARE UserStructCompare,\r
113 IN RED_BLACK_TREE_KEY_COMPARE KeyCompare\r
114 )\r
115{\r
116 RED_BLACK_TREE *Tree;\r
117\r
118 Tree = AllocatePool (sizeof *Tree);\r
119 if (Tree == NULL) {\r
120 return NULL;\r
121 }\r
122\r
123 Tree->Root = NULL;\r
124 Tree->UserStructCompare = UserStructCompare;\r
125 Tree->KeyCompare = KeyCompare;\r
126\r
127 if (FeaturePcdGet (PcdValidateOrderedCollection)) {\r
128 RedBlackTreeValidate (Tree);\r
129 }\r
130 return Tree;\r
131}\r
132\r
133\r
134/**\r
135 Check whether the tree is empty (has no nodes).\r
136\r
137 Read-only operation.\r
138\r
139 @param[in] Tree The tree to check for emptiness.\r
140\r
141 @retval TRUE The tree is empty.\r
142\r
143 @retval FALSE The tree is not empty.\r
144**/\r
145BOOLEAN\r
146EFIAPI\r
147OrderedCollectionIsEmpty (\r
148 IN CONST RED_BLACK_TREE *Tree\r
149 )\r
150{\r
6a650d1f 151 return (BOOLEAN)(Tree->Root == NULL);\r
cf556c6a
LE
152}\r
153\r
154\r
155/**\r
156 Uninitialize and release an empty RED_BLACK_TREE structure.\r
157\r
158 Read-write operation.\r
159\r
160 Release occurs via MemoryAllocationLib's FreePool() function.\r
161\r
162 It is the caller's responsibility to delete all nodes from the tree before\r
163 calling this function.\r
164\r
165 @param[in] Tree The empty tree to uninitialize and release.\r
166**/\r
167VOID\r
168EFIAPI\r
169OrderedCollectionUninit (\r
170 IN RED_BLACK_TREE *Tree\r
171 )\r
172{\r
173 ASSERT (OrderedCollectionIsEmpty (Tree));\r
174 FreePool (Tree);\r
175}\r
176\r
177\r
178/**\r
179 Look up the tree node that links the user structure that matches the\r
180 specified standalone key.\r
181\r
182 Read-only operation.\r
183\r
184 @param[in] Tree The tree to search for StandaloneKey.\r
185\r
186 @param[in] StandaloneKey The key to locate among the user structures linked\r
187 into Tree. StandaloneKey will be passed to\r
188 Tree->KeyCompare().\r
189\r
190 @retval NULL StandaloneKey could not be found.\r
191\r
192 @return The tree node that links to the user structure matching\r
193 StandaloneKey, otherwise.\r
194**/\r
195RED_BLACK_TREE_NODE *\r
196EFIAPI\r
197OrderedCollectionFind (\r
198 IN CONST RED_BLACK_TREE *Tree,\r
199 IN CONST VOID *StandaloneKey\r
200 )\r
201{\r
202 RED_BLACK_TREE_NODE *Node;\r
203\r
204 Node = Tree->Root;\r
205 while (Node != NULL) {\r
206 INTN Result;\r
207\r
208 Result = Tree->KeyCompare (StandaloneKey, Node->UserStruct);\r
209 if (Result == 0) {\r
210 break;\r
211 }\r
212 Node = (Result < 0) ? Node->Left : Node->Right;\r
213 }\r
214 return Node;\r
215}\r
216\r
217\r
218/**\r
219 Find the tree node of the minimum user structure stored in the tree.\r
220\r
221 Read-only operation.\r
222\r
223 @param[in] Tree The tree to return the minimum node of. The user structure\r
224 linked by the minimum node compares less than all other user\r
225 structures in the tree.\r
226\r
227 @retval NULL If Tree is empty.\r
228\r
229 @return The tree node that links the minimum user structure, otherwise.\r
230**/\r
231RED_BLACK_TREE_NODE *\r
232EFIAPI\r
233OrderedCollectionMin (\r
234 IN CONST RED_BLACK_TREE *Tree\r
235 )\r
236{\r
237 RED_BLACK_TREE_NODE *Node;\r
238\r
239 Node = Tree->Root;\r
240 if (Node == NULL) {\r
241 return NULL;\r
242 }\r
243 while (Node->Left != NULL) {\r
244 Node = Node->Left;\r
245 }\r
246 return Node;\r
247}\r
248\r
249\r
250/**\r
251 Find the tree node of the maximum user structure stored in the tree.\r
252\r
253 Read-only operation.\r
254\r
255 @param[in] Tree The tree to return the maximum node of. The user structure\r
256 linked by the maximum node compares greater than all other\r
257 user structures in the tree.\r
258\r
259 @retval NULL If Tree is empty.\r
260\r
261 @return The tree node that links the maximum user structure, otherwise.\r
262**/\r
263RED_BLACK_TREE_NODE *\r
264EFIAPI\r
265OrderedCollectionMax (\r
266 IN CONST RED_BLACK_TREE *Tree\r
267 )\r
268{\r
269 RED_BLACK_TREE_NODE *Node;\r
270\r
271 Node = Tree->Root;\r
272 if (Node == NULL) {\r
273 return NULL;\r
274 }\r
275 while (Node->Right != NULL) {\r
276 Node = Node->Right;\r
277 }\r
278 return Node;\r
279}\r
280\r
281\r
282/**\r
283 Get the tree node of the least user structure that is greater than the one\r
284 linked by Node.\r
285\r
286 Read-only operation.\r
287\r
288 @param[in] Node The node to get the successor node of.\r
289\r
290 @retval NULL If Node is NULL, or Node is the maximum node of its containing\r
291 tree (ie. Node has no successor node).\r
292\r
293 @return The tree node linking the least user structure that is greater\r
294 than the one linked by Node, otherwise.\r
295**/\r
296RED_BLACK_TREE_NODE *\r
297EFIAPI\r
298OrderedCollectionNext (\r
299 IN CONST RED_BLACK_TREE_NODE *Node\r
300 )\r
301{\r
302 RED_BLACK_TREE_NODE *Walk;\r
303 CONST RED_BLACK_TREE_NODE *Child;\r
304\r
305 if (Node == NULL) {\r
306 return NULL;\r
307 }\r
308\r
309 //\r
310 // If Node has a right subtree, then the successor is the minimum node of\r
311 // that subtree.\r
312 //\r
313 Walk = Node->Right;\r
314 if (Walk != NULL) {\r
315 while (Walk->Left != NULL) {\r
316 Walk = Walk->Left;\r
317 }\r
318 return Walk;\r
319 }\r
320\r
321 //\r
322 // Otherwise we have to ascend as long as we're our parent's right child (ie.\r
323 // ascending to the left).\r
324 //\r
325 Child = Node;\r
326 Walk = Child->Parent;\r
327 while (Walk != NULL && Child == Walk->Right) {\r
328 Child = Walk;\r
329 Walk = Child->Parent;\r
330 }\r
331 return Walk;\r
332}\r
333\r
334\r
335/**\r
336 Get the tree node of the greatest user structure that is less than the one\r
337 linked by Node.\r
338\r
339 Read-only operation.\r
340\r
341 @param[in] Node The node to get the predecessor node of.\r
342\r
343 @retval NULL If Node is NULL, or Node is the minimum node of its containing\r
344 tree (ie. Node has no predecessor node).\r
345\r
346 @return The tree node linking the greatest user structure that is less\r
347 than the one linked by Node, otherwise.\r
348**/\r
349RED_BLACK_TREE_NODE *\r
350EFIAPI\r
351OrderedCollectionPrev (\r
352 IN CONST RED_BLACK_TREE_NODE *Node\r
353 )\r
354{\r
355 RED_BLACK_TREE_NODE *Walk;\r
356 CONST RED_BLACK_TREE_NODE *Child;\r
357\r
358 if (Node == NULL) {\r
359 return NULL;\r
360 }\r
361\r
362 //\r
363 // If Node has a left subtree, then the predecessor is the maximum node of\r
364 // that subtree.\r
365 //\r
366 Walk = Node->Left;\r
367 if (Walk != NULL) {\r
368 while (Walk->Right != NULL) {\r
369 Walk = Walk->Right;\r
370 }\r
371 return Walk;\r
372 }\r
373\r
374 //\r
375 // Otherwise we have to ascend as long as we're our parent's left child (ie.\r
376 // ascending to the right).\r
377 //\r
378 Child = Node;\r
379 Walk = Child->Parent;\r
380 while (Walk != NULL && Child == Walk->Left) {\r
381 Child = Walk;\r
382 Walk = Child->Parent;\r
383 }\r
384 return Walk;\r
385}\r
386\r
387\r
388/**\r
389 Rotate tree nodes around Pivot to the right.\r
390\r
391 Parent Parent\r
392 | |\r
393 Pivot LeftChild\r
394 / . . \_\r
395 LeftChild Node1 ---> Node2 Pivot\r
396 . \ / .\r
397 Node2 LeftRightChild LeftRightChild Node1\r
398\r
399 The ordering Node2 < LeftChild < LeftRightChild < Pivot < Node1 is kept\r
400 intact. Parent (if any) is either at the left extreme or the right extreme of\r
401 this ordering, and that relation is also kept intact.\r
402\r
403 Edges marked with a dot (".") don't change during rotation.\r
404\r
405 Internal read-write operation.\r
406\r
407 @param[in,out] Pivot The tree node to rotate other nodes right around. It\r
408 is the caller's responsibility to ensure that\r
409 Pivot->Left is not NULL.\r
410\r
411 @param[out] NewRoot If Pivot has a parent node on input, then the\r
412 function updates Pivot's original parent on output\r
413 according to the rotation, and NewRoot is not\r
414 accessed.\r
415\r
416 If Pivot has no parent node on input (ie. Pivot is\r
417 the root of the tree), then the function stores the\r
418 new root node of the tree in NewRoot.\r
419**/\r
cf556c6a
LE
420VOID\r
421RedBlackTreeRotateRight (\r
422 IN OUT RED_BLACK_TREE_NODE *Pivot,\r
423 OUT RED_BLACK_TREE_NODE **NewRoot\r
424 )\r
425{\r
64fabae5
ED
426 RED_BLACK_TREE_NODE *Parent;\r
427 RED_BLACK_TREE_NODE *LeftChild;\r
428 RED_BLACK_TREE_NODE *LeftRightChild;\r
cf556c6a
LE
429\r
430 Parent = Pivot->Parent;\r
431 LeftChild = Pivot->Left;\r
432 LeftRightChild = LeftChild->Right;\r
433\r
434 Pivot->Left = LeftRightChild;\r
435 if (LeftRightChild != NULL) {\r
436 LeftRightChild->Parent = Pivot;\r
437 }\r
438 LeftChild->Parent = Parent;\r
439 if (Parent == NULL) {\r
440 *NewRoot = LeftChild;\r
441 } else {\r
442 if (Pivot == Parent->Left) {\r
443 Parent->Left = LeftChild;\r
444 } else {\r
445 Parent->Right = LeftChild;\r
446 }\r
447 }\r
448 LeftChild->Right = Pivot;\r
449 Pivot->Parent = LeftChild;\r
450}\r
451\r
452\r
453/**\r
454 Rotate tree nodes around Pivot to the left.\r
455\r
456 Parent Parent\r
457 | |\r
458 Pivot RightChild\r
459 . \ / .\r
460 Node1 RightChild ---> Pivot Node2\r
461 /. . \_\r
462 RightLeftChild Node2 Node1 RightLeftChild\r
463\r
464 The ordering Node1 < Pivot < RightLeftChild < RightChild < Node2 is kept\r
465 intact. Parent (if any) is either at the left extreme or the right extreme of\r
466 this ordering, and that relation is also kept intact.\r
467\r
468 Edges marked with a dot (".") don't change during rotation.\r
469\r
470 Internal read-write operation.\r
471\r
472 @param[in,out] Pivot The tree node to rotate other nodes left around. It\r
473 is the caller's responsibility to ensure that\r
474 Pivot->Right is not NULL.\r
475\r
476 @param[out] NewRoot If Pivot has a parent node on input, then the\r
477 function updates Pivot's original parent on output\r
478 according to the rotation, and NewRoot is not\r
479 accessed.\r
480\r
481 If Pivot has no parent node on input (ie. Pivot is\r
482 the root of the tree), then the function stores the\r
483 new root node of the tree in NewRoot.\r
484**/\r
cf556c6a
LE
485VOID\r
486RedBlackTreeRotateLeft (\r
487 IN OUT RED_BLACK_TREE_NODE *Pivot,\r
488 OUT RED_BLACK_TREE_NODE **NewRoot\r
489 )\r
490{\r
64fabae5
ED
491 RED_BLACK_TREE_NODE *Parent;\r
492 RED_BLACK_TREE_NODE *RightChild;\r
493 RED_BLACK_TREE_NODE *RightLeftChild;\r
cf556c6a
LE
494\r
495 Parent = Pivot->Parent;\r
496 RightChild = Pivot->Right;\r
497 RightLeftChild = RightChild->Left;\r
498\r
499 Pivot->Right = RightLeftChild;\r
500 if (RightLeftChild != NULL) {\r
501 RightLeftChild->Parent = Pivot;\r
502 }\r
503 RightChild->Parent = Parent;\r
504 if (Parent == NULL) {\r
505 *NewRoot = RightChild;\r
506 } else {\r
507 if (Pivot == Parent->Left) {\r
508 Parent->Left = RightChild;\r
509 } else {\r
510 Parent->Right = RightChild;\r
511 }\r
512 }\r
513 RightChild->Left = Pivot;\r
514 Pivot->Parent = RightChild;\r
515}\r
516\r
517\r
518/**\r
519 Insert (link) a user structure into the tree.\r
520\r
521 Read-write operation.\r
522\r
523 This function allocates the new tree node with MemoryAllocationLib's\r
524 AllocatePool() function.\r
525\r
526 @param[in,out] Tree The tree to insert UserStruct into.\r
527\r
528 @param[out] Node The meaning of this optional, output-only\r
529 parameter depends on the return value of the\r
530 function.\r
531\r
532 When insertion is successful (RETURN_SUCCESS),\r
533 Node is set on output to the new tree node that\r
534 now links UserStruct.\r
535\r
536 When insertion fails due to lack of memory\r
537 (RETURN_OUT_OF_RESOURCES), Node is not changed.\r
538\r
539 When insertion fails due to key collision (ie.\r
540 another user structure is already in the tree that\r
541 compares equal to UserStruct), with return value\r
542 RETURN_ALREADY_STARTED, then Node is set on output\r
543 to the node that links the colliding user\r
544 structure. This enables "find-or-insert" in one\r
545 function call, or helps with later removal of the\r
546 colliding element.\r
547\r
548 @param[in] UserStruct The user structure to link into the tree.\r
549 UserStruct is ordered against in-tree user\r
550 structures with the Tree->UserStructCompare()\r
551 function.\r
552\r
553 @retval RETURN_SUCCESS Insertion successful. A new tree node has\r
554 been allocated, linking UserStruct. The new\r
555 tree node is reported back in Node (if the\r
556 caller requested it).\r
557\r
558 Existing RED_BLACK_TREE_NODE pointers into\r
559 Tree remain valid. For example, on-going\r
560 iterations in the caller can continue with\r
561 OrderedCollectionNext() /\r
562 OrderedCollectionPrev(), and they will\r
563 return the new node at some point if user\r
564 structure order dictates it.\r
565\r
566 @retval RETURN_OUT_OF_RESOURCES AllocatePool() failed to allocate memory for\r
567 the new tree node. The tree has not been\r
568 changed. Existing RED_BLACK_TREE_NODE\r
569 pointers into Tree remain valid.\r
570\r
571 @retval RETURN_ALREADY_STARTED A user structure has been found in the tree\r
572 that compares equal to UserStruct. The node\r
573 linking the colliding user structure is\r
574 reported back in Node (if the caller\r
575 requested it). The tree has not been\r
576 changed. Existing RED_BLACK_TREE_NODE\r
577 pointers into Tree remain valid.\r
578**/\r
579RETURN_STATUS\r
580EFIAPI\r
581OrderedCollectionInsert (\r
582 IN OUT RED_BLACK_TREE *Tree,\r
583 OUT RED_BLACK_TREE_NODE **Node OPTIONAL,\r
584 IN VOID *UserStruct\r
585 )\r
586{\r
64fabae5
ED
587 RED_BLACK_TREE_NODE *Tmp;\r
588 RED_BLACK_TREE_NODE *Parent;\r
cf556c6a
LE
589 INTN Result;\r
590 RETURN_STATUS Status;\r
591 RED_BLACK_TREE_NODE *NewRoot;\r
592\r
593 Tmp = Tree->Root;\r
594 Parent = NULL;\r
75955444 595 Result = 0;\r
cf556c6a
LE
596\r
597 //\r
598 // First look for a collision, saving the last examined node for the case\r
599 // when there's no collision.\r
600 //\r
601 while (Tmp != NULL) {\r
602 Result = Tree->UserStructCompare (UserStruct, Tmp->UserStruct);\r
603 if (Result == 0) {\r
604 break;\r
605 }\r
606 Parent = Tmp;\r
607 Tmp = (Result < 0) ? Tmp->Left : Tmp->Right;\r
608 }\r
609\r
610 if (Tmp != NULL) {\r
611 if (Node != NULL) {\r
612 *Node = Tmp;\r
613 }\r
614 Status = RETURN_ALREADY_STARTED;\r
615 goto Done;\r
616 }\r
617\r
618 //\r
619 // no collision, allocate a new node\r
620 //\r
621 Tmp = AllocatePool (sizeof *Tmp);\r
622 if (Tmp == NULL) {\r
623 Status = RETURN_OUT_OF_RESOURCES;\r
624 goto Done;\r
625 }\r
626 if (Node != NULL) {\r
627 *Node = Tmp;\r
628 }\r
629\r
630 //\r
631 // reference the user structure from the node\r
632 //\r
633 Tmp->UserStruct = UserStruct;\r
634\r
635 //\r
636 // Link the node as a child to the correct side of the parent.\r
637 // If there's no parent, the new node is the root node in the tree.\r
638 //\r
639 Tmp->Parent = Parent;\r
640 Tmp->Left = NULL;\r
641 Tmp->Right = NULL;\r
642 if (Parent == NULL) {\r
643 Tree->Root = Tmp;\r
644 Tmp->Color = RedBlackTreeBlack;\r
645 Status = RETURN_SUCCESS;\r
646 goto Done;\r
647 }\r
648 if (Result < 0) {\r
649 Parent->Left = Tmp;\r
650 } else {\r
651 Parent->Right = Tmp;\r
652 }\r
653 Tmp->Color = RedBlackTreeRed;\r
654\r
655 //\r
656 // Red-black tree properties:\r
657 //\r
658 // #1 Each node is either red or black (RED_BLACK_TREE_NODE.Color).\r
659 //\r
660 // #2 Each leaf (ie. a pseudo-node pointed-to by a NULL valued\r
661 // RED_BLACK_TREE_NODE.Left or RED_BLACK_TREE_NODE.Right field) is black.\r
662 //\r
663 // #3 Each red node has two black children.\r
664 //\r
665 // #4 For any node N, and for any leaves L1 and L2 reachable from N, the\r
666 // paths N..L1 and N..L2 contain the same number of black nodes.\r
667 //\r
668 // #5 The root node is black.\r
669 //\r
670 // By replacing a leaf with a red node above, only property #3 may have been\r
671 // broken. (Note that this is the only edge across which property #3 might\r
672 // not hold in the entire tree.) Restore property #3.\r
673 //\r
674\r
675 NewRoot = Tree->Root;\r
676 while (Tmp != NewRoot && Parent->Color == RedBlackTreeRed) {\r
64fabae5
ED
677 RED_BLACK_TREE_NODE *GrandParent;\r
678 RED_BLACK_TREE_NODE *Uncle;\r
cf556c6a
LE
679\r
680 //\r
681 // Tmp is not the root node. Tmp is red. Tmp's parent is red. (Breaking\r
682 // property #3.)\r
683 //\r
684 // Due to property #5, Tmp's parent cannot be the root node, hence Tmp's\r
685 // grandparent exists.\r
686 //\r
687 // Tmp's grandparent is black, because property #3 is only broken between\r
688 // Tmp and Tmp's parent.\r
689 //\r
690 GrandParent = Parent->Parent;\r
691\r
692 if (Parent == GrandParent->Left) {\r
693 Uncle = GrandParent->Right;\r
694 if (Uncle != NULL && Uncle->Color == RedBlackTreeRed) {\r
695 //\r
696 // GrandParent (black)\r
697 // / \_\r
698 // Parent (red) Uncle (red)\r
699 // |\r
700 // Tmp (red)\r
701 //\r
702\r
703 Parent->Color = RedBlackTreeBlack;\r
704 Uncle->Color = RedBlackTreeBlack;\r
705 GrandParent->Color = RedBlackTreeRed;\r
706\r
707 //\r
708 // GrandParent (red)\r
709 // / \_\r
710 // Parent (black) Uncle (black)\r
711 // |\r
712 // Tmp (red)\r
713 //\r
714 // We restored property #3 between Tmp and Tmp's parent, without\r
715 // breaking property #4. However, we may have broken property #3\r
716 // between Tmp's grandparent and Tmp's great-grandparent (if any), so\r
717 // repeat the loop for Tmp's grandparent.\r
718 //\r
719 // If Tmp's grandparent has no parent, then the loop will terminate,\r
720 // and we will have broken property #5, by coloring the root red. We'll\r
721 // restore property #5 after the loop, without breaking any others.\r
722 //\r
723 Tmp = GrandParent;\r
724 Parent = Tmp->Parent;\r
725 } else {\r
726 //\r
727 // Tmp's uncle is black (satisfied by the case too when Tmp's uncle is\r
728 // NULL, see property #2).\r
729 //\r
730\r
731 if (Tmp == Parent->Right) {\r
732 //\r
733 // GrandParent (black): D\r
734 // / \_\r
735 // Parent (red): A Uncle (black): E\r
736 // \_\r
737 // Tmp (red): B\r
738 // \_\r
739 // black: C\r
740 //\r
741 // Rotate left, pivoting on node A. This keeps the breakage of\r
742 // property #3 in the same spot, and keeps other properties intact\r
743 // (because both Tmp and its parent are red).\r
744 //\r
745 Tmp = Parent;\r
746 RedBlackTreeRotateLeft (Tmp, &NewRoot);\r
747 Parent = Tmp->Parent;\r
748\r
749 //\r
750 // With the rotation we reached the same configuration as if Tmp had\r
751 // been a left child to begin with.\r
752 //\r
753 // GrandParent (black): D\r
754 // / \_\r
755 // Parent (red): B Uncle (black): E\r
756 // / \_\r
757 // Tmp (red): A black: C\r
758 //\r
759 ASSERT (GrandParent == Parent->Parent);\r
760 }\r
761\r
762 Parent->Color = RedBlackTreeBlack;\r
763 GrandParent->Color = RedBlackTreeRed;\r
764\r
765 //\r
766 // Property #3 is now restored, but we've broken property #4. Namely,\r
767 // paths going through node E now see a decrease in black count, while\r
768 // paths going through node B don't.\r
769 //\r
770 // GrandParent (red): D\r
771 // / \_\r
772 // Parent (black): B Uncle (black): E\r
773 // / \_\r
774 // Tmp (red): A black: C\r
775 //\r
776\r
777 RedBlackTreeRotateRight (GrandParent, &NewRoot);\r
778\r
779 //\r
780 // Property #4 has been restored for node E, and preserved for others.\r
781 //\r
782 // Parent (black): B\r
783 // / \_\r
784 // Tmp (red): A [GrandParent] (red): D\r
785 // / \_\r
786 // black: C [Uncle] (black): E\r
787 //\r
788 // This configuration terminates the loop because Tmp's parent is now\r
789 // black.\r
790 //\r
791 }\r
792 } else {\r
793 //\r
794 // Symmetrical to the other branch.\r
795 //\r
796 Uncle = GrandParent->Left;\r
797 if (Uncle != NULL && Uncle->Color == RedBlackTreeRed) {\r
798 Parent->Color = RedBlackTreeBlack;\r
799 Uncle->Color = RedBlackTreeBlack;\r
800 GrandParent->Color = RedBlackTreeRed;\r
801 Tmp = GrandParent;\r
802 Parent = Tmp->Parent;\r
803 } else {\r
804 if (Tmp == Parent->Left) {\r
805 Tmp = Parent;\r
806 RedBlackTreeRotateRight (Tmp, &NewRoot);\r
807 Parent = Tmp->Parent;\r
808 ASSERT (GrandParent == Parent->Parent);\r
809 }\r
810 Parent->Color = RedBlackTreeBlack;\r
811 GrandParent->Color = RedBlackTreeRed;\r
812 RedBlackTreeRotateLeft (GrandParent, &NewRoot);\r
813 }\r
814 }\r
815 }\r
816\r
817 NewRoot->Color = RedBlackTreeBlack;\r
818 Tree->Root = NewRoot;\r
819 Status = RETURN_SUCCESS;\r
820\r
821Done:\r
822 if (FeaturePcdGet (PcdValidateOrderedCollection)) {\r
823 RedBlackTreeValidate (Tree);\r
824 }\r
825 return Status;\r
826}\r
827\r
828\r
829/**\r
830 Check if a node is black, allowing for leaf nodes (see property #2).\r
831\r
832 This is a convenience shorthand.\r
833\r
834 param[in] Node The node to check. Node may be NULL, corresponding to a leaf.\r
835\r
836 @return If Node is NULL or colored black.\r
837**/\r
cf556c6a
LE
838BOOLEAN\r
839NodeIsNullOrBlack (\r
840 IN CONST RED_BLACK_TREE_NODE *Node\r
841 )\r
842{\r
6a650d1f 843 return (BOOLEAN)(Node == NULL || Node->Color == RedBlackTreeBlack);\r
cf556c6a
LE
844}\r
845\r
846\r
847/**\r
848 Delete a node from the tree, unlinking the associated user structure.\r
849\r
850 Read-write operation.\r
851\r
852 @param[in,out] Tree The tree to delete Node from.\r
853\r
854 @param[in] Node The tree node to delete from Tree. The caller is\r
855 responsible for ensuring that Node belongs to\r
856 Tree, and that Node is non-NULL and valid. Node is\r
857 typically an earlier return value, or output\r
858 parameter, of:\r
859\r
860 - OrderedCollectionFind(), for deleting a node by\r
861 user structure key,\r
862\r
863 - OrderedCollectionMin() / OrderedCollectionMax(),\r
864 for deleting the minimum / maximum node,\r
865\r
866 - OrderedCollectionNext() /\r
867 OrderedCollectionPrev(), for deleting a node\r
868 found during an iteration,\r
869\r
870 - OrderedCollectionInsert() with return value\r
871 RETURN_ALREADY_STARTED, for deleting a node\r
872 whose linked user structure caused collision\r
873 during insertion.\r
874\r
875 Given a non-empty Tree, Tree->Root is also a valid\r
876 Node argument (typically used for simplicity in\r
877 loops that empty the tree completely).\r
878\r
879 Node is released with MemoryAllocationLib's\r
880 FreePool() function.\r
881\r
882 Existing RED_BLACK_TREE_NODE pointers (ie.\r
883 iterators) *different* from Node remain valid. For\r
884 example:\r
885\r
886 - OrderedCollectionNext() /\r
887 OrderedCollectionPrev() iterations in the caller\r
888 can be continued from Node, if\r
889 OrderedCollectionNext() or\r
890 OrderedCollectionPrev() is called on Node\r
891 *before* OrderedCollectionDelete() is. That is,\r
892 fetch the successor / predecessor node first,\r
893 then delete Node.\r
894\r
895 - On-going iterations in the caller that would\r
896 have otherwise returned Node at some point, as\r
897 dictated by user structure order, will correctly\r
898 reflect the absence of Node after\r
899 OrderedCollectionDelete() is called\r
900 mid-iteration.\r
901\r
902 @param[out] UserStruct If the caller provides this optional output-only\r
903 parameter, then on output it is set to the user\r
904 structure originally linked by Node (which is now\r
905 freed).\r
906\r
907 This is a convenience that may save the caller a\r
908 OrderedCollectionUserStruct() invocation before\r
909 calling OrderedCollectionDelete(), in order to\r
910 retrieve the user structure being unlinked.\r
911**/\r
912VOID\r
913EFIAPI\r
914OrderedCollectionDelete (\r
915 IN OUT RED_BLACK_TREE *Tree,\r
916 IN RED_BLACK_TREE_NODE *Node,\r
917 OUT VOID **UserStruct OPTIONAL\r
918 )\r
919{\r
920 RED_BLACK_TREE_NODE *NewRoot;\r
64fabae5
ED
921 RED_BLACK_TREE_NODE *OrigLeftChild;\r
922 RED_BLACK_TREE_NODE *OrigRightChild;\r
923 RED_BLACK_TREE_NODE *OrigParent;\r
924 RED_BLACK_TREE_NODE *Child;\r
925 RED_BLACK_TREE_NODE *Parent;\r
cf556c6a
LE
926 RED_BLACK_TREE_COLOR ColorOfUnlinked;\r
927\r
928 NewRoot = Tree->Root;\r
929 OrigLeftChild = Node->Left,\r
930 OrigRightChild = Node->Right,\r
931 OrigParent = Node->Parent;\r
932\r
933 if (UserStruct != NULL) {\r
934 *UserStruct = Node->UserStruct;\r
935 }\r
936\r
937 //\r
938 // After this block, no matter which branch we take:\r
939 // - Child will point to the unique (or NULL) original child of the node that\r
940 // we will have unlinked,\r
941 // - Parent will point to the *position* of the original parent of the node\r
942 // that we will have unlinked.\r
943 //\r
944 if (OrigLeftChild == NULL || OrigRightChild == NULL) {\r
945 //\r
946 // Node has at most one child. We can connect that child (if any) with\r
947 // Node's parent (if any), unlinking Node. This will preserve ordering\r
948 // because the subtree rooted in Node's child (if any) remains on the same\r
949 // side of Node's parent (if any) that Node was before.\r
950 //\r
951 Parent = OrigParent;\r
952 Child = (OrigLeftChild != NULL) ? OrigLeftChild : OrigRightChild;\r
953 ColorOfUnlinked = Node->Color;\r
954\r
955 if (Child != NULL) {\r
956 Child->Parent = Parent;\r
957 }\r
958 if (OrigParent == NULL) {\r
959 NewRoot = Child;\r
960 } else {\r
961 if (Node == OrigParent->Left) {\r
962 OrigParent->Left = Child;\r
963 } else {\r
964 OrigParent->Right = Child;\r
965 }\r
966 }\r
967 } else {\r
968 //\r
969 // Node has two children. We unlink Node's successor, and then link it into\r
970 // Node's place, keeping Node's original color. This preserves ordering\r
971 // because:\r
972 // - Node's left subtree is less than Node, hence less than Node's\r
973 // successor.\r
974 // - Node's right subtree is greater than Node. Node's successor is the\r
975 // minimum of that subtree, hence Node's successor is less than Node's\r
976 // right subtree with its minimum removed.\r
977 // - Node's successor is in Node's subtree, hence it falls on the same side\r
978 // of Node's parent as Node itself. The relinking doesn't change this\r
979 // relation.\r
980 //\r
981 RED_BLACK_TREE_NODE *ToRelink;\r
982\r
983 ToRelink = OrigRightChild;\r
984 if (ToRelink->Left == NULL) {\r
985 //\r
986 // OrigRightChild itself is Node's successor, it has no left child:\r
987 //\r
988 // OrigParent\r
989 // |\r
990 // Node: B\r
991 // / \_\r
992 // OrigLeftChild: A OrigRightChild: E <--- Parent, ToRelink\r
993 // \_\r
994 // F <--- Child\r
995 //\r
996 Parent = OrigRightChild;\r
997 Child = OrigRightChild->Right;\r
998 } else {\r
999 do {\r
1000 ToRelink = ToRelink->Left;\r
1001 } while (ToRelink->Left != NULL);\r
1002\r
1003 //\r
1004 // Node's successor is the minimum of OrigRightChild's proper subtree:\r
1005 //\r
1006 // OrigParent\r
1007 // |\r
1008 // Node: B\r
1009 // / \_\r
1010 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1011 // /\r
1012 // C <--- ToRelink\r
1013 // \_\r
1014 // D <--- Child\r
1015 Parent = ToRelink->Parent;\r
1016 Child = ToRelink->Right;\r
1017\r
1018 //\r
1019 // Unlink Node's successor (ie. ToRelink):\r
1020 //\r
1021 // OrigParent\r
1022 // |\r
1023 // Node: B\r
1024 // / \_\r
1025 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1026 // /\r
1027 // D <--- Child\r
1028 //\r
1029 // C <--- ToRelink\r
1030 //\r
1031 Parent->Left = Child;\r
64fabae5 1032 if (Child != NULL) {\r
cf556c6a
LE
1033 Child->Parent = Parent;\r
1034 }\r
1035\r
1036 //\r
1037 // We start to link Node's unlinked successor into Node's place:\r
1038 //\r
1039 // OrigParent\r
1040 // |\r
1041 // Node: B C <--- ToRelink\r
1042 // / \_\r
1043 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1044 // /\r
1045 // D <--- Child\r
1046 //\r
1047 //\r
1048 //\r
1049 ToRelink->Right = OrigRightChild;\r
1050 OrigRightChild->Parent = ToRelink;\r
1051 }\r
1052\r
1053 //\r
1054 // The rest handles both cases, attaching ToRelink (Node's original\r
1055 // successor) to OrigLeftChild and OrigParent.\r
1056 //\r
1057 // Parent,\r
1058 // OrigParent ToRelink OrigParent\r
1059 // | | |\r
1060 // Node: B | Node: B Parent\r
1061 // v |\r
1062 // OrigRightChild: E C <--- ToRelink |\r
1063 // / \ / \ v\r
1064 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E\r
1065 // ^ /\r
1066 // | D <--- Child\r
1067 // Child\r
1068 //\r
1069 ToRelink->Left = OrigLeftChild;\r
1070 OrigLeftChild->Parent = ToRelink;\r
1071\r
1072 //\r
1073 // Node's color must be preserved in Node's original place.\r
1074 //\r
1075 ColorOfUnlinked = ToRelink->Color;\r
1076 ToRelink->Color = Node->Color;\r
1077\r
1078 //\r
1079 // Finish linking Node's unlinked successor into Node's place.\r
1080 //\r
1081 // Parent,\r
1082 // Node: B ToRelink Node: B\r
1083 // |\r
1084 // OrigParent | OrigParent Parent\r
1085 // | v | |\r
1086 // OrigRightChild: E C <--- ToRelink |\r
1087 // / \ / \ v\r
1088 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E\r
1089 // ^ /\r
1090 // | D <--- Child\r
1091 // Child\r
1092 //\r
1093 ToRelink->Parent = OrigParent;\r
1094 if (OrigParent == NULL) {\r
1095 NewRoot = ToRelink;\r
1096 } else {\r
1097 if (Node == OrigParent->Left) {\r
1098 OrigParent->Left = ToRelink;\r
1099 } else {\r
1100 OrigParent->Right = ToRelink;\r
1101 }\r
1102 }\r
1103 }\r
1104\r
1105 FreePool (Node);\r
1106\r
1107 //\r
1108 // If the node that we unlinked from its original spot (ie. Node itself, or\r
1109 // Node's successor), was red, then we broke neither property #3 nor property\r
1110 // #4: we didn't create any red-red edge between Child and Parent, and we\r
1111 // didn't change the black count on any path.\r
1112 //\r
1113 if (ColorOfUnlinked == RedBlackTreeBlack) {\r
1114 //\r
1115 // However, if the unlinked node was black, then we have to transfer its\r
1116 // "black-increment" to its unique child (pointed-to by Child), lest we\r
1117 // break property #4 for its ancestors.\r
1118 //\r
1119 // If Child is red, we can simply color it black. If Child is black\r
1120 // already, we can't technically transfer a black-increment to it, due to\r
1121 // property #1.\r
1122 //\r
1123 // In the following loop we ascend searching for a red node to color black,\r
1124 // or until we reach the root (in which case we can drop the\r
1125 // black-increment). Inside the loop body, Child has a black value of 2,\r
1126 // transitorily breaking property #1 locally, but maintaining property #4\r
1127 // globally.\r
1128 //\r
1129 // Rotations in the loop preserve property #4.\r
1130 //\r
1131 while (Child != NewRoot && NodeIsNullOrBlack (Child)) {\r
64fabae5
ED
1132 RED_BLACK_TREE_NODE *Sibling;\r
1133 RED_BLACK_TREE_NODE *LeftNephew;\r
1134 RED_BLACK_TREE_NODE *RightNephew;\r
cf556c6a
LE
1135\r
1136 if (Child == Parent->Left) {\r
1137 Sibling = Parent->Right;\r
1138 //\r
1139 // Sibling can never be NULL (ie. a leaf).\r
1140 //\r
1141 // If Sibling was NULL, then the black count on the path from Parent to\r
1142 // Sibling would equal Parent's black value, plus 1 (due to property\r
1143 // #2). Whereas the black count on the path from Parent to any leaf via\r
1144 // Child would be at least Parent's black value, plus 2 (due to Child's\r
1145 // black value of 2). This would clash with property #4.\r
1146 //\r
1147 // (Sibling can be black of course, but it has to be an internal node.\r
1148 // Internality allows Sibling to have children, bumping the black\r
1149 // counts of paths that go through it.)\r
1150 //\r
1151 ASSERT (Sibling != NULL);\r
1152 if (Sibling->Color == RedBlackTreeRed) {\r
1153 //\r
1154 // Sibling's red color implies its children (if any), node C and node\r
1155 // E, are black (property #3). It also implies that Parent is black.\r
1156 //\r
1157 // grandparent grandparent\r
1158 // | |\r
1159 // Parent,b:B b:D\r
1160 // / \ / \_\r
1161 // Child,2b:A Sibling,r:D ---> Parent,r:B b:E\r
1162 // /\ /\_\r
1163 // b:C b:E Child,2b:A Sibling,b:C\r
1164 //\r
1165 Sibling->Color = RedBlackTreeBlack;\r
1166 Parent->Color = RedBlackTreeRed;\r
1167 RedBlackTreeRotateLeft (Parent, &NewRoot);\r
1168 Sibling = Parent->Right;\r
1169 //\r
1170 // Same reasoning as above.\r
1171 //\r
1172 ASSERT (Sibling != NULL);\r
1173 }\r
1174\r
1175 //\r
1176 // Sibling is black, and not NULL. (Ie. Sibling is a black internal\r
1177 // node.)\r
1178 //\r
1179 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1180 LeftNephew = Sibling->Left;\r
1181 RightNephew = Sibling->Right;\r
1182 if (NodeIsNullOrBlack (LeftNephew) &&\r
1183 NodeIsNullOrBlack (RightNephew)) {\r
1184 //\r
1185 // In this case we can "steal" one black value from Child and Sibling\r
1186 // each, and pass it to Parent. "Stealing" means that Sibling (black\r
1187 // value 1) becomes red, Child (black value 2) becomes singly-black,\r
1188 // and Parent will have to be examined if it can eat the\r
1189 // black-increment.\r
1190 //\r
1191 // Sibling is allowed to become red because both of its children are\r
1192 // black (property #3).\r
1193 //\r
1194 // grandparent Parent\r
1195 // | |\r
1196 // Parent,x:B Child,x:B\r
1197 // / \ / \_\r
1198 // Child,2b:A Sibling,b:D ---> b:A r:D\r
1199 // /\ /\_\r
1200 // LeftNephew,b:C RightNephew,b:E b:C b:E\r
1201 //\r
1202 Sibling->Color = RedBlackTreeRed;\r
1203 Child = Parent;\r
1204 Parent = Parent->Parent;\r
1205 //\r
1206 // Continue ascending.\r
1207 //\r
1208 } else {\r
1209 //\r
1210 // At least one nephew is red.\r
1211 //\r
1212 if (NodeIsNullOrBlack (RightNephew)) {\r
1213 //\r
1214 // Since the right nephew is black, the left nephew is red. Due to\r
1215 // property #3, LeftNephew has two black children, hence node E is\r
1216 // black.\r
1217 //\r
1218 // Together with the rotation, this enables us to color node F red\r
1219 // (because property #3 will be satisfied). We flip node D to black\r
1220 // to maintain property #4.\r
1221 //\r
1222 // grandparent grandparent\r
1223 // | |\r
1224 // Parent,x:B Parent,x:B\r
1225 // /\ /\_\r
1226 // Child,2b:A Sibling,b:F ---> Child,2b:A Sibling,b:D\r
1227 // /\ / \_\r
1228 // LeftNephew,r:D RightNephew,b:G b:C RightNephew,r:F\r
1229 // /\ /\_\r
1230 // b:C b:E b:E b:G\r
1231 //\r
1232 LeftNephew->Color = RedBlackTreeBlack;\r
1233 Sibling->Color = RedBlackTreeRed;\r
1234 RedBlackTreeRotateRight (Sibling, &NewRoot);\r
1235 Sibling = Parent->Right;\r
1236 RightNephew = Sibling->Right;\r
1237 //\r
1238 // These operations ensure that...\r
1239 //\r
1240 }\r
1241 //\r
1242 // ... RightNephew is definitely red here, plus Sibling is (still)\r
1243 // black and non-NULL.\r
1244 //\r
1245 ASSERT (RightNephew != NULL);\r
1246 ASSERT (RightNephew->Color == RedBlackTreeRed);\r
1247 ASSERT (Sibling != NULL);\r
1248 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1249 //\r
1250 // In this case we can flush the extra black-increment immediately,\r
1251 // restoring property #1 for Child (node A): we color RightNephew\r
1252 // (node E) from red to black.\r
1253 //\r
1254 // In order to maintain property #4, we exchange colors between\r
1255 // Parent and Sibling (nodes B and D), and rotate left around Parent\r
1256 // (node B). The transformation doesn't change the black count\r
1257 // increase incurred by each partial path, eg.\r
1258 // - ascending from node A: 2 + x == 1 + 1 + x\r
1259 // - ascending from node C: y + 1 + x == y + 1 + x\r
1260 // - ascending from node E: 0 + 1 + x == 1 + x\r
1261 //\r
1262 // The color exchange is valid, because even if x stands for red,\r
1263 // both children of node D are black after the transformation\r
1264 // (preserving property #3).\r
1265 //\r
1266 // grandparent grandparent\r
1267 // | |\r
1268 // Parent,x:B x:D\r
1269 // / \ / \_\r
1270 // Child,2b:A Sibling,b:D ---> b:B b:E\r
1271 // / \ / \_\r
1272 // y:C RightNephew,r:E b:A y:C\r
1273 //\r
1274 //\r
1275 Sibling->Color = Parent->Color;\r
1276 Parent->Color = RedBlackTreeBlack;\r
1277 RightNephew->Color = RedBlackTreeBlack;\r
1278 RedBlackTreeRotateLeft (Parent, &NewRoot);\r
1279 Child = NewRoot;\r
1280 //\r
1281 // This terminates the loop.\r
1282 //\r
1283 }\r
1284 } else {\r
1285 //\r
1286 // Mirrors the other branch.\r
1287 //\r
1288 Sibling = Parent->Left;\r
1289 ASSERT (Sibling != NULL);\r
1290 if (Sibling->Color == RedBlackTreeRed) {\r
1291 Sibling->Color = RedBlackTreeBlack;\r
1292 Parent->Color = RedBlackTreeRed;\r
1293 RedBlackTreeRotateRight (Parent, &NewRoot);\r
1294 Sibling = Parent->Left;\r
1295 ASSERT (Sibling != NULL);\r
1296 }\r
1297\r
1298 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1299 RightNephew = Sibling->Right;\r
1300 LeftNephew = Sibling->Left;\r
1301 if (NodeIsNullOrBlack (RightNephew) &&\r
1302 NodeIsNullOrBlack (LeftNephew)) {\r
1303 Sibling->Color = RedBlackTreeRed;\r
1304 Child = Parent;\r
1305 Parent = Parent->Parent;\r
1306 } else {\r
1307 if (NodeIsNullOrBlack (LeftNephew)) {\r
1308 RightNephew->Color = RedBlackTreeBlack;\r
1309 Sibling->Color = RedBlackTreeRed;\r
1310 RedBlackTreeRotateLeft (Sibling, &NewRoot);\r
1311 Sibling = Parent->Left;\r
1312 LeftNephew = Sibling->Left;\r
1313 }\r
1314 ASSERT (LeftNephew != NULL);\r
1315 ASSERT (LeftNephew->Color == RedBlackTreeRed);\r
1316 ASSERT (Sibling != NULL);\r
1317 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1318 Sibling->Color = Parent->Color;\r
1319 Parent->Color = RedBlackTreeBlack;\r
1320 LeftNephew->Color = RedBlackTreeBlack;\r
1321 RedBlackTreeRotateRight (Parent, &NewRoot);\r
1322 Child = NewRoot;\r
1323 }\r
1324 }\r
1325 }\r
1326\r
1327 if (Child != NULL) {\r
1328 Child->Color = RedBlackTreeBlack;\r
1329 }\r
1330 }\r
1331\r
1332 Tree->Root = NewRoot;\r
1333\r
1334 if (FeaturePcdGet (PcdValidateOrderedCollection)) {\r
1335 RedBlackTreeValidate (Tree);\r
1336 }\r
1337}\r
1338\r
1339\r
1340/**\r
1341 Recursively check the red-black tree properties #1 to #4 on a node.\r
1342\r
1343 @param[in] Node The root of the subtree to validate.\r
1344\r
1345 @retval The black-height of Node's parent.\r
1346**/\r
cf556c6a
LE
1347UINT32\r
1348RedBlackTreeRecursiveCheck (\r
1349 IN CONST RED_BLACK_TREE_NODE *Node\r
1350 )\r
1351{\r
64fabae5
ED
1352 UINT32 LeftHeight;\r
1353 UINT32 RightHeight;\r
cf556c6a
LE
1354\r
1355 //\r
1356 // property #2\r
1357 //\r
1358 if (Node == NULL) {\r
1359 return 1;\r
1360 }\r
1361\r
1362 //\r
1363 // property #1\r
1364 //\r
1365 ASSERT (Node->Color == RedBlackTreeRed || Node->Color == RedBlackTreeBlack);\r
1366\r
1367 //\r
1368 // property #3\r
1369 //\r
1370 if (Node->Color == RedBlackTreeRed) {\r
1371 ASSERT (NodeIsNullOrBlack (Node->Left));\r
1372 ASSERT (NodeIsNullOrBlack (Node->Right));\r
1373 }\r
1374\r
1375 //\r
1376 // property #4\r
1377 //\r
1378 LeftHeight = RedBlackTreeRecursiveCheck (Node->Left);\r
1379 RightHeight = RedBlackTreeRecursiveCheck (Node->Right);\r
1380 ASSERT (LeftHeight == RightHeight);\r
1381\r
1382 return (Node->Color == RedBlackTreeBlack) + LeftHeight;\r
1383}\r
1384\r
1385\r
1386/**\r
1387 A slow function that asserts that the tree is a valid red-black tree, and\r
1388 that it orders user structures correctly.\r
1389\r
1390 Read-only operation.\r
1391\r
1392 This function uses the stack for recursion and is not recommended for\r
1393 "production use".\r
1394\r
1395 @param[in] Tree The tree to validate.\r
1396**/\r
cf556c6a
LE
1397VOID\r
1398RedBlackTreeValidate (\r
1399 IN CONST RED_BLACK_TREE *Tree\r
1400 )\r
1401{\r
1402 UINT32 BlackHeight;\r
64fabae5
ED
1403 UINT32 ForwardCount;\r
1404 UINT32 BackwardCount;\r
1405 CONST RED_BLACK_TREE_NODE *Last;\r
1406 CONST RED_BLACK_TREE_NODE *Node;\r
cf556c6a
LE
1407\r
1408 DEBUG ((DEBUG_VERBOSE, "%a: Tree=%p\n", __FUNCTION__, Tree));\r
1409\r
1410 //\r
1411 // property #5\r
1412 //\r
1413 ASSERT (NodeIsNullOrBlack (Tree->Root));\r
1414\r
1415 //\r
1416 // check the other properties\r
1417 //\r
1418 BlackHeight = RedBlackTreeRecursiveCheck (Tree->Root) - 1;\r
1419\r
1420 //\r
1421 // forward ordering\r
1422 //\r
1423 Last = OrderedCollectionMin (Tree);\r
1424 ForwardCount = (Last != NULL);\r
1425 for (Node = OrderedCollectionNext (Last); Node != NULL;\r
1426 Node = OrderedCollectionNext (Last)) {\r
1427 ASSERT (Tree->UserStructCompare (Last->UserStruct, Node->UserStruct) < 0);\r
1428 Last = Node;\r
1429 ++ForwardCount;\r
1430 }\r
1431\r
1432 //\r
1433 // backward ordering\r
1434 //\r
1435 Last = OrderedCollectionMax (Tree);\r
1436 BackwardCount = (Last != NULL);\r
1437 for (Node = OrderedCollectionPrev (Last); Node != NULL;\r
1438 Node = OrderedCollectionPrev (Last)) {\r
1439 ASSERT (Tree->UserStructCompare (Last->UserStruct, Node->UserStruct) > 0);\r
1440 Last = Node;\r
1441 ++BackwardCount;\r
1442 }\r
1443\r
1444 ASSERT (ForwardCount == BackwardCount);\r
1445\r
1446 DEBUG ((DEBUG_VERBOSE, "%a: Tree=%p BlackHeight=%Ld Count=%Ld\n",\r
1447 __FUNCTION__, Tree, (INT64)BlackHeight, (INT64)ForwardCount));\r
1448}\r