]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.c
MdePkg: BaseOrderedCollectionRedBlackTreeLib: silence invalid gcc warning
[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
14\r
15 This program and the accompanying materials are licensed and made available\r
16 under the terms and conditions of the BSD License that accompanies this\r
17 distribution. The full text of the license may be found at\r
18 http://opensource.org/licenses/bsd-license.php.\r
19\r
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
21 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22**/\r
23\r
24#include <Library/OrderedCollectionLib.h>\r
25#include <Library/DebugLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27\r
28typedef enum {\r
29 RedBlackTreeRed,\r
30 RedBlackTreeBlack\r
31} RED_BLACK_TREE_COLOR;\r
32\r
33//\r
34// Incomplete types and convenience typedefs are present in the library class\r
35// header. Beside completing the types, we introduce typedefs here that reflect\r
36// the implementation closely.\r
37//\r
38typedef ORDERED_COLLECTION RED_BLACK_TREE;\r
39typedef ORDERED_COLLECTION_ENTRY RED_BLACK_TREE_NODE;\r
40typedef ORDERED_COLLECTION_USER_COMPARE RED_BLACK_TREE_USER_COMPARE;\r
41typedef ORDERED_COLLECTION_KEY_COMPARE RED_BLACK_TREE_KEY_COMPARE;\r
42\r
43struct ORDERED_COLLECTION {\r
44 RED_BLACK_TREE_NODE *Root;\r
45 RED_BLACK_TREE_USER_COMPARE UserStructCompare;\r
46 RED_BLACK_TREE_KEY_COMPARE KeyCompare;\r
47};\r
48\r
49struct ORDERED_COLLECTION_ENTRY {\r
50 VOID *UserStruct;\r
51 RED_BLACK_TREE_NODE *Parent;\r
52 RED_BLACK_TREE_NODE *Left;\r
53 RED_BLACK_TREE_NODE *Right;\r
54 RED_BLACK_TREE_COLOR Color;\r
55};\r
56\r
57\r
58/**\r
59 Retrieve the user structure linked by the specified tree node.\r
60\r
61 Read-only operation.\r
62\r
63 @param[in] Node Pointer to the tree node whose associated user structure we\r
64 want to retrieve. The caller is responsible for passing a\r
65 non-NULL argument.\r
66\r
67 @return Pointer to user structure linked by Node.\r
68**/\r
69VOID *\r
70EFIAPI\r
71OrderedCollectionUserStruct (\r
72 IN CONST RED_BLACK_TREE_NODE *Node\r
73 )\r
74{\r
75 return Node->UserStruct;\r
76}\r
77\r
78\r
79//\r
80// Forward declaration of internal, unit test helper function. See\r
81// specification and function definition later.\r
82//\r
83STATIC\r
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
151 return Tree->Root == NULL;\r
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
420STATIC\r
421VOID\r
422RedBlackTreeRotateRight (\r
423 IN OUT RED_BLACK_TREE_NODE *Pivot,\r
424 OUT RED_BLACK_TREE_NODE **NewRoot\r
425 )\r
426{\r
427 RED_BLACK_TREE_NODE *Parent, *LeftChild, *LeftRightChild;\r
428\r
429 Parent = Pivot->Parent;\r
430 LeftChild = Pivot->Left;\r
431 LeftRightChild = LeftChild->Right;\r
432\r
433 Pivot->Left = LeftRightChild;\r
434 if (LeftRightChild != NULL) {\r
435 LeftRightChild->Parent = Pivot;\r
436 }\r
437 LeftChild->Parent = Parent;\r
438 if (Parent == NULL) {\r
439 *NewRoot = LeftChild;\r
440 } else {\r
441 if (Pivot == Parent->Left) {\r
442 Parent->Left = LeftChild;\r
443 } else {\r
444 Parent->Right = LeftChild;\r
445 }\r
446 }\r
447 LeftChild->Right = Pivot;\r
448 Pivot->Parent = LeftChild;\r
449}\r
450\r
451\r
452/**\r
453 Rotate tree nodes around Pivot to the left.\r
454\r
455 Parent Parent\r
456 | |\r
457 Pivot RightChild\r
458 . \ / .\r
459 Node1 RightChild ---> Pivot Node2\r
460 /. . \_\r
461 RightLeftChild Node2 Node1 RightLeftChild\r
462\r
463 The ordering Node1 < Pivot < RightLeftChild < RightChild < Node2 is kept\r
464 intact. Parent (if any) is either at the left extreme or the right extreme of\r
465 this ordering, and that relation is also kept intact.\r
466\r
467 Edges marked with a dot (".") don't change during rotation.\r
468\r
469 Internal read-write operation.\r
470\r
471 @param[in,out] Pivot The tree node to rotate other nodes left around. It\r
472 is the caller's responsibility to ensure that\r
473 Pivot->Right is not NULL.\r
474\r
475 @param[out] NewRoot If Pivot has a parent node on input, then the\r
476 function updates Pivot's original parent on output\r
477 according to the rotation, and NewRoot is not\r
478 accessed.\r
479\r
480 If Pivot has no parent node on input (ie. Pivot is\r
481 the root of the tree), then the function stores the\r
482 new root node of the tree in NewRoot.\r
483**/\r
484STATIC\r
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
491 RED_BLACK_TREE_NODE *Parent, *RightChild, *RightLeftChild;\r
492\r
493 Parent = Pivot->Parent;\r
494 RightChild = Pivot->Right;\r
495 RightLeftChild = RightChild->Left;\r
496\r
497 Pivot->Right = RightLeftChild;\r
498 if (RightLeftChild != NULL) {\r
499 RightLeftChild->Parent = Pivot;\r
500 }\r
501 RightChild->Parent = Parent;\r
502 if (Parent == NULL) {\r
503 *NewRoot = RightChild;\r
504 } else {\r
505 if (Pivot == Parent->Left) {\r
506 Parent->Left = RightChild;\r
507 } else {\r
508 Parent->Right = RightChild;\r
509 }\r
510 }\r
511 RightChild->Left = Pivot;\r
512 Pivot->Parent = RightChild;\r
513}\r
514\r
515\r
516/**\r
517 Insert (link) a user structure into the tree.\r
518\r
519 Read-write operation.\r
520\r
521 This function allocates the new tree node with MemoryAllocationLib's\r
522 AllocatePool() function.\r
523\r
524 @param[in,out] Tree The tree to insert UserStruct into.\r
525\r
526 @param[out] Node The meaning of this optional, output-only\r
527 parameter depends on the return value of the\r
528 function.\r
529\r
530 When insertion is successful (RETURN_SUCCESS),\r
531 Node is set on output to the new tree node that\r
532 now links UserStruct.\r
533\r
534 When insertion fails due to lack of memory\r
535 (RETURN_OUT_OF_RESOURCES), Node is not changed.\r
536\r
537 When insertion fails due to key collision (ie.\r
538 another user structure is already in the tree that\r
539 compares equal to UserStruct), with return value\r
540 RETURN_ALREADY_STARTED, then Node is set on output\r
541 to the node that links the colliding user\r
542 structure. This enables "find-or-insert" in one\r
543 function call, or helps with later removal of the\r
544 colliding element.\r
545\r
546 @param[in] UserStruct The user structure to link into the tree.\r
547 UserStruct is ordered against in-tree user\r
548 structures with the Tree->UserStructCompare()\r
549 function.\r
550\r
551 @retval RETURN_SUCCESS Insertion successful. A new tree node has\r
552 been allocated, linking UserStruct. The new\r
553 tree node is reported back in Node (if the\r
554 caller requested it).\r
555\r
556 Existing RED_BLACK_TREE_NODE pointers into\r
557 Tree remain valid. For example, on-going\r
558 iterations in the caller can continue with\r
559 OrderedCollectionNext() /\r
560 OrderedCollectionPrev(), and they will\r
561 return the new node at some point if user\r
562 structure order dictates it.\r
563\r
564 @retval RETURN_OUT_OF_RESOURCES AllocatePool() failed to allocate memory for\r
565 the new tree node. The tree has not been\r
566 changed. Existing RED_BLACK_TREE_NODE\r
567 pointers into Tree remain valid.\r
568\r
569 @retval RETURN_ALREADY_STARTED A user structure has been found in the tree\r
570 that compares equal to UserStruct. The node\r
571 linking the colliding user structure is\r
572 reported back in Node (if the caller\r
573 requested it). The tree has not been\r
574 changed. Existing RED_BLACK_TREE_NODE\r
575 pointers into Tree remain valid.\r
576**/\r
577RETURN_STATUS\r
578EFIAPI\r
579OrderedCollectionInsert (\r
580 IN OUT RED_BLACK_TREE *Tree,\r
581 OUT RED_BLACK_TREE_NODE **Node OPTIONAL,\r
582 IN VOID *UserStruct\r
583 )\r
584{\r
585 RED_BLACK_TREE_NODE *Tmp, *Parent;\r
586 INTN Result;\r
587 RETURN_STATUS Status;\r
588 RED_BLACK_TREE_NODE *NewRoot;\r
589\r
590 Tmp = Tree->Root;\r
591 Parent = NULL;\r
75955444 592 Result = 0;\r
cf556c6a
LE
593\r
594 //\r
595 // First look for a collision, saving the last examined node for the case\r
596 // when there's no collision.\r
597 //\r
598 while (Tmp != NULL) {\r
599 Result = Tree->UserStructCompare (UserStruct, Tmp->UserStruct);\r
600 if (Result == 0) {\r
601 break;\r
602 }\r
603 Parent = Tmp;\r
604 Tmp = (Result < 0) ? Tmp->Left : Tmp->Right;\r
605 }\r
606\r
607 if (Tmp != NULL) {\r
608 if (Node != NULL) {\r
609 *Node = Tmp;\r
610 }\r
611 Status = RETURN_ALREADY_STARTED;\r
612 goto Done;\r
613 }\r
614\r
615 //\r
616 // no collision, allocate a new node\r
617 //\r
618 Tmp = AllocatePool (sizeof *Tmp);\r
619 if (Tmp == NULL) {\r
620 Status = RETURN_OUT_OF_RESOURCES;\r
621 goto Done;\r
622 }\r
623 if (Node != NULL) {\r
624 *Node = Tmp;\r
625 }\r
626\r
627 //\r
628 // reference the user structure from the node\r
629 //\r
630 Tmp->UserStruct = UserStruct;\r
631\r
632 //\r
633 // Link the node as a child to the correct side of the parent.\r
634 // If there's no parent, the new node is the root node in the tree.\r
635 //\r
636 Tmp->Parent = Parent;\r
637 Tmp->Left = NULL;\r
638 Tmp->Right = NULL;\r
639 if (Parent == NULL) {\r
640 Tree->Root = Tmp;\r
641 Tmp->Color = RedBlackTreeBlack;\r
642 Status = RETURN_SUCCESS;\r
643 goto Done;\r
644 }\r
645 if (Result < 0) {\r
646 Parent->Left = Tmp;\r
647 } else {\r
648 Parent->Right = Tmp;\r
649 }\r
650 Tmp->Color = RedBlackTreeRed;\r
651\r
652 //\r
653 // Red-black tree properties:\r
654 //\r
655 // #1 Each node is either red or black (RED_BLACK_TREE_NODE.Color).\r
656 //\r
657 // #2 Each leaf (ie. a pseudo-node pointed-to by a NULL valued\r
658 // RED_BLACK_TREE_NODE.Left or RED_BLACK_TREE_NODE.Right field) is black.\r
659 //\r
660 // #3 Each red node has two black children.\r
661 //\r
662 // #4 For any node N, and for any leaves L1 and L2 reachable from N, the\r
663 // paths N..L1 and N..L2 contain the same number of black nodes.\r
664 //\r
665 // #5 The root node is black.\r
666 //\r
667 // By replacing a leaf with a red node above, only property #3 may have been\r
668 // broken. (Note that this is the only edge across which property #3 might\r
669 // not hold in the entire tree.) Restore property #3.\r
670 //\r
671\r
672 NewRoot = Tree->Root;\r
673 while (Tmp != NewRoot && Parent->Color == RedBlackTreeRed) {\r
674 RED_BLACK_TREE_NODE *GrandParent, *Uncle;\r
675\r
676 //\r
677 // Tmp is not the root node. Tmp is red. Tmp's parent is red. (Breaking\r
678 // property #3.)\r
679 //\r
680 // Due to property #5, Tmp's parent cannot be the root node, hence Tmp's\r
681 // grandparent exists.\r
682 //\r
683 // Tmp's grandparent is black, because property #3 is only broken between\r
684 // Tmp and Tmp's parent.\r
685 //\r
686 GrandParent = Parent->Parent;\r
687\r
688 if (Parent == GrandParent->Left) {\r
689 Uncle = GrandParent->Right;\r
690 if (Uncle != NULL && Uncle->Color == RedBlackTreeRed) {\r
691 //\r
692 // GrandParent (black)\r
693 // / \_\r
694 // Parent (red) Uncle (red)\r
695 // |\r
696 // Tmp (red)\r
697 //\r
698\r
699 Parent->Color = RedBlackTreeBlack;\r
700 Uncle->Color = RedBlackTreeBlack;\r
701 GrandParent->Color = RedBlackTreeRed;\r
702\r
703 //\r
704 // GrandParent (red)\r
705 // / \_\r
706 // Parent (black) Uncle (black)\r
707 // |\r
708 // Tmp (red)\r
709 //\r
710 // We restored property #3 between Tmp and Tmp's parent, without\r
711 // breaking property #4. However, we may have broken property #3\r
712 // between Tmp's grandparent and Tmp's great-grandparent (if any), so\r
713 // repeat the loop for Tmp's grandparent.\r
714 //\r
715 // If Tmp's grandparent has no parent, then the loop will terminate,\r
716 // and we will have broken property #5, by coloring the root red. We'll\r
717 // restore property #5 after the loop, without breaking any others.\r
718 //\r
719 Tmp = GrandParent;\r
720 Parent = Tmp->Parent;\r
721 } else {\r
722 //\r
723 // Tmp's uncle is black (satisfied by the case too when Tmp's uncle is\r
724 // NULL, see property #2).\r
725 //\r
726\r
727 if (Tmp == Parent->Right) {\r
728 //\r
729 // GrandParent (black): D\r
730 // / \_\r
731 // Parent (red): A Uncle (black): E\r
732 // \_\r
733 // Tmp (red): B\r
734 // \_\r
735 // black: C\r
736 //\r
737 // Rotate left, pivoting on node A. This keeps the breakage of\r
738 // property #3 in the same spot, and keeps other properties intact\r
739 // (because both Tmp and its parent are red).\r
740 //\r
741 Tmp = Parent;\r
742 RedBlackTreeRotateLeft (Tmp, &NewRoot);\r
743 Parent = Tmp->Parent;\r
744\r
745 //\r
746 // With the rotation we reached the same configuration as if Tmp had\r
747 // been a left child to begin with.\r
748 //\r
749 // GrandParent (black): D\r
750 // / \_\r
751 // Parent (red): B Uncle (black): E\r
752 // / \_\r
753 // Tmp (red): A black: C\r
754 //\r
755 ASSERT (GrandParent == Parent->Parent);\r
756 }\r
757\r
758 Parent->Color = RedBlackTreeBlack;\r
759 GrandParent->Color = RedBlackTreeRed;\r
760\r
761 //\r
762 // Property #3 is now restored, but we've broken property #4. Namely,\r
763 // paths going through node E now see a decrease in black count, while\r
764 // paths going through node B don't.\r
765 //\r
766 // GrandParent (red): D\r
767 // / \_\r
768 // Parent (black): B Uncle (black): E\r
769 // / \_\r
770 // Tmp (red): A black: C\r
771 //\r
772\r
773 RedBlackTreeRotateRight (GrandParent, &NewRoot);\r
774\r
775 //\r
776 // Property #4 has been restored for node E, and preserved for others.\r
777 //\r
778 // Parent (black): B\r
779 // / \_\r
780 // Tmp (red): A [GrandParent] (red): D\r
781 // / \_\r
782 // black: C [Uncle] (black): E\r
783 //\r
784 // This configuration terminates the loop because Tmp's parent is now\r
785 // black.\r
786 //\r
787 }\r
788 } else {\r
789 //\r
790 // Symmetrical to the other branch.\r
791 //\r
792 Uncle = GrandParent->Left;\r
793 if (Uncle != NULL && Uncle->Color == RedBlackTreeRed) {\r
794 Parent->Color = RedBlackTreeBlack;\r
795 Uncle->Color = RedBlackTreeBlack;\r
796 GrandParent->Color = RedBlackTreeRed;\r
797 Tmp = GrandParent;\r
798 Parent = Tmp->Parent;\r
799 } else {\r
800 if (Tmp == Parent->Left) {\r
801 Tmp = Parent;\r
802 RedBlackTreeRotateRight (Tmp, &NewRoot);\r
803 Parent = Tmp->Parent;\r
804 ASSERT (GrandParent == Parent->Parent);\r
805 }\r
806 Parent->Color = RedBlackTreeBlack;\r
807 GrandParent->Color = RedBlackTreeRed;\r
808 RedBlackTreeRotateLeft (GrandParent, &NewRoot);\r
809 }\r
810 }\r
811 }\r
812\r
813 NewRoot->Color = RedBlackTreeBlack;\r
814 Tree->Root = NewRoot;\r
815 Status = RETURN_SUCCESS;\r
816\r
817Done:\r
818 if (FeaturePcdGet (PcdValidateOrderedCollection)) {\r
819 RedBlackTreeValidate (Tree);\r
820 }\r
821 return Status;\r
822}\r
823\r
824\r
825/**\r
826 Check if a node is black, allowing for leaf nodes (see property #2).\r
827\r
828 This is a convenience shorthand.\r
829\r
830 param[in] Node The node to check. Node may be NULL, corresponding to a leaf.\r
831\r
832 @return If Node is NULL or colored black.\r
833**/\r
834\r
835STATIC\r
836BOOLEAN\r
837NodeIsNullOrBlack (\r
838 IN CONST RED_BLACK_TREE_NODE *Node\r
839 )\r
840{\r
841 return Node == NULL || Node->Color == RedBlackTreeBlack;\r
842}\r
843\r
844\r
845/**\r
846 Delete a node from the tree, unlinking the associated user structure.\r
847\r
848 Read-write operation.\r
849\r
850 @param[in,out] Tree The tree to delete Node from.\r
851\r
852 @param[in] Node The tree node to delete from Tree. The caller is\r
853 responsible for ensuring that Node belongs to\r
854 Tree, and that Node is non-NULL and valid. Node is\r
855 typically an earlier return value, or output\r
856 parameter, of:\r
857\r
858 - OrderedCollectionFind(), for deleting a node by\r
859 user structure key,\r
860\r
861 - OrderedCollectionMin() / OrderedCollectionMax(),\r
862 for deleting the minimum / maximum node,\r
863\r
864 - OrderedCollectionNext() /\r
865 OrderedCollectionPrev(), for deleting a node\r
866 found during an iteration,\r
867\r
868 - OrderedCollectionInsert() with return value\r
869 RETURN_ALREADY_STARTED, for deleting a node\r
870 whose linked user structure caused collision\r
871 during insertion.\r
872\r
873 Given a non-empty Tree, Tree->Root is also a valid\r
874 Node argument (typically used for simplicity in\r
875 loops that empty the tree completely).\r
876\r
877 Node is released with MemoryAllocationLib's\r
878 FreePool() function.\r
879\r
880 Existing RED_BLACK_TREE_NODE pointers (ie.\r
881 iterators) *different* from Node remain valid. For\r
882 example:\r
883\r
884 - OrderedCollectionNext() /\r
885 OrderedCollectionPrev() iterations in the caller\r
886 can be continued from Node, if\r
887 OrderedCollectionNext() or\r
888 OrderedCollectionPrev() is called on Node\r
889 *before* OrderedCollectionDelete() is. That is,\r
890 fetch the successor / predecessor node first,\r
891 then delete Node.\r
892\r
893 - On-going iterations in the caller that would\r
894 have otherwise returned Node at some point, as\r
895 dictated by user structure order, will correctly\r
896 reflect the absence of Node after\r
897 OrderedCollectionDelete() is called\r
898 mid-iteration.\r
899\r
900 @param[out] UserStruct If the caller provides this optional output-only\r
901 parameter, then on output it is set to the user\r
902 structure originally linked by Node (which is now\r
903 freed).\r
904\r
905 This is a convenience that may save the caller a\r
906 OrderedCollectionUserStruct() invocation before\r
907 calling OrderedCollectionDelete(), in order to\r
908 retrieve the user structure being unlinked.\r
909**/\r
910VOID\r
911EFIAPI\r
912OrderedCollectionDelete (\r
913 IN OUT RED_BLACK_TREE *Tree,\r
914 IN RED_BLACK_TREE_NODE *Node,\r
915 OUT VOID **UserStruct OPTIONAL\r
916 )\r
917{\r
918 RED_BLACK_TREE_NODE *NewRoot;\r
919 RED_BLACK_TREE_NODE *OrigLeftChild, *OrigRightChild, *OrigParent;\r
920 RED_BLACK_TREE_NODE *Child, *Parent;\r
921 RED_BLACK_TREE_COLOR ColorOfUnlinked;\r
922\r
923 NewRoot = Tree->Root;\r
924 OrigLeftChild = Node->Left,\r
925 OrigRightChild = Node->Right,\r
926 OrigParent = Node->Parent;\r
927\r
928 if (UserStruct != NULL) {\r
929 *UserStruct = Node->UserStruct;\r
930 }\r
931\r
932 //\r
933 // After this block, no matter which branch we take:\r
934 // - Child will point to the unique (or NULL) original child of the node that\r
935 // we will have unlinked,\r
936 // - Parent will point to the *position* of the original parent of the node\r
937 // that we will have unlinked.\r
938 //\r
939 if (OrigLeftChild == NULL || OrigRightChild == NULL) {\r
940 //\r
941 // Node has at most one child. We can connect that child (if any) with\r
942 // Node's parent (if any), unlinking Node. This will preserve ordering\r
943 // because the subtree rooted in Node's child (if any) remains on the same\r
944 // side of Node's parent (if any) that Node was before.\r
945 //\r
946 Parent = OrigParent;\r
947 Child = (OrigLeftChild != NULL) ? OrigLeftChild : OrigRightChild;\r
948 ColorOfUnlinked = Node->Color;\r
949\r
950 if (Child != NULL) {\r
951 Child->Parent = Parent;\r
952 }\r
953 if (OrigParent == NULL) {\r
954 NewRoot = Child;\r
955 } else {\r
956 if (Node == OrigParent->Left) {\r
957 OrigParent->Left = Child;\r
958 } else {\r
959 OrigParent->Right = Child;\r
960 }\r
961 }\r
962 } else {\r
963 //\r
964 // Node has two children. We unlink Node's successor, and then link it into\r
965 // Node's place, keeping Node's original color. This preserves ordering\r
966 // because:\r
967 // - Node's left subtree is less than Node, hence less than Node's\r
968 // successor.\r
969 // - Node's right subtree is greater than Node. Node's successor is the\r
970 // minimum of that subtree, hence Node's successor is less than Node's\r
971 // right subtree with its minimum removed.\r
972 // - Node's successor is in Node's subtree, hence it falls on the same side\r
973 // of Node's parent as Node itself. The relinking doesn't change this\r
974 // relation.\r
975 //\r
976 RED_BLACK_TREE_NODE *ToRelink;\r
977\r
978 ToRelink = OrigRightChild;\r
979 if (ToRelink->Left == NULL) {\r
980 //\r
981 // OrigRightChild itself is Node's successor, it has no left child:\r
982 //\r
983 // OrigParent\r
984 // |\r
985 // Node: B\r
986 // / \_\r
987 // OrigLeftChild: A OrigRightChild: E <--- Parent, ToRelink\r
988 // \_\r
989 // F <--- Child\r
990 //\r
991 Parent = OrigRightChild;\r
992 Child = OrigRightChild->Right;\r
993 } else {\r
994 do {\r
995 ToRelink = ToRelink->Left;\r
996 } while (ToRelink->Left != NULL);\r
997\r
998 //\r
999 // Node's successor is the minimum of OrigRightChild's proper subtree:\r
1000 //\r
1001 // OrigParent\r
1002 // |\r
1003 // Node: B\r
1004 // / \_\r
1005 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1006 // /\r
1007 // C <--- ToRelink\r
1008 // \_\r
1009 // D <--- Child\r
1010 Parent = ToRelink->Parent;\r
1011 Child = ToRelink->Right;\r
1012\r
1013 //\r
1014 // Unlink Node's successor (ie. ToRelink):\r
1015 //\r
1016 // OrigParent\r
1017 // |\r
1018 // Node: B\r
1019 // / \_\r
1020 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1021 // /\r
1022 // D <--- Child\r
1023 //\r
1024 // C <--- ToRelink\r
1025 //\r
1026 Parent->Left = Child;\r
1027 if (Child) {\r
1028 Child->Parent = Parent;\r
1029 }\r
1030\r
1031 //\r
1032 // We start to link Node's unlinked successor into Node's place:\r
1033 //\r
1034 // OrigParent\r
1035 // |\r
1036 // Node: B C <--- ToRelink\r
1037 // / \_\r
1038 // OrigLeftChild: A OrigRightChild: E <--- Parent\r
1039 // /\r
1040 // D <--- Child\r
1041 //\r
1042 //\r
1043 //\r
1044 ToRelink->Right = OrigRightChild;\r
1045 OrigRightChild->Parent = ToRelink;\r
1046 }\r
1047\r
1048 //\r
1049 // The rest handles both cases, attaching ToRelink (Node's original\r
1050 // successor) to OrigLeftChild and OrigParent.\r
1051 //\r
1052 // Parent,\r
1053 // OrigParent ToRelink OrigParent\r
1054 // | | |\r
1055 // Node: B | Node: B Parent\r
1056 // v |\r
1057 // OrigRightChild: E C <--- ToRelink |\r
1058 // / \ / \ v\r
1059 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E\r
1060 // ^ /\r
1061 // | D <--- Child\r
1062 // Child\r
1063 //\r
1064 ToRelink->Left = OrigLeftChild;\r
1065 OrigLeftChild->Parent = ToRelink;\r
1066\r
1067 //\r
1068 // Node's color must be preserved in Node's original place.\r
1069 //\r
1070 ColorOfUnlinked = ToRelink->Color;\r
1071 ToRelink->Color = Node->Color;\r
1072\r
1073 //\r
1074 // Finish linking Node's unlinked successor into Node's place.\r
1075 //\r
1076 // Parent,\r
1077 // Node: B ToRelink Node: B\r
1078 // |\r
1079 // OrigParent | OrigParent Parent\r
1080 // | v | |\r
1081 // OrigRightChild: E C <--- ToRelink |\r
1082 // / \ / \ v\r
1083 // OrigLeftChild: A F OrigLeftChild: A OrigRightChild: E\r
1084 // ^ /\r
1085 // | D <--- Child\r
1086 // Child\r
1087 //\r
1088 ToRelink->Parent = OrigParent;\r
1089 if (OrigParent == NULL) {\r
1090 NewRoot = ToRelink;\r
1091 } else {\r
1092 if (Node == OrigParent->Left) {\r
1093 OrigParent->Left = ToRelink;\r
1094 } else {\r
1095 OrigParent->Right = ToRelink;\r
1096 }\r
1097 }\r
1098 }\r
1099\r
1100 FreePool (Node);\r
1101\r
1102 //\r
1103 // If the node that we unlinked from its original spot (ie. Node itself, or\r
1104 // Node's successor), was red, then we broke neither property #3 nor property\r
1105 // #4: we didn't create any red-red edge between Child and Parent, and we\r
1106 // didn't change the black count on any path.\r
1107 //\r
1108 if (ColorOfUnlinked == RedBlackTreeBlack) {\r
1109 //\r
1110 // However, if the unlinked node was black, then we have to transfer its\r
1111 // "black-increment" to its unique child (pointed-to by Child), lest we\r
1112 // break property #4 for its ancestors.\r
1113 //\r
1114 // If Child is red, we can simply color it black. If Child is black\r
1115 // already, we can't technically transfer a black-increment to it, due to\r
1116 // property #1.\r
1117 //\r
1118 // In the following loop we ascend searching for a red node to color black,\r
1119 // or until we reach the root (in which case we can drop the\r
1120 // black-increment). Inside the loop body, Child has a black value of 2,\r
1121 // transitorily breaking property #1 locally, but maintaining property #4\r
1122 // globally.\r
1123 //\r
1124 // Rotations in the loop preserve property #4.\r
1125 //\r
1126 while (Child != NewRoot && NodeIsNullOrBlack (Child)) {\r
1127 RED_BLACK_TREE_NODE *Sibling, *LeftNephew, *RightNephew;\r
1128\r
1129 if (Child == Parent->Left) {\r
1130 Sibling = Parent->Right;\r
1131 //\r
1132 // Sibling can never be NULL (ie. a leaf).\r
1133 //\r
1134 // If Sibling was NULL, then the black count on the path from Parent to\r
1135 // Sibling would equal Parent's black value, plus 1 (due to property\r
1136 // #2). Whereas the black count on the path from Parent to any leaf via\r
1137 // Child would be at least Parent's black value, plus 2 (due to Child's\r
1138 // black value of 2). This would clash with property #4.\r
1139 //\r
1140 // (Sibling can be black of course, but it has to be an internal node.\r
1141 // Internality allows Sibling to have children, bumping the black\r
1142 // counts of paths that go through it.)\r
1143 //\r
1144 ASSERT (Sibling != NULL);\r
1145 if (Sibling->Color == RedBlackTreeRed) {\r
1146 //\r
1147 // Sibling's red color implies its children (if any), node C and node\r
1148 // E, are black (property #3). It also implies that Parent is black.\r
1149 //\r
1150 // grandparent grandparent\r
1151 // | |\r
1152 // Parent,b:B b:D\r
1153 // / \ / \_\r
1154 // Child,2b:A Sibling,r:D ---> Parent,r:B b:E\r
1155 // /\ /\_\r
1156 // b:C b:E Child,2b:A Sibling,b:C\r
1157 //\r
1158 Sibling->Color = RedBlackTreeBlack;\r
1159 Parent->Color = RedBlackTreeRed;\r
1160 RedBlackTreeRotateLeft (Parent, &NewRoot);\r
1161 Sibling = Parent->Right;\r
1162 //\r
1163 // Same reasoning as above.\r
1164 //\r
1165 ASSERT (Sibling != NULL);\r
1166 }\r
1167\r
1168 //\r
1169 // Sibling is black, and not NULL. (Ie. Sibling is a black internal\r
1170 // node.)\r
1171 //\r
1172 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1173 LeftNephew = Sibling->Left;\r
1174 RightNephew = Sibling->Right;\r
1175 if (NodeIsNullOrBlack (LeftNephew) &&\r
1176 NodeIsNullOrBlack (RightNephew)) {\r
1177 //\r
1178 // In this case we can "steal" one black value from Child and Sibling\r
1179 // each, and pass it to Parent. "Stealing" means that Sibling (black\r
1180 // value 1) becomes red, Child (black value 2) becomes singly-black,\r
1181 // and Parent will have to be examined if it can eat the\r
1182 // black-increment.\r
1183 //\r
1184 // Sibling is allowed to become red because both of its children are\r
1185 // black (property #3).\r
1186 //\r
1187 // grandparent Parent\r
1188 // | |\r
1189 // Parent,x:B Child,x:B\r
1190 // / \ / \_\r
1191 // Child,2b:A Sibling,b:D ---> b:A r:D\r
1192 // /\ /\_\r
1193 // LeftNephew,b:C RightNephew,b:E b:C b:E\r
1194 //\r
1195 Sibling->Color = RedBlackTreeRed;\r
1196 Child = Parent;\r
1197 Parent = Parent->Parent;\r
1198 //\r
1199 // Continue ascending.\r
1200 //\r
1201 } else {\r
1202 //\r
1203 // At least one nephew is red.\r
1204 //\r
1205 if (NodeIsNullOrBlack (RightNephew)) {\r
1206 //\r
1207 // Since the right nephew is black, the left nephew is red. Due to\r
1208 // property #3, LeftNephew has two black children, hence node E is\r
1209 // black.\r
1210 //\r
1211 // Together with the rotation, this enables us to color node F red\r
1212 // (because property #3 will be satisfied). We flip node D to black\r
1213 // to maintain property #4.\r
1214 //\r
1215 // grandparent grandparent\r
1216 // | |\r
1217 // Parent,x:B Parent,x:B\r
1218 // /\ /\_\r
1219 // Child,2b:A Sibling,b:F ---> Child,2b:A Sibling,b:D\r
1220 // /\ / \_\r
1221 // LeftNephew,r:D RightNephew,b:G b:C RightNephew,r:F\r
1222 // /\ /\_\r
1223 // b:C b:E b:E b:G\r
1224 //\r
1225 LeftNephew->Color = RedBlackTreeBlack;\r
1226 Sibling->Color = RedBlackTreeRed;\r
1227 RedBlackTreeRotateRight (Sibling, &NewRoot);\r
1228 Sibling = Parent->Right;\r
1229 RightNephew = Sibling->Right;\r
1230 //\r
1231 // These operations ensure that...\r
1232 //\r
1233 }\r
1234 //\r
1235 // ... RightNephew is definitely red here, plus Sibling is (still)\r
1236 // black and non-NULL.\r
1237 //\r
1238 ASSERT (RightNephew != NULL);\r
1239 ASSERT (RightNephew->Color == RedBlackTreeRed);\r
1240 ASSERT (Sibling != NULL);\r
1241 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1242 //\r
1243 // In this case we can flush the extra black-increment immediately,\r
1244 // restoring property #1 for Child (node A): we color RightNephew\r
1245 // (node E) from red to black.\r
1246 //\r
1247 // In order to maintain property #4, we exchange colors between\r
1248 // Parent and Sibling (nodes B and D), and rotate left around Parent\r
1249 // (node B). The transformation doesn't change the black count\r
1250 // increase incurred by each partial path, eg.\r
1251 // - ascending from node A: 2 + x == 1 + 1 + x\r
1252 // - ascending from node C: y + 1 + x == y + 1 + x\r
1253 // - ascending from node E: 0 + 1 + x == 1 + x\r
1254 //\r
1255 // The color exchange is valid, because even if x stands for red,\r
1256 // both children of node D are black after the transformation\r
1257 // (preserving property #3).\r
1258 //\r
1259 // grandparent grandparent\r
1260 // | |\r
1261 // Parent,x:B x:D\r
1262 // / \ / \_\r
1263 // Child,2b:A Sibling,b:D ---> b:B b:E\r
1264 // / \ / \_\r
1265 // y:C RightNephew,r:E b:A y:C\r
1266 //\r
1267 //\r
1268 Sibling->Color = Parent->Color;\r
1269 Parent->Color = RedBlackTreeBlack;\r
1270 RightNephew->Color = RedBlackTreeBlack;\r
1271 RedBlackTreeRotateLeft (Parent, &NewRoot);\r
1272 Child = NewRoot;\r
1273 //\r
1274 // This terminates the loop.\r
1275 //\r
1276 }\r
1277 } else {\r
1278 //\r
1279 // Mirrors the other branch.\r
1280 //\r
1281 Sibling = Parent->Left;\r
1282 ASSERT (Sibling != NULL);\r
1283 if (Sibling->Color == RedBlackTreeRed) {\r
1284 Sibling->Color = RedBlackTreeBlack;\r
1285 Parent->Color = RedBlackTreeRed;\r
1286 RedBlackTreeRotateRight (Parent, &NewRoot);\r
1287 Sibling = Parent->Left;\r
1288 ASSERT (Sibling != NULL);\r
1289 }\r
1290\r
1291 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1292 RightNephew = Sibling->Right;\r
1293 LeftNephew = Sibling->Left;\r
1294 if (NodeIsNullOrBlack (RightNephew) &&\r
1295 NodeIsNullOrBlack (LeftNephew)) {\r
1296 Sibling->Color = RedBlackTreeRed;\r
1297 Child = Parent;\r
1298 Parent = Parent->Parent;\r
1299 } else {\r
1300 if (NodeIsNullOrBlack (LeftNephew)) {\r
1301 RightNephew->Color = RedBlackTreeBlack;\r
1302 Sibling->Color = RedBlackTreeRed;\r
1303 RedBlackTreeRotateLeft (Sibling, &NewRoot);\r
1304 Sibling = Parent->Left;\r
1305 LeftNephew = Sibling->Left;\r
1306 }\r
1307 ASSERT (LeftNephew != NULL);\r
1308 ASSERT (LeftNephew->Color == RedBlackTreeRed);\r
1309 ASSERT (Sibling != NULL);\r
1310 ASSERT (Sibling->Color == RedBlackTreeBlack);\r
1311 Sibling->Color = Parent->Color;\r
1312 Parent->Color = RedBlackTreeBlack;\r
1313 LeftNephew->Color = RedBlackTreeBlack;\r
1314 RedBlackTreeRotateRight (Parent, &NewRoot);\r
1315 Child = NewRoot;\r
1316 }\r
1317 }\r
1318 }\r
1319\r
1320 if (Child != NULL) {\r
1321 Child->Color = RedBlackTreeBlack;\r
1322 }\r
1323 }\r
1324\r
1325 Tree->Root = NewRoot;\r
1326\r
1327 if (FeaturePcdGet (PcdValidateOrderedCollection)) {\r
1328 RedBlackTreeValidate (Tree);\r
1329 }\r
1330}\r
1331\r
1332\r
1333/**\r
1334 Recursively check the red-black tree properties #1 to #4 on a node.\r
1335\r
1336 @param[in] Node The root of the subtree to validate.\r
1337\r
1338 @retval The black-height of Node's parent.\r
1339**/\r
1340STATIC\r
1341UINT32\r
1342RedBlackTreeRecursiveCheck (\r
1343 IN CONST RED_BLACK_TREE_NODE *Node\r
1344 )\r
1345{\r
1346 UINT32 LeftHeight, RightHeight;\r
1347\r
1348 //\r
1349 // property #2\r
1350 //\r
1351 if (Node == NULL) {\r
1352 return 1;\r
1353 }\r
1354\r
1355 //\r
1356 // property #1\r
1357 //\r
1358 ASSERT (Node->Color == RedBlackTreeRed || Node->Color == RedBlackTreeBlack);\r
1359\r
1360 //\r
1361 // property #3\r
1362 //\r
1363 if (Node->Color == RedBlackTreeRed) {\r
1364 ASSERT (NodeIsNullOrBlack (Node->Left));\r
1365 ASSERT (NodeIsNullOrBlack (Node->Right));\r
1366 }\r
1367\r
1368 //\r
1369 // property #4\r
1370 //\r
1371 LeftHeight = RedBlackTreeRecursiveCheck (Node->Left);\r
1372 RightHeight = RedBlackTreeRecursiveCheck (Node->Right);\r
1373 ASSERT (LeftHeight == RightHeight);\r
1374\r
1375 return (Node->Color == RedBlackTreeBlack) + LeftHeight;\r
1376}\r
1377\r
1378\r
1379/**\r
1380 A slow function that asserts that the tree is a valid red-black tree, and\r
1381 that it orders user structures correctly.\r
1382\r
1383 Read-only operation.\r
1384\r
1385 This function uses the stack for recursion and is not recommended for\r
1386 "production use".\r
1387\r
1388 @param[in] Tree The tree to validate.\r
1389**/\r
1390STATIC\r
1391VOID\r
1392RedBlackTreeValidate (\r
1393 IN CONST RED_BLACK_TREE *Tree\r
1394 )\r
1395{\r
1396 UINT32 BlackHeight;\r
1397 UINT32 ForwardCount, BackwardCount;\r
1398 CONST RED_BLACK_TREE_NODE *Last, *Node;\r
1399\r
1400 DEBUG ((DEBUG_VERBOSE, "%a: Tree=%p\n", __FUNCTION__, Tree));\r
1401\r
1402 //\r
1403 // property #5\r
1404 //\r
1405 ASSERT (NodeIsNullOrBlack (Tree->Root));\r
1406\r
1407 //\r
1408 // check the other properties\r
1409 //\r
1410 BlackHeight = RedBlackTreeRecursiveCheck (Tree->Root) - 1;\r
1411\r
1412 //\r
1413 // forward ordering\r
1414 //\r
1415 Last = OrderedCollectionMin (Tree);\r
1416 ForwardCount = (Last != NULL);\r
1417 for (Node = OrderedCollectionNext (Last); Node != NULL;\r
1418 Node = OrderedCollectionNext (Last)) {\r
1419 ASSERT (Tree->UserStructCompare (Last->UserStruct, Node->UserStruct) < 0);\r
1420 Last = Node;\r
1421 ++ForwardCount;\r
1422 }\r
1423\r
1424 //\r
1425 // backward ordering\r
1426 //\r
1427 Last = OrderedCollectionMax (Tree);\r
1428 BackwardCount = (Last != NULL);\r
1429 for (Node = OrderedCollectionPrev (Last); Node != NULL;\r
1430 Node = OrderedCollectionPrev (Last)) {\r
1431 ASSERT (Tree->UserStructCompare (Last->UserStruct, Node->UserStruct) > 0);\r
1432 Last = Node;\r
1433 ++BackwardCount;\r
1434 }\r
1435\r
1436 ASSERT (ForwardCount == BackwardCount);\r
1437\r
1438 DEBUG ((DEBUG_VERBOSE, "%a: Tree=%p BlackHeight=%Ld Count=%Ld\n",\r
1439 __FUNCTION__, Tree, (INT64)BlackHeight, (INT64)ForwardCount));\r
1440}\r