windows-nt/Source/XPSP1/NT/base/ntos/rtl/splay.c
2020-09-26 16:20:57 +08:00

1075 lines
25 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
Splay.c
Abstract:
This module implements the general splay utilities
Author:
Gary Kimura [GaryKi] 23-May-1989
Environment:
Pure utility routine
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#define SwapPointers(Ptr1, Ptr2) { \
PVOID _SWAP_POINTER_TEMP; \
_SWAP_POINTER_TEMP = (PVOID)(Ptr1); \
(Ptr1) = (Ptr2); \
(Ptr2) = _SWAP_POINTER_TEMP; \
}
#define ParentsChildPointerAddress(Links) ( \
RtlIsLeftChild(Links) ? \
&(((Links)->Parent)->LeftChild) \
: \
&(((Links)->Parent)->RightChild) \
)
VOID
SwapSplayLinks (
IN PRTL_SPLAY_LINKS Link1,
IN PRTL_SPLAY_LINKS Link2
);
PRTL_SPLAY_LINKS
RtlSplay (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The Splay function takes as input a pointer to a splay link in a tree
and splays the tree. Its function return value is a pointer to the
root of the splayed tree.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the root of the splayed tree.
--*/
{
PRTL_SPLAY_LINKS L;
PRTL_SPLAY_LINKS P;
PRTL_SPLAY_LINKS G;
//
// while links is not the root we need to keep rotating it toward
// the root
//
L = Links;
while (!RtlIsRoot(L)) {
P = RtlParent(L);
G = RtlParent(P);
if (RtlIsLeftChild(L)) {
if (RtlIsRoot(P)) {
/*
we have the following case
P L
/ \ / \
L c ==> a P
/ \ / \
a b b c
*/
//
// Connect P & b
//
P->LeftChild = L->RightChild;
if (P->LeftChild != NULL) {P->LeftChild->Parent = P;}
//
// Connect L & P
//
L->RightChild = P;
P->Parent = L;
//
// Make L the root
//
L->Parent = L;
} else if (RtlIsLeftChild(P)) {
/*
we have the following case
| |
G L
/ \ / \
P d ==> a P
/ \ / \
L c b G
/ \ / \
a b c d
*/
//
// Connect P & b
//
P->LeftChild = L->RightChild;
if (P->LeftChild != NULL) {P->LeftChild->Parent = P;}
//
// Connect G & c
//
G->LeftChild = P->RightChild;
if (G->LeftChild != NULL) {G->LeftChild->Parent = G;}
//
// Connect L & Great GrandParent
//
if (RtlIsRoot(G)) {
L->Parent = L;
} else {
L->Parent = G->Parent;
*(ParentsChildPointerAddress(G)) = L;
}
//
// Connect L & P
//
L->RightChild = P;
P->Parent = L;
//
// Connect P & G
//
P->RightChild = G;
G->Parent = P;
} else { // RtlIsRightChild(Parent)
/*
we have the following case
| |
G L
/ \ / \
a P G P
/ \ / \ / \
L d ==> a b c d
/ \
b c
*/
//
// Connect G & b
//
G->RightChild = L->LeftChild;
if (G->RightChild != NULL) {G->RightChild->Parent = G;}
//
// Connect P & c
//
P->LeftChild = L->RightChild;
if (P->LeftChild != NULL) {P->LeftChild->Parent = P;}
//
// Connect L & Great GrandParent
//
if (RtlIsRoot(G)) {
L->Parent = L;
} else {
L->Parent = G->Parent;
*(ParentsChildPointerAddress(G)) = L;
}
//
// Connect L & G
//
L->LeftChild = G;
G->Parent = L;
//
// Connect L & P
//
L->RightChild = P;
P->Parent = L;
}
} else { // RtlIsRightChild(L)
if (RtlIsRoot(P)) {
/*
we have the following case
P L
/ \ / \
a L P c
/ \ / \
b c ==> a b
*/
//
// Connect P & b
//
P->RightChild = L->LeftChild;
if (P->RightChild != NULL) {P->RightChild->Parent = P;}
//
// Connect P & L
//
L->LeftChild = P;
P->Parent = L;
//
// Make L the root
//
L->Parent = L;
} else if (RtlIsRightChild(P)) {
/*
we have the following case
| |
G L
/ \ / \
a P P d
/ \ / \
b L G c
/ \ / \
c d ==> a b
*/
//
// Connect G & b
//
G->RightChild = P->LeftChild;
if (G->RightChild != NULL) {G->RightChild->Parent = G;}
//
// Connect P & c
//
P->RightChild = L->LeftChild;
if (P->RightChild != NULL) {P->RightChild->Parent = P;}
//
// Connect L & Great GrandParent
//
if (RtlIsRoot(G)) {
L->Parent = L;
} else {
L->Parent = G->Parent;
*(ParentsChildPointerAddress(G)) = L;
}
//
// Connect L & P
//
L->LeftChild = P;
P->Parent = L;
//
// Connect P & G
//
P->LeftChild = G;
G->Parent = P;
} else { // RtlIsLeftChild(P)
/*
we have the following case
| |
G L
/ \ / \
P d P G
/ \ / \ / \
a L ==> a b c d
/ \
b c
*/
//
// Connect P & b
//
P->RightChild = L->LeftChild;
if (P->RightChild != NULL) {P->RightChild->Parent = P;}
//
// Connect G & c
//
G->LeftChild = L->RightChild;
if (G->LeftChild != NULL) {G->LeftChild->Parent = G;}
//
// Connect L & Great GrandParent
//
if (RtlIsRoot(G)) {
L->Parent = L;
} else {
L->Parent = G->Parent;
*(ParentsChildPointerAddress(G)) = L;
}
//
// Connect L & P
//
L->LeftChild = P;
P->Parent = L;
//
// Connect L & G
//
L->RightChild = G;
G->Parent = L;
}
}
}
return L;
}
PRTL_SPLAY_LINKS
RtlDelete (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The Delete function takes as input a pointer to a splay link in a tree
and deletes that node from the tree. Its function return value is a
pointer to the root of the tree. If the tree is now empty, the return
value is NULL.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the root of the tree.
--*/
{
PRTL_SPLAY_LINKS Predecessor;
PRTL_SPLAY_LINKS Parent;
PRTL_SPLAY_LINKS Child;
PRTL_SPLAY_LINKS *ParentChildPtr;
//
// First check to see if Links as two children. If it does then swap
// Links with its subtree predecessor. Now we are guaranteed that Links
// has at most one child.
//
if ((RtlLeftChild(Links) != NULL) && (RtlRightChild(Links) != NULL)) {
//
// get the predecessor, and swap their position in the tree
//
Predecessor = RtlSubtreePredecessor(Links);
SwapSplayLinks(Predecessor, Links);
}
//
// If Links has no children then delete links by checking if it is
// already the root or has a parent. If it is the root then the
// tree is now empty, otherwise it set the appropriate parent's child
// pointer (i.e., the one to links) to NULL, and splay the parent.
//
if ((RtlLeftChild(Links) == NULL) && (RtlRightChild(Links) == NULL)) {
//
// Links has no children, if it is the root then return NULL
//
if (RtlIsRoot(Links)) {
return NULL;
}
//
// Links as not children and is not the root, so to the parent's
// child pointer to NULL and splay the parent.
//
Parent = RtlParent(Links);
ParentChildPtr = ParentsChildPointerAddress(Links);
*ParentChildPtr = NULL;
return RtlSplay(Parent);
}
//
// otherwise Links has one child. If it is the root then make the child
// the new root, otherwise link together the child and parent, and splay
// the parent. But first remember who our child is.
//
if (RtlLeftChild(Links) != NULL) {
Child = RtlLeftChild(Links);
} else {
Child = RtlRightChild(Links);
}
//
// If links is the root then we make the child the root and return the
// child.
//
if (RtlIsRoot(Links)) {
Child->Parent = Child;
return Child;
}
//
// Links is not the root, so set link's parent child pointer to be
// the child and the set child's parent to be link's parent, and splay
// the parent.
//
ParentChildPtr = ParentsChildPointerAddress(Links);
*ParentChildPtr = Child;
Child->Parent = Links->Parent;
return RtlSplay(RtlParent(Child));
}
VOID
RtlDeleteNoSplay (
IN PRTL_SPLAY_LINKS Links,
IN OUT PRTL_SPLAY_LINKS *Root
)
/*++
Routine Description:
The Delete function takes as input a pointer to a splay link in a tree,
a pointer to the callers pointer to the tree and deletes that node from
the tree. The caller's pointer is updated upon return. If the tree is
now empty, the value is NULL.
Unfortunately, the original RtlDelete() always splays and this is not
always a desireable side-effect.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Root - Pointer to the callers pointer to the root
Return Value:
None
--*/
{
PRTL_SPLAY_LINKS Predecessor;
PRTL_SPLAY_LINKS Parent;
PRTL_SPLAY_LINKS Child;
PRTL_SPLAY_LINKS *ParentChildPtr;
//
// First check to see if Links as two children. If it does then swap
// Links with its subtree predecessor. Now we are guaranteed that Links
// has at most one child.
//
if ((RtlLeftChild(Links) != NULL) && (RtlRightChild(Links) != NULL)) {
//
// get the predecessor, and swap their position in the tree
//
Predecessor = RtlSubtreePredecessor(Links);
if (RtlIsRoot(Links)) {
//
// If we're switching with the root of the tree, fix the
// caller's root pointer
//
*Root = Predecessor;
}
SwapSplayLinks(Predecessor, Links);
}
//
// If Links has no children then delete links by checking if it is
// already the root or has a parent. If it is the root then the
// tree is now empty, otherwise it set the appropriate parent's child
// pointer (i.e., the one to links) to NULL.
//
if ((RtlLeftChild(Links) == NULL) && (RtlRightChild(Links) == NULL)) {
//
// Links has no children, if it is the root then set root to NULL
//
if (RtlIsRoot(Links)) {
*Root = NULL;
return;
}
//
// Links as not children and is not the root, so to the parent's
// child pointer to NULL.
//
ParentChildPtr = ParentsChildPointerAddress(Links);
*ParentChildPtr = NULL;
return;
}
//
// otherwise Links has one child. If it is the root then make the child
// the new root, otherwise link together the child and parent. But first
// remember who our child is.
//
if (RtlLeftChild(Links) != NULL) {
Child = RtlLeftChild(Links);
} else {
Child = RtlRightChild(Links);
}
//
// If links is the root then we make the child the root and return the
// child.
//
if (RtlIsRoot(Links)) {
Child->Parent = Child;
*Root = Child;
return;
}
//
// Links is not the root, so set link's parent child pointer to be
// the child and the set child's parent to be link's parent.
//
ParentChildPtr = ParentsChildPointerAddress(Links);
*ParentChildPtr = Child;
Child->Parent = Links->Parent;
return;
}
PRTL_SPLAY_LINKS
RtlSubtreeSuccessor (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The SubtreeSuccessor function takes as input a pointer to a splay link
in a tree and returns a pointer to the successor of the input node of
the substree rooted at the input node. If there is not a successor, the
return value is NULL.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the successor in the subtree
--*/
{
PRTL_SPLAY_LINKS Ptr;
/*
check to see if there is a right subtree to the input link
if there is then the subtree successor is the left most node in
the right subtree. That is find and return P in the following diagram
Links
\
.
.
.
/
P
\
*/
if ((Ptr = RtlRightChild(Links)) != NULL) {
while (RtlLeftChild(Ptr) != NULL) {
Ptr = RtlLeftChild(Ptr);
}
return Ptr;
}
//
// otherwise we are do not have a subtree successor so we simply return
// NULL
//
return NULL;
}
PRTL_SPLAY_LINKS
RtlSubtreePredecessor (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The SubtreePredecessor function takes as input a pointer to a splay link
in a tree and returns a pointer to the predecessor of the input node of
the substree rooted at the input node. If there is not a predecessor,
the return value is NULL.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the predecessor in the subtree
--*/
{
PRTL_SPLAY_LINKS Ptr;
//
// check to see if there is a left subtree to the input link
// if there is then the subtree predecessor is the right most node in
// the left subtree. That is find and return P in the following diagram
//
// Links
// /
// .
// .
// .
// P
// /
//
if ((Ptr = RtlLeftChild(Links)) != NULL) {
while (RtlRightChild(Ptr) != NULL) {
Ptr = RtlRightChild(Ptr);
}
return Ptr;
}
//
// otherwise we are do not have a subtree predecessor so we simply return
// NULL
//
return NULL;
}
PRTL_SPLAY_LINKS
RtlRealSuccessor (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The RealSuccessor function takes as input a pointer to a splay link
in a tree and returns a pointer to the successor of the input node within
the entire tree. If there is not a successor, the return value is NULL.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the successor in the entire tree
--*/
{
PRTL_SPLAY_LINKS Ptr;
/*
first check to see if there is a right subtree to the input link
if there is then the real successor is the left most node in
the right subtree. That is find and return P in the following diagram
Links
\
.
.
.
/
P
\
*/
if ((Ptr = RtlRightChild(Links)) != NULL) {
while (RtlLeftChild(Ptr) != NULL) {
Ptr = RtlLeftChild(Ptr);
}
return Ptr;
}
/*
we do not have a right child so check to see if have a parent and if
so find the first ancestor that we are a left decendent of. That
is find and return P in the following diagram
P
/
.
.
.
Links
*/
Ptr = Links;
while (RtlIsRightChild(Ptr)) {
Ptr = RtlParent(Ptr);
}
if (RtlIsLeftChild(Ptr)) {
return RtlParent(Ptr);
}
//
// otherwise we are do not have a real successor so we simply return
// NULL
//
return NULL;
}
PRTL_SPLAY_LINKS
RtlRealPredecessor (
IN PRTL_SPLAY_LINKS Links
)
/*++
Routine Description:
The RealPredecessor function takes as input a pointer to a splay link
in a tree and returns a pointer to the predecessor of the input node
within the entire tree. If there is not a predecessor, the return value
is NULL.
Arguments:
Links - Supplies a pointer to a splay link in a tree.
Return Value:
PRTL_SPLAY_LINKS - returns a pointer to the predecessor in the entire tree
--*/
{
PRTL_SPLAY_LINKS Ptr;
/*
first check to see if there is a left subtree to the input link
if there is then the real predecessor is the right most node in
the left subtree. That is find and return P in the following diagram
Links
/
.
.
.
P
/
*/
if ((Ptr = RtlLeftChild(Links)) != NULL) {
while (RtlRightChild(Ptr) != NULL) {
Ptr = RtlRightChild(Ptr);
}
return Ptr;
}
/*
we do not have a left child so check to see if have a parent and if
so find the first ancestor that we are a right decendent of. That
is find and return P in the following diagram
P
\
.
.
.
Links
*/
Ptr = Links;
while (RtlIsLeftChild(Ptr)) {
Ptr = RtlParent(Ptr);
}
if (RtlIsRightChild(Ptr)) {
return RtlParent(Ptr);
}
//
// otherwise we are do not have a real predecessor so we simply return
// NULL
//
return NULL;
}
VOID
SwapSplayLinks (
IN PRTL_SPLAY_LINKS Link1,
IN PRTL_SPLAY_LINKS Link2
)
{
PRTL_SPLAY_LINKS *Parent1ChildPtr;
PRTL_SPLAY_LINKS *Parent2ChildPtr;
/*
We have the following situation
Parent1 Parent2
| |
| |
Link1 Link2
/ \ / \
/ \ / \
LC1 RC1 LC2 RC2
where one of the links can possibly be the root and one of the links
can possibly be a direct child of the other. Without loss of
generality we'll make link2 be the possible and root and link1 be
the possible child.
*/
if ((RtlIsRoot(Link1)) || (RtlParent(Link2) == Link1)) {
SwapPointers(Link1, Link2);
}
//
// The four cases we need to handle are
//
// 1. Link1 is not a child of link2 and link2 is not the root
// 2. Link1 is not a child of link2 and link2 is the root
// 3. Link1 is a child of link2 and link2 is not the root
// 4. Link1 is a child of link2 and link2 is the root
//
//
// Each case will be handled separately
//
if (RtlParent(Link1) != Link2) {
if (!RtlIsRoot(Link2)) {
//
// Case 1 the initial steps are:
//
// 1. get both parent child pointers
// 2. swap the parent child pointers
// 3. swap the parent pointers
//
Parent1ChildPtr = ParentsChildPointerAddress(Link1);
Parent2ChildPtr = ParentsChildPointerAddress(Link2);
SwapPointers(*Parent1ChildPtr, *Parent2ChildPtr);
SwapPointers(Link1->Parent, Link2->Parent);
} else {
//
// Case 2 the initial steps are:
//
// 1. Set link1's parent child pointer to link2
// 2. Set parent pointer of link2 to link1's parent
// 3. Set parent pointer of link1 to be itself
//
Parent1ChildPtr = ParentsChildPointerAddress(Link1);
*Parent1ChildPtr = Link2;
Link2->Parent = Link1->Parent;
Link1->Parent = Link1;
}
//
// Case 1 and 2 common steps are:
//
// 1. swap the child pointers
//
SwapPointers(Link1->LeftChild, Link2->LeftChild);
SwapPointers(Link1->RightChild, Link2->RightChild);
} else { // RtlParent(Link1) == Link2
if (!RtlIsRoot(Link2)) {
//
// Case 3 the initial steps are:
//
// 1. Set Link2's parent child pointer to link1
// 2. Set Link1's parent pointer to parent of link2
//
Parent2ChildPtr = ParentsChildPointerAddress(Link2);
*Parent2ChildPtr = Link1;
Link1->Parent = Link2->Parent;
} else {
//
// Case 4 the initial steps are:
//
// 1. Set Link1's parent pointer to be link1
//
Link1->Parent = Link1;
}
//
// Case 3 and 4 common steps are:
//
// 1. Swap the child pointers
// 2. if link1 was a left child (i.e., RtlLeftChild(Link1) == Link1)
// then set left child of link1 to link2
// else set right child of link1 to link2
//
SwapPointers(Link1->LeftChild, Link2->LeftChild);
SwapPointers(Link1->RightChild, Link2->RightChild);
if (Link1->LeftChild == Link1) {
Link1->LeftChild = Link2;
} else {
Link1->RightChild = Link2;
}
}
//
// Case 1, 2, 3, 4 common (and final) steps are:
//
// 1. Fix the parent pointers of the left and right children
//
if (Link1->LeftChild != NULL) {Link1->LeftChild->Parent = Link1;}
if (Link1->RightChild != NULL) {Link1->RightChild->Parent = Link1;}
if (Link2->LeftChild != NULL) {Link2->LeftChild->Parent = Link2;}
if (Link2->RightChild != NULL) {Link2->RightChild->Parent = Link2;}
}