mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 10:33:11 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
395
sdk/lib/rtl/avlsupp.c
Normal file
395
sdk/lib/rtl/avlsupp.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Runtime Library
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: lib/rtl/avlsupp.c
|
||||
* PURPOSE: AVL Tree Internal Support Routines/Main Algorithms
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
/* Internal header for table entries */
|
||||
typedef struct _TABLE_ENTRY_HEADER
|
||||
{
|
||||
RTL_BALANCED_LINKS BalancedLinks;
|
||||
LONGLONG UserData;
|
||||
} TABLE_ENTRY_HEADER, *PTABLE_ENTRY_HEADER;
|
||||
|
||||
typedef enum _RTL_AVL_BALANCE_FACTOR
|
||||
{
|
||||
RtlUnbalancedAvlTree = -2,
|
||||
RtlLeftHeavyAvlTree,
|
||||
RtlBalancedAvlTree,
|
||||
RtlRightHeavyAvlTree,
|
||||
} RTL_AVL_BALANCE_FACTOR;
|
||||
|
||||
C_ASSERT(RtlBalancedAvlTree == 0);
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
FORCEINLINE
|
||||
TABLE_SEARCH_RESULT
|
||||
RtlpFindAvlTableNodeOrParent(IN PRTL_AVL_TABLE Table,
|
||||
IN PVOID Buffer,
|
||||
OUT PRTL_BALANCED_LINKS *NodeOrParent)
|
||||
{
|
||||
PRTL_BALANCED_LINKS CurrentNode, ChildNode;
|
||||
RTL_GENERIC_COMPARE_RESULTS Result;
|
||||
|
||||
/* Quick check to see if the table is empty */
|
||||
if (!Table->NumberGenericTableElements) return TableEmptyTree;
|
||||
|
||||
/* Set the current node */
|
||||
CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
|
||||
|
||||
/* Start compare loop */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Compare which side is greater */
|
||||
Result = RtlpAvlCompareRoutine(Table,
|
||||
Buffer,
|
||||
&((PTABLE_ENTRY_HEADER)CurrentNode)->
|
||||
UserData);
|
||||
if (Result == GenericLessThan)
|
||||
{
|
||||
/* We're less, check if this is the left child */
|
||||
ChildNode = RtlLeftChildAvl(CurrentNode);
|
||||
if (ChildNode)
|
||||
{
|
||||
/* Continue searching from this node */
|
||||
CurrentNode = ChildNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, the element isn't in this tree */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableInsertAsLeft;
|
||||
}
|
||||
}
|
||||
else if (Result == GenericGreaterThan)
|
||||
{
|
||||
/* We're more, check if this is the right child */
|
||||
ChildNode = RtlRightChildAvl(CurrentNode);
|
||||
if (ChildNode)
|
||||
{
|
||||
/* Continue searching from this node */
|
||||
CurrentNode = ChildNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, the element isn't in this tree */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableInsertAsRight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should've found the node */
|
||||
ASSERT(Result == GenericEqual);
|
||||
|
||||
/* Return node found */
|
||||
*NodeOrParent = CurrentNode;
|
||||
return TableFoundNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlpPromoteAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
|
||||
{
|
||||
PRTL_BALANCED_LINKS ParentNode, SuperParentNode;
|
||||
PRTL_BALANCED_LINKS *SwapNode1, *SwapNode2;
|
||||
|
||||
/* Grab parents up to 2 levels high */
|
||||
ParentNode = RtlParentAvl(Node);
|
||||
SuperParentNode = RtlParentAvl(ParentNode);
|
||||
|
||||
/* Pick which nodes will be rotated */
|
||||
SwapNode1 = RtlIsLeftChildAvl(Node) ? &ParentNode->LeftChild : &ParentNode->RightChild;
|
||||
SwapNode2 = RtlIsLeftChildAvl(Node) ? &Node->RightChild : &Node->LeftChild;
|
||||
|
||||
/* Do the rotate, and update the parent and super-parent as needed */
|
||||
*SwapNode1 = *SwapNode2;
|
||||
if (*SwapNode1) RtlSetParent(*SwapNode1, ParentNode);
|
||||
*SwapNode2 = ParentNode;
|
||||
RtlSetParent(ParentNode, Node);
|
||||
|
||||
/* Now update the super-parent child link, and make it parent of the node*/
|
||||
SwapNode1 = (RtlLeftChildAvl(SuperParentNode) == ParentNode) ?
|
||||
&SuperParentNode->LeftChild: &SuperParentNode->RightChild;
|
||||
*SwapNode1 = Node;
|
||||
RtlSetParent(Node, SuperParentNode);
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
RtlpRebalanceAvlTreeNode(IN PRTL_BALANCED_LINKS Node)
|
||||
{
|
||||
PRTL_BALANCED_LINKS ChildNode, SubChildNode;
|
||||
CHAR Balance;
|
||||
ASSERT(RtlParentAvl(Node) != Node);
|
||||
|
||||
/* Get the balance, and figure out which child node to go down on */
|
||||
Balance = RtlBalance(Node);
|
||||
ChildNode = (Balance == RtlRightHeavyAvlTree) ?
|
||||
RtlRightChildAvl(Node) : RtlLeftChildAvl(Node);
|
||||
|
||||
/* The child and node have the same balance, promote the child upwards */
|
||||
if (RtlBalance(ChildNode) == Balance)
|
||||
{
|
||||
/* This performs the rotation described in Knuth A8-A10 for Case 1 */
|
||||
RtlpPromoteAvlTreeNode(ChildNode);
|
||||
|
||||
/* The nodes are now balanced */
|
||||
RtlSetBalance(ChildNode, RtlBalancedAvlTree);
|
||||
RtlSetBalance(Node, RtlBalancedAvlTree);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The child has the opposite balance, a double promotion of the child's child must happen */
|
||||
if (RtlBalance(ChildNode) == -Balance)
|
||||
{
|
||||
/* Pick which sub-child to use based on the balance */
|
||||
SubChildNode = (Balance == RtlRightHeavyAvlTree) ?
|
||||
RtlLeftChildAvl(ChildNode) : RtlRightChildAvl(ChildNode);
|
||||
|
||||
/* Do the double-rotation described in Knuth A8-A10 for Case 2 */
|
||||
RtlpPromoteAvlTreeNode(SubChildNode);
|
||||
RtlpPromoteAvlTreeNode(SubChildNode);
|
||||
|
||||
/* Was the sub-child sharing the same balance as the node? */
|
||||
if (RtlBalance(SubChildNode) == Balance)
|
||||
{
|
||||
/* Then the subchild is now balanced, and the node's weight is inversed */
|
||||
RtlSetBalance(ChildNode, RtlBalancedAvlTree);
|
||||
RtlSetBalance(Node, -Balance);
|
||||
}
|
||||
else if (RtlBalance(SubChildNode) == -Balance)
|
||||
{
|
||||
/*
|
||||
* In this case, the sub-child weight was the inverse of the node, so
|
||||
* the child now shares the node's balance original weight, while the
|
||||
* node becomes balanced.
|
||||
*/
|
||||
RtlSetBalance(ChildNode, Balance);
|
||||
RtlSetBalance(Node, RtlBalancedAvlTree);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Otherwise, the sub-child was unbalanced, so both the child and node
|
||||
* now become balanced.
|
||||
*/
|
||||
RtlSetBalance(ChildNode, RtlBalancedAvlTree);
|
||||
RtlSetBalance(Node, RtlBalancedAvlTree);
|
||||
}
|
||||
|
||||
/* In all cases, the sub-child is now balanced */
|
||||
RtlSetBalance(SubChildNode, RtlBalancedAvlTree);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The case that remains is that the child was already balanced, so this is
|
||||
* This is the rotation required for Case 3 in Knuth A8-A10
|
||||
*/
|
||||
RtlpPromoteAvlTreeNode(ChildNode);
|
||||
|
||||
/* Now the child has the opposite weight of the node */
|
||||
RtlSetBalance(ChildNode, -Balance);
|
||||
|
||||
/* This only happens on deletion, so we return TRUE to terminate the delete */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlpInsertAvlTreeNode(IN PRTL_AVL_TABLE Table,
|
||||
IN PRTL_BALANCED_LINKS NewNode,
|
||||
IN OUT PVOID NodeOrParent,
|
||||
IN OUT TABLE_SEARCH_RESULT SearchResult)
|
||||
{
|
||||
CHAR Balance;
|
||||
|
||||
/* Initialize the new inserted element */
|
||||
MI_ASSERT(SearchResult != TableFoundNode);
|
||||
NewNode->LeftChild = NewNode->RightChild = NULL;
|
||||
RtlSetBalance(NewNode, RtlBalancedAvlTree);
|
||||
|
||||
/* Increase element count */
|
||||
Table->NumberGenericTableElements++;
|
||||
|
||||
/* Check where we should insert the entry */
|
||||
if (SearchResult == TableEmptyTree)
|
||||
{
|
||||
/* This is the new root node */
|
||||
RtlInsertAsRightChildAvl(&Table->BalancedRoot, NewNode);
|
||||
|
||||
/* On AVL trees, we also update the depth */
|
||||
ASSERT(Table->DepthOfTree == 0);
|
||||
Table->DepthOfTree = 1;
|
||||
return;
|
||||
}
|
||||
else if (SearchResult == TableInsertAsLeft)
|
||||
{
|
||||
/* Insert it left */
|
||||
RtlInsertAsLeftChildAvl(NodeOrParent, NewNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right node */
|
||||
RtlInsertAsRightChildAvl(NodeOrParent, NewNode);
|
||||
}
|
||||
|
||||
/* Little cheat to save on loop processing, taken from Timo */
|
||||
RtlSetBalance(&Table->BalancedRoot, RtlLeftHeavyAvlTree);
|
||||
|
||||
/*
|
||||
* This implements A6-A7 from Knuth based on http://coding.derkeiler.com
|
||||
* /pdf/Archive/C_CPP/comp.lang.c/2004-01/1812.pdf, however the algorithm
|
||||
* is slightly modified to follow the tree based on the Parent Node such
|
||||
* as the Windows algorithm does it, instead of following the nodes down.
|
||||
*/
|
||||
while (TRUE)
|
||||
{
|
||||
/* Calculate which side to balance on */
|
||||
Balance = RtlIsLeftChildAvl(NewNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
|
||||
|
||||
/* Check if the parent node was balanced */
|
||||
if (RtlBalance(NodeOrParent) == RtlBalancedAvlTree)
|
||||
{
|
||||
/* It's not balanced anymore (heavy on one side) */
|
||||
RtlSetBalance(NodeOrParent, Balance);
|
||||
|
||||
/* Move up */
|
||||
NewNode = NodeOrParent;
|
||||
NodeOrParent = RtlParentAvl(NodeOrParent);
|
||||
}
|
||||
else if (RtlBalance(NodeOrParent) != Balance)
|
||||
{
|
||||
/* The parent's balance is opposite, so the tree is balanced now */
|
||||
RtlSetBalance(NodeOrParent, RtlBalancedAvlTree);
|
||||
|
||||
/* Check if this is the root (the cheat applied earlier gets us here) */
|
||||
if (RtlBalance(&Table->BalancedRoot) == RtlBalancedAvlTree)
|
||||
{
|
||||
/* The depth has thus increased */
|
||||
Table->DepthOfTree++;
|
||||
}
|
||||
|
||||
/* We reached the root or a balanced node, so we're done */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tree is now unbalanced, so AVL rebalancing must happen */
|
||||
RtlpRebalanceAvlTreeNode(NodeOrParent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlpDeleteAvlTreeNode(IN PRTL_AVL_TABLE Table,
|
||||
IN PRTL_BALANCED_LINKS Node)
|
||||
{
|
||||
PRTL_BALANCED_LINKS DeleteNode = NULL, ParentNode;
|
||||
PRTL_BALANCED_LINKS *Node1, *Node2;
|
||||
CHAR Balance;
|
||||
|
||||
/* Take one of the children if possible */
|
||||
if (!(RtlLeftChildAvl(Node)) || !(RtlRightChildAvl(Node))) DeleteNode = Node;
|
||||
|
||||
/* Otherwise, check if one side is longer */
|
||||
if (!(DeleteNode) && (RtlBalance(Node) >= RtlBalancedAvlTree))
|
||||
{
|
||||
/* Pick the successor which will be the longest side in this case */
|
||||
DeleteNode = RtlRightChildAvl(Node);
|
||||
while (RtlLeftChildAvl(DeleteNode)) DeleteNode = RtlLeftChildAvl(DeleteNode);
|
||||
}
|
||||
else if (!DeleteNode)
|
||||
{
|
||||
/* Pick the predecessor which will be the longest side in this case */
|
||||
DeleteNode = RtlLeftChildAvl(Node);
|
||||
while (RtlRightChildAvl(DeleteNode)) DeleteNode = RtlRightChildAvl(DeleteNode);
|
||||
}
|
||||
|
||||
/* Get the parent node */
|
||||
ParentNode = RtlParentAvl(DeleteNode);
|
||||
DPRINT("Parent: %p\n", ParentNode);
|
||||
|
||||
/* Pick which now to use based on whether or not we have a left child */
|
||||
Node1 = RtlLeftChildAvl(DeleteNode) ? &DeleteNode->LeftChild : &DeleteNode->RightChild;
|
||||
DPRINT("Node 1: %p %p\n", Node1, *Node1);
|
||||
|
||||
/* Pick which node to swap based on if we're already a left child or not */
|
||||
Node2 = RtlIsLeftChildAvl(DeleteNode) ? &ParentNode->LeftChild : &ParentNode->RightChild;
|
||||
DPRINT("Node 2: %p %p\n", Node2, *Node2);
|
||||
|
||||
/* Pick the correct balance depending on which side will get heavier */
|
||||
Balance = RtlIsLeftChildAvl(DeleteNode) ? RtlLeftHeavyAvlTree : RtlRightHeavyAvlTree;
|
||||
DPRINT("Balance: %lx\n", Balance);
|
||||
|
||||
/* Swap the children nodes, making one side heavier */
|
||||
*Node2 = *Node1;
|
||||
|
||||
/* If the node has a child now, update its parent */
|
||||
if (*Node1) RtlSetParent(*Node1, ParentNode);
|
||||
|
||||
/* Assume balanced root for loop optimization */
|
||||
RtlSetBalance(&Table->BalancedRoot, RtlBalancedAvlTree);
|
||||
|
||||
/* Loop up the tree by parents */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Check if the tree's balance increased */
|
||||
if (RtlBalance(ParentNode) == Balance)
|
||||
{
|
||||
/* Now the tree is balanced */
|
||||
RtlSetBalance(ParentNode, RtlBalancedAvlTree);
|
||||
}
|
||||
else if (RtlBalance(ParentNode) == RtlBalancedAvlTree)
|
||||
{
|
||||
/* The tree has now become less balanced, since it was balanced */
|
||||
RtlSetBalance(ParentNode, -Balance);
|
||||
|
||||
/* Deal with the loop optimization to detect loss of a tree level */
|
||||
if (RtlBalance(&Table->BalancedRoot) != RtlBalancedAvlTree) Table->DepthOfTree--;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tree has become unbalanced, so a rebalance is needed */
|
||||
if (RtlpRebalanceAvlTreeNode(ParentNode)) break;
|
||||
|
||||
/* Get the new parent after the balance */
|
||||
ParentNode = RtlParentAvl(ParentNode);
|
||||
}
|
||||
|
||||
/* Choose which balance factor to use based on which side we're on */
|
||||
Balance = RtlIsRightChild(ParentNode) ?
|
||||
RtlRightHeavyAvlTree : RtlLeftHeavyAvlTree;
|
||||
|
||||
/* Iterate up the tree */
|
||||
ParentNode = RtlParentAvl(ParentNode);
|
||||
}
|
||||
|
||||
/* Check if this isn't the node we ended up deleting directly */
|
||||
if (Node == DeleteNode) return;
|
||||
|
||||
/* Copy the deleted node itself */
|
||||
RtlpCopyAvlNodeData(DeleteNode, Node);
|
||||
|
||||
/* Pick the right node to unlink */
|
||||
Node1 = RtlIsLeftChildAvl(Node) ?
|
||||
&(RtlParentAvl(DeleteNode))->LeftChild : &(RtlParentAvl(DeleteNode))->RightChild;
|
||||
*Node1 = DeleteNode;
|
||||
|
||||
/* Reparent as appropriate */
|
||||
if (RtlLeftChildAvl(DeleteNode)) RtlSetParent(RtlLeftChildAvl(DeleteNode), DeleteNode);
|
||||
if (RtlRightChildAvl(DeleteNode)) RtlSetParent(RtlRightChildAvl(DeleteNode), DeleteNode);
|
||||
}
|
||||
|
||||
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue