3 * Copyright (C) 1998-2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
22 * PURPOSE: Splay tree support
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * NOTES: Based on a splay tree implementation by
25 * Daniel Stenberg <Daniel.Stenberg@sth.frontec.se>
26 * http://www.contactor.se/~dast/stuff/dsplay-1.2.tar.gz
28 * 15-03-2002 CSH Created
30 #include <ddk/ntddk.h>
31 #include <internal/ex.h>
34 #include <internal/debug.h>
36 /* DATA **********************************************************************/
41 typedef struct _SPLAY_TREE_NODE
43 /* Children on this branch that has smaller keys than this node */
44 struct _SPLAY_TREE_NODE * SmallerChild;
46 /* Children on this branch that has larger keys than this node */
47 struct _SPLAY_TREE_NODE * LargerChild;
49 /* Points to a node with identical key */
50 struct _SPLAY_TREE_NODE * Same;
52 /* Key of this node */
55 /* Value of this node */
58 /* The number of nodes rooted here */
60 } SPLAY_TREE_NODE, *PSPLAY_TREE_NODE;
62 typedef struct _TRAVERSE_CONTEXT {
63 PTRAVERSE_ROUTINE Routine;
65 } TRAVERSE_CONTEXT, *PTRAVERSE_CONTEXT;
68 #define SEARCH_INDEX 1
69 #define INSERT_INDEX 2
70 #define REMOVE_INDEX 3
72 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_SPLAY)(PSPLAY_TREE Tree,
74 PSPLAY_TREE_NODE Node);
76 typedef BOOLEAN (*PSPLAY_TREE_SEARCH)(PSPLAY_TREE Tree,
78 PSPLAY_TREE_NODE Node,
79 PSPLAY_TREE_NODE * ReturnNode);
81 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_INSERT)(PSPLAY_TREE Tree,
83 PSPLAY_TREE_NODE Node,
84 PSPLAY_TREE_NODE New);
86 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_REMOVE)(PSPLAY_TREE Tree,
88 PSPLAY_TREE_NODE Node,
89 PSPLAY_TREE_NODE * RemovedNode);
91 /* FUNCTIONS ****************************************************************/
93 #define ExpSplayTreeRootNode(Tree)(((PSPLAY_TREE) (Tree))->RootNode)
94 #define ExpSplayTreeNodeKey(Node)((Node)->Key)
95 #define ExpSplayTreeNodeValue(Node)((Node)->Value)
96 #define ExpSplayTreeSmallerChildNode(Node)((Node)->SmallerChild)
97 #define ExpSplayTreeLargerChildNode(Node)((Node)->LargerChild)
98 #define ExpSplayTreeNodeEqual(Equality)((Equality) == 0)
99 #define ExpSplayTreeNodeLess(Equality)((Equality) < 0)
100 #define ExpSplayTreeNodeMore(Equality)((Equality) > 0)
101 #define ExpSplayTreeNodeSame(Node)((Node)->Same)
102 #define ExpSplayTreeNodeWeight(Node)((Node)->Weight)
103 #define ExpSplayTreeNodeGetWeight(Node)(((Node) == NULL) ? 0 : ((Node)->Weight))
104 #define ExpSplayTreeNodeSetWeight(Node, _Weight)((Node)->Weight = (_Weight))
106 #define KEY_NOTUSED (PVOID)-1
110 * Lock the splay tree
113 ExpLockSplayTree(PSPLAY_TREE Tree,
116 if (Tree->UseNonPagedPool)
118 KeAcquireSpinLock(&Tree->Lock.NonPaged, OldIrql);
122 ExAcquireFastMutex(&Tree->Lock.Paged);
128 * Unlock the splay tree
131 ExpUnlockSplayTree(PSPLAY_TREE Tree,
134 if (Tree->UseNonPagedPool)
136 KeReleaseSpinLock(&Tree->Lock.NonPaged, *OldIrql);
140 ExReleaseFastMutex(&Tree->Lock.Paged);
146 * Allocate resources for a new node and initialize it.
148 inline PSPLAY_TREE_NODE
149 ExpCreateSplayTreeNode(PSPLAY_TREE Tree,
152 PSPLAY_TREE_NODE Node;
154 if (Tree->UseNonPagedPool)
156 Node = (PSPLAY_TREE_NODE) ExAllocateFromNPagedLookasideList(&Tree->List.NonPaged);
160 Node = (PSPLAY_TREE_NODE) ExAllocateFromPagedLookasideList(&Tree->List.Paged);
165 ExpSplayTreeSmallerChildNode(Node) = NULL;
166 ExpSplayTreeLargerChildNode(Node) = NULL;
167 ExpSplayTreeNodeValue(Node) = Value;
174 * Release resources for the node.
177 ExpDestroySplayTreeNode(PSPLAY_TREE Tree,
178 PSPLAY_TREE_NODE Node)
180 if (Tree->UseNonPagedPool)
182 ExFreeToNPagedLookasideList(&Tree->List.NonPaged, Node);
186 ExFreeToPagedLookasideList(&Tree->List.Paged, Node);
192 * Splay using the key 'Key' (which may or may not be in the tree). The starting
194 * The lock for the tree must be acquired when this routine is called.
195 * This routine does not maintain weight information.
198 ExpSplayTreeNoWeight(PSPLAY_TREE Tree,
200 PSPLAY_TREE_NODE Node)
212 ExpSplayTreeSmallerChildNode(&N) = NULL;
213 ExpSplayTreeLargerChildNode(&N) = NULL;
219 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
221 if (ExpSplayTreeNodeLess(Equality))
223 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
226 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node)));
227 if (ExpSplayTreeNodeLess(ChildEquality))
229 y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */
230 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y);
231 ExpSplayTreeLargerChildNode(y) = Node;
234 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
238 ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */
240 Node = ExpSplayTreeSmallerChildNode(Node);
242 else if (ExpSplayTreeNodeMore(Equality))
244 if (ExpSplayTreeLargerChildNode(Node) == NULL)
247 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node)));
248 if (ExpSplayTreeNodeMore(ChildEquality))
250 y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */
251 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y);
252 ExpSplayTreeSmallerChildNode(y) = Node;
255 if (ExpSplayTreeLargerChildNode(Node) == NULL)
259 ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */
261 Node = ExpSplayTreeLargerChildNode(Node);
269 ExpSplayTreeLargerChildNode(l) = NULL;
270 ExpSplayTreeSmallerChildNode(r) = NULL;
272 ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */
273 ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node);
274 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N);
275 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N);
282 * Splay using the key 'Key' (which may or may not be in the tree). The starting
284 * The lock for the tree must be acquired when this routine is called.
285 * This routine maintains weight information.
288 ExpSplayTreeWeight(PSPLAY_TREE Tree,
290 PSPLAY_TREE_NODE Node)
307 ExpSplayTreeSmallerChildNode(&N) = NULL;
308 ExpSplayTreeLargerChildNode(&N) = NULL;
313 RootWeight = ExpSplayTreeNodeGetWeight(Node);
320 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
322 if (ExpSplayTreeNodeLess(Equality))
324 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
327 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node)));
328 if (ExpSplayTreeNodeLess(ChildEquality))
330 y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */
331 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y);
332 ExpSplayTreeLargerChildNode(y) = Node;
335 ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
336 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1);
340 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
344 ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */
346 Node = ExpSplayTreeSmallerChildNode(Node);
349 Weight2 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(r));
352 else if (ExpSplayTreeNodeMore(Equality))
354 if (ExpSplayTreeLargerChildNode(Node) == NULL)
357 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node)));
358 if (ExpSplayTreeNodeMore(ChildEquality))
360 y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */
361 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y);
362 ExpSplayTreeSmallerChildNode(y) = Node;
365 ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
366 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1);
370 if (ExpSplayTreeLargerChildNode(Node) == NULL)
374 ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */
376 Node = ExpSplayTreeLargerChildNode(Node);
379 Weight1 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(l));
390 Weight1 += ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)); /* Now Weight1 and Weight2 are the weights of */
391 Weight2 += ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)); /* The 'smaller' and 'larger' trees we just built. */
392 ExpSplayTreeNodeSetWeight(Node, Weight1 + Weight2 + 1);
395 ExpSplayTreeLargerChildNode(l) = NULL;
396 ExpSplayTreeSmallerChildNode(r) = NULL;
399 /* The following two loops correct the weight fields of the right path from
400 * the left child of the root and the right path from the left child of the
403 for (y = ExpSplayTreeLargerChildNode(&N); y != NULL; y = ExpSplayTreeLargerChildNode(y)) {
404 ExpSplayTreeNodeSetWeight(y, Weight1);
405 Weight1 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(y));
407 for (y = ExpSplayTreeSmallerChildNode(&N); y != NULL; y = ExpSplayTreeSmallerChildNode(y)) {
408 ExpSplayTreeNodeSetWeight(y, Weight2);
409 Weight2 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(y));
413 ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */
414 ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node);
415 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N);
416 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N);
422 inline PSPLAY_TREE_NODE
423 ExpSplayTree(PSPLAY_TREE Tree,
425 PSPLAY_TREE_NODE Node)
427 return (*((PSPLAY_TREE_SPLAY)Tree->Reserved[SPLAY_INDEX]))(Tree, Key, Node);
432 * The lock for the tree must be acquired when this routine is called.
433 * This routine does not maintain weight information.
436 ExpSearchSplayTreeNoWeight(PSPLAY_TREE Tree,
438 PSPLAY_TREE_NODE Node,
439 PSPLAY_TREE_NODE * ReturnNode)
446 Node = ExpSplayTree(Tree, Key, Node);
448 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
449 if (ExpSplayTreeNodeEqual(Equality))
458 *ReturnNode = NULL; /* No match */
459 return FALSE; /* It wasn't there */
465 * The lock for the tree must be acquired when this routine is called.
466 * This routine maintains weight information.
469 ExpSearchSplayTreeWeight(PSPLAY_TREE Tree,
471 PSPLAY_TREE_NODE Node,
472 PSPLAY_TREE_NODE * ReturnNode)
474 PSPLAY_TREE_NODE x = NULL;
484 tweight = ExpSplayTreeNodeGetWeight(Node);
487 Node = ExpSplayTree(Tree, Key, Node);
489 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
490 if (ExpSplayTreeNodeEqual(Equality))
497 ExpSplayTreeNodeSetWeight(x, tweight - 1);
506 *ReturnNode = NULL; /* No match */
507 return FALSE; /* It wasn't there */
513 ExpSearchSplayTree(PSPLAY_TREE Tree,
515 PSPLAY_TREE_NODE Node,
516 PSPLAY_TREE_NODE * ReturnNode)
518 return (*((PSPLAY_TREE_SEARCH)Tree->Reserved[SEARCH_INDEX]))(Tree, Key, Node, ReturnNode);
523 * The lock for the tree must be acquired when this routine is called.
524 * This routine does not maintain weight information.
527 ExpInsertSplayTreeNoWeight(PSPLAY_TREE Tree,
529 PSPLAY_TREE_NODE Node,
530 PSPLAY_TREE_NODE New)
539 Node = ExpSplayTree(Tree, Key, Node);
541 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
542 if (ExpSplayTreeNodeEqual(Equality))
547 /* This is how to prevent the same node key getting added twice */
552 /* It already exists one of this size */
554 ExpSplayTreeNodeSame(New) = Node;
555 ExpSplayTreeNodeKey(New) = Key;
556 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
557 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
559 ExpSplayTreeSmallerChildNode(Node) = New;
560 ExpSplayTreeNodeKey(Node) = KEY_NOTUSED;
572 ExpSplayTreeSmallerChildNode(New) = NULL;
573 ExpSplayTreeLargerChildNode(New) = NULL;
575 else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node))))
577 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
578 ExpSplayTreeLargerChildNode(New) = Node;
579 ExpSplayTreeSmallerChildNode(Node) = NULL;
583 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
584 ExpSplayTreeSmallerChildNode(New) = Node;
585 ExpSplayTreeLargerChildNode(Node) = NULL;
588 ExpSplayTreeNodeKey(New) = Key;
591 /* No identical nodes (yet) */
592 ExpSplayTreeNodeSame(New) = NULL;
600 * The lock for the tree must be acquired when this routine is called.
601 * This routine maintains weight information.
604 ExpInsertSplayTreeWeight(PSPLAY_TREE Tree,
606 PSPLAY_TREE_NODE Node,
607 PSPLAY_TREE_NODE New)
616 Node = ExpSplayTree(Tree, Key, Node);
618 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
619 if (ExpSplayTreeNodeEqual(Equality))
624 /* This is how to prevent the same node key getting added twice */
629 /* It already exists one of this size */
631 ExpSplayTreeNodeSame(New) = Node;
632 ExpSplayTreeNodeKey(New) = Key;
633 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
634 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
637 ExpSplayTreeNodeSetWeight(New, ExpSplayTreeNodeGetWeight(Node));
640 ExpSplayTreeSmallerChildNode(Node) = New;
641 ExpSplayTreeNodeKey(Node) = KEY_NOTUSED;
653 ExpSplayTreeSmallerChildNode(New) = NULL;
654 ExpSplayTreeLargerChildNode(New) = NULL;
656 else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node))))
658 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
659 ExpSplayTreeLargerChildNode(New) = Node;
660 ExpSplayTreeSmallerChildNode(Node) = NULL;
663 ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)));
669 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
670 ExpSplayTreeSmallerChildNode(New) = Node;
671 ExpSplayTreeLargerChildNode(Node) = NULL;
674 ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)));
679 ExpSplayTreeNodeKey(New) = Key;
682 ExpSplayTreeNodeSetWeight(New, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(New))
683 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(New)));
687 /* No identical nodes (yet) */
688 ExpSplayTreeNodeSame(New) = NULL;
695 inline PSPLAY_TREE_NODE
696 ExpInsertSplayTree(PSPLAY_TREE Tree,
698 PSPLAY_TREE_NODE Node,
699 PSPLAY_TREE_NODE New)
701 return (*((PSPLAY_TREE_INSERT)Tree->Reserved[INSERT_INDEX]))(Tree, Key, Node, New);
706 * Deletes the node with key 'Key' from the tree if it's there.
707 * Return a pointer to the resulting tree.
708 * The lock for the tree must be acquired when this routine is called.
709 * This routine does not maintain weight information.
712 ExpRemoveSplayTreeNoWeight(PSPLAY_TREE Tree,
714 PSPLAY_TREE_NODE Node,
715 PSPLAY_TREE_NODE * RemovedNode)
723 Node = ExpSplayTree(Tree, Key, Node);
725 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
726 if (ExpSplayTreeNodeEqual(Equality))
731 /* FIRST! Check if there is a list with identical sizes */
732 x = ExpSplayTreeNodeSame(Node);
735 /* There is several, pick one from the list */
737 /* 'x' is the new root node */
739 ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node);
740 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
741 ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node);
748 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
750 x = ExpSplayTreeLargerChildNode(Node);
754 x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node));
755 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
763 *RemovedNode = NULL; /* No match */
764 return Node; /* It wasn't there */
770 * Deletes the node with key 'Key' from the tree if it's there.
771 * Return a pointer to the resulting tree.
772 * The lock for the tree must be acquired when this routine is called.
773 * This routine maintains weight information.
776 ExpRemoveSplayTreeWeight(PSPLAY_TREE Tree,
778 PSPLAY_TREE_NODE Node,
779 PSPLAY_TREE_NODE * RemovedNode)
792 tweight = ExpSplayTreeNodeGetWeight(Node);
795 Node = ExpSplayTree(Tree, Key, Node);
797 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
798 if (ExpSplayTreeNodeEqual(Equality))
803 /* FIRST! Check if there is a list with identical sizes */
804 x = ExpSplayTreeNodeSame(Node);
807 /* There is several, pick one from the list */
809 /* 'x' is the new root node */
811 ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node);
812 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
813 ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node);
816 ExpSplayTreeNodeSetWeight(x, ExpSplayTreeNodeGetWeight(Node));
824 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
826 x = ExpSplayTreeLargerChildNode(Node);
830 x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node));
831 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
838 ExpSplayTreeNodeSetWeight(x, tweight - 1);
846 *RemovedNode = NULL; /* No match */
847 return Node; /* It wasn't there */
852 inline PSPLAY_TREE_NODE
853 ExpRemoveSplayTree(PSPLAY_TREE Tree,
855 PSPLAY_TREE_NODE Node,
856 PSPLAY_TREE_NODE * RemovedNode)
858 return (*((PSPLAY_TREE_REMOVE)Tree->Reserved[REMOVE_INDEX]))(Tree, Key, Node, RemovedNode);
863 * The lock for the tree must be acquired when this routine is called.
866 ExpPrintSplayTree(PSPLAY_TREE Tree,
867 PSPLAY_TREE_NODE Node,
877 Distance += ExpPrintSplayTree(Tree, ExpSplayTreeLargerChildNode(Node), Distance + 1);
879 for (i = 0; i < Distance; i++)
886 DbgPrint("%d(%d)[%d]", ExpSplayTreeNodeKey(Node), ExpSplayTreeNodeGetWeight(Node), i);
890 DbgPrint("%d[%d]", ExpSplayTreeNodeKey(Node), i);
893 for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n))
902 d += ExpPrintSplayTree(Tree, ExpSplayTreeSmallerChildNode(Node), Distance + 1);
913 * The lock for the tree must be acquired when this routine is called.
914 * Returns the new root of the tree.
915 * Use of this routine could improve performance, or it might not.
916 * FIXME: Do some performance tests
919 ExpSplayTreeMaxTreeWeight(PSPLAY_TREE Tree,
920 PSPLAY_TREE_NODE Node)
922 PSPLAY_TREE_NODE First = Node;
927 Diff = ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
928 - ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node));
930 if (Diff >= MAX_DIFF)
932 Node = ExpSplayTreeSmallerChildNode(Node);
934 else if (Diff <= -MAX_DIFF)
936 Node = ExpSplayTreeLargerChildNode(Node);
940 } while (abs(Diff) >= MAX_DIFF);
943 return ExpSplayTree(Tree, ExpSplayTreeNodeKey(Node), First);
952 * Traverse a splay tree using preorder traversal method.
953 * Returns FALSE, if the traversal was terminated prematurely or
954 * TRUE if the callback routine did not request that the traversal
955 * be terminated prematurely.
956 * The lock for the tree must be acquired when this routine is called.
959 ExpTraverseSplayTreePreorder(PTRAVERSE_CONTEXT Context,
960 PSPLAY_TREE_NODE Node)
967 /* Call the traversal routine */
968 if (!(*Context->Routine)(Context->Context,
969 ExpSplayTreeNodeKey(Node),
970 ExpSplayTreeNodeValue(Node)))
975 for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n))
977 /* Call the traversal routine */
978 if (!(*Context->Routine)(Context->Context,
979 ExpSplayTreeNodeKey(n),
980 ExpSplayTreeNodeValue(n)))
986 /* Traverse 'smaller' subtree */
987 ExpTraverseSplayTreePreorder(Context, ExpSplayTreeSmallerChildNode(Node));
989 /* Traverse 'larger' subtree */
990 ExpTraverseSplayTreePreorder(Context, ExpSplayTreeLargerChildNode(Node));
997 * Traverse a splay tree using inorder traversal method.
998 * Returns FALSE, if the traversal was terminated prematurely or
999 * TRUE if the callback routine did not request that the traversal
1000 * be terminated prematurely.
1001 * The lock for the tree must be acquired when this routine is called.
1004 ExpTraverseSplayTreeInorder(PTRAVERSE_CONTEXT Context,
1005 PSPLAY_TREE_NODE Node)
1012 /* Traverse 'smaller' subtree */
1013 ExpTraverseSplayTreeInorder(Context, ExpSplayTreeSmallerChildNode(Node));
1015 /* Call the traversal routine */
1016 if (!(*Context->Routine)(Context->Context,
1017 ExpSplayTreeNodeKey(Node),
1018 ExpSplayTreeNodeValue(Node)))
1023 for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n))
1025 /* Call the traversal routine */
1026 if (!(*Context->Routine)(Context->Context,
1027 ExpSplayTreeNodeKey(n),
1028 ExpSplayTreeNodeValue(n)))
1034 /* Traverse right subtree */
1035 ExpTraverseSplayTreeInorder(Context, ExpSplayTreeLargerChildNode(Node));
1042 * Traverse a splay tree using postorder traversal method.
1043 * Returns FALSE, if the traversal was terminated prematurely or
1044 * TRUE if the callback routine did not request that the traversal
1045 * be terminated prematurely.
1046 * The lock for the tree must be acquired when this routine is called.
1049 ExpTraverseSplayTreePostorder(PTRAVERSE_CONTEXT Context,
1050 PSPLAY_TREE_NODE Node)
1057 /* Traverse 'smaller' subtree */
1058 ExpTraverseSplayTreePostorder(Context, ExpSplayTreeSmallerChildNode(Node));
1060 /* Traverse 'larger' subtree */
1061 ExpTraverseSplayTreePostorder(Context, ExpSplayTreeLargerChildNode(Node));
1063 /* Call the traversal routine */
1064 if (!(*Context->Routine)(Context->Context,
1065 ExpSplayTreeNodeKey(Node),
1066 ExpSplayTreeNodeValue(Node)))
1071 for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n))
1073 /* Call the traversal routine */
1074 if (!(*Context->Routine)(Context->Context,
1075 ExpSplayTreeNodeKey(n),
1076 ExpSplayTreeNodeValue(n)))
1087 * Default key compare function. Compares the integer values of the two keys.
1090 ExpSplayTreeDefaultCompare(IN PVOID Key1,
1096 return (((LONG_PTR) Key1 < (LONG_PTR) Key2) ? -1 : 1);
1101 * Initializes a splay tree.
1104 ExInitializeSplayTree(IN PSPLAY_TREE Tree,
1105 IN PKEY_COMPARATOR Compare,
1106 IN BOOLEAN Weighted,
1107 IN BOOLEAN UseNonPagedPool)
1109 RtlZeroMemory(Tree, sizeof(SPLAY_TREE));
1111 Tree->Compare = (Compare == NULL)
1112 ? ExpSplayTreeDefaultCompare : Compare;
1114 Tree->Weighted = Weighted;
1118 Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeWeight;
1119 Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeWeight;
1120 Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeWeight;
1121 Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeWeight;
1125 Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeNoWeight;
1126 Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeNoWeight;
1127 Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeNoWeight;
1128 Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeNoWeight;
1131 Tree->UseNonPagedPool = UseNonPagedPool;
1133 if (UseNonPagedPool)
1135 ExInitializeNPagedLookasideList(
1136 &Tree->List.NonPaged, /* Lookaside list */
1137 NULL, /* Allocate routine */
1138 NULL, /* Free routine */
1140 sizeof(SPLAY_TREE_NODE), /* Size of each entry */
1141 TAG('E','X','S','T'), /* Tag */
1144 KeInitializeSpinLock(&Tree->Lock.NonPaged);
1148 ExInitializePagedLookasideList(
1149 &Tree->List.Paged, /* Lookaside list */
1150 NULL, /* Allocate routine */
1151 NULL, /* Free routine */
1153 sizeof(SPLAY_TREE_NODE), /* Size of each entry */
1154 TAG('E','X','S','T'), /* Tag */
1157 ExInitializeFastMutex(&Tree->Lock.Paged);
1165 * Release resources used by a splay tree.
1168 ExDeleteSplayTree(IN PSPLAY_TREE Tree)
1170 PSPLAY_TREE_NODE RemovedNode;
1171 PSPLAY_TREE_NODE Node;
1173 /* Remove all nodes */
1174 Node = ExpSplayTreeRootNode(Tree);
1175 while (Node != NULL)
1177 Node = ExpRemoveSplayTree(Tree, Node->Key, Node, &RemovedNode);
1179 if (RemovedNode != NULL)
1181 ExpDestroySplayTreeNode(Tree, RemovedNode);
1185 if (Tree->UseNonPagedPool)
1187 ExDeleteNPagedLookasideList(&Tree->List.NonPaged);
1191 ExDeletePagedLookasideList(&Tree->List.Paged);
1197 * Insert a value in a splay tree.
1200 ExInsertSplayTree(IN PSPLAY_TREE Tree,
1204 PSPLAY_TREE_NODE Node;
1205 PSPLAY_TREE_NODE NewNode;
1208 /* FIXME: Use SEH for error reporting */
1210 NewNode = ExpCreateSplayTreeNode(Tree, Value);
1212 ExpLockSplayTree(Tree, &OldIrql);
1213 Node = ExpInsertSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), NewNode);
1214 ExpSplayTreeRootNode(Tree) = Node;
1215 ExpUnlockSplayTree(Tree, &OldIrql);
1220 * Search for a value associated with a given key in a splay tree.
1223 ExSearchSplayTree(IN PSPLAY_TREE Tree,
1227 PSPLAY_TREE_NODE Node;
1231 ExpLockSplayTree(Tree, &OldIrql);
1232 Status = ExpSearchSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &Node);
1236 ExpSplayTreeRootNode(Tree) = Node;
1237 *Value = ExpSplayTreeNodeValue(Node);
1238 ExpUnlockSplayTree(Tree, &OldIrql);
1243 ExpUnlockSplayTree(Tree, &OldIrql);
1250 * Remove a value associated with a given key from a splay tree.
1253 ExRemoveSplayTree(IN PSPLAY_TREE Tree,
1257 PSPLAY_TREE_NODE RemovedNode;
1258 PSPLAY_TREE_NODE Node;
1261 ExpLockSplayTree(Tree, &OldIrql);
1262 Node = ExpRemoveSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &RemovedNode);
1263 ExpSplayTreeRootNode(Tree) = Node;
1264 ExpUnlockSplayTree(Tree, &OldIrql);
1266 if (RemovedNode != NULL)
1268 *Value = ExpSplayTreeNodeValue(RemovedNode);
1269 ExpDestroySplayTreeNode(Tree, RemovedNode);
1280 * Return the weight of the root node in the splay tree.
1281 * The returned value is the number of nodes in the tree.
1284 ExWeightOfSplayTree(IN PSPLAY_TREE Tree,
1289 ExpLockSplayTree(Tree, &OldIrql);
1291 if (!Tree->Weighted)
1293 ExpUnlockSplayTree(Tree, &OldIrql);
1297 *Weight = ExpSplayTreeNodeWeight(ExpSplayTreeRootNode(Tree));
1298 ExpUnlockSplayTree(Tree, &OldIrql);
1305 * Traverse a splay tree using either preorder, inorder or postorder
1307 * Returns FALSE, if the traversal was terminated prematurely or
1308 * TRUE if the callback routine did not request that the traversal
1309 * be terminated prematurely.
1312 ExTraverseSplayTree(IN PSPLAY_TREE Tree,
1313 IN TRAVERSE_METHOD Method,
1314 IN PTRAVERSE_ROUTINE Routine,
1317 TRAVERSE_CONTEXT tc;
1321 tc.Routine = Routine;
1322 tc.Context = Context;
1324 ExpLockSplayTree(Tree, &OldIrql);
1326 if (ExpSplayTreeRootNode(Tree) == NULL)
1328 ExpUnlockSplayTree(Tree, &OldIrql);
1334 case TraverseMethodPreorder:
1335 Status = ExpTraverseSplayTreePreorder(&tc, ExpSplayTreeRootNode(Tree));
1338 case TraverseMethodInorder:
1339 Status = ExpTraverseSplayTreeInorder(&tc, ExpSplayTreeRootNode(Tree));
1342 case TraverseMethodPostorder:
1343 Status = ExpTraverseSplayTreePostorder(&tc, ExpSplayTreeRootNode(Tree));
1351 ExpUnlockSplayTree(Tree, &OldIrql);