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