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: Binary tree support
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * 15-03-2002 CSH Created
27 #include <ddk/ntddk.h>
28 #include <internal/ex.h>
31 #include <internal/debug.h>
33 /* DATA **********************************************************************/
35 typedef struct _BINARY_TREE_NODE
37 struct _BINARY_TREE_NODE
* Parent
;
38 struct _BINARY_TREE_NODE
* LeftChild
;
39 struct _BINARY_TREE_NODE
* RightChild
;
42 } BINARY_TREE_NODE
, *PBINARY_TREE_NODE
;
44 /* FUNCTIONS ****************************************************************/
46 #define ExpBinaryTreeRootNode(Tree)(((PBINARY_TREE) (Tree))->RootNode)
47 #define ExpIsExternalBinaryTreeNode(Node)(((Node)->LeftChild == NULL) && ((Node)->RightChild == NULL))
48 #define ExpIsInternalBinaryTreeNode(Node)(!ExpIsExternalBinaryTreeNode(Node))
49 #define ExpBinaryTreeNodeKey(Node)((Node)->Key)
50 #define ExpBinaryTreeNodeValue(Node)((Node)->Value)
51 #define ExpBinaryTreeParentNode(Node)((Node)->Parent)
52 #define ExpBinaryTreeLeftChildNode(Node)((Node)->LeftChild)
53 #define ExpBinaryTreeRightChildNode(Node)((Node)->RightChild)
54 #define ExpBinaryTreeNodeEqual(Equality)((Equality) == 0)
55 #define ExpBinaryTreeNodeLess(Equality)((Equality) < 0)
56 #define ExpBinaryTreeNodeMore(Equality)((Equality) > 0)
60 * Lock the binary tree
63 ExpLockBinaryTree(PBINARY_TREE Tree
,
66 if (Tree
->UseNonPagedPool
)
68 KeAcquireSpinLock(&Tree
->Lock
.NonPaged
, OldIrql
);
72 ExAcquireFastMutex(&Tree
->Lock
.Paged
);
78 * Unlock the binary tree
81 ExpUnlockBinaryTree(PBINARY_TREE Tree
,
84 if (Tree
->UseNonPagedPool
)
86 KeReleaseSpinLock(&Tree
->Lock
.NonPaged
, *OldIrql
);
90 ExReleaseFastMutex(&Tree
->Lock
.Paged
);
96 * Allocate resources for a new node and initialize it.
98 inline PBINARY_TREE_NODE
99 ExpCreateBinaryTreeNode(PBINARY_TREE Tree
,
100 PBINARY_TREE_NODE Parent
,
103 PBINARY_TREE_NODE Node
;
105 if (Tree
->UseNonPagedPool
)
107 Node
= (PBINARY_TREE_NODE
) ExAllocateFromNPagedLookasideList(&Tree
->List
.NonPaged
);
111 Node
= (PBINARY_TREE_NODE
) ExAllocateFromPagedLookasideList(&Tree
->List
.Paged
);
116 ExpBinaryTreeParentNode(Node
) = Parent
;
117 ExpBinaryTreeLeftChildNode(Node
) = NULL
;
118 ExpBinaryTreeRightChildNode(Node
) = NULL
;
119 ExpBinaryTreeNodeValue(Node
) = Value
;
127 * Release resources for the node.
130 ExpDestroyBinaryTreeNode(PBINARY_TREE Tree
,
131 PBINARY_TREE_NODE Node
)
133 if (Tree
->UseNonPagedPool
)
135 ExFreeToNPagedLookasideList(&Tree
->List
.NonPaged
, Node
);
139 ExFreeToPagedLookasideList(&Tree
->List
.Paged
, Node
);
145 * Replaces a child node of a node with a new node.
146 * The lock for the tree must be acquired when this routine is called.
149 ExpBinaryTreeReplaceChildNode(PBINARY_TREE_NODE Child
,
150 PBINARY_TREE_NODE NewChild
)
152 if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child
)) == Child
)
154 ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child
)) = NewChild
;
158 ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Child
)) = NewChild
;
164 * Returns the sibling node of a node.
165 * The lock for the tree must be acquired when this routine is called.
167 inline PBINARY_TREE_NODE
168 ExpSiblingBinaryTreeNode(PBINARY_TREE Tree
,
169 PBINARY_TREE_NODE Node
)
171 if (Node
== ExpBinaryTreeRootNode(Tree
))
177 if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node
)) == Node
)
179 return ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Node
));
183 return ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node
));
190 * Expands an external node to an internal node.
191 * The lock for the tree must be acquired when this routine is called.
194 ExpExpandExternalBinaryTreeNode(PBINARY_TREE Tree
,
195 PBINARY_TREE_NODE Node
)
197 ExpBinaryTreeLeftChildNode(Node
) = ExpCreateBinaryTreeNode(Tree
, Node
, NULL
);
199 if (!ExpBinaryTreeLeftChildNode(Node
))
201 /* FIXME: Throw exception */
202 DbgPrint("ExpCreateBinaryTreeNode() failed\n");
205 ExpBinaryTreeRightChildNode(Node
) = ExpCreateBinaryTreeNode(Tree
, Node
, NULL
);
207 if (!ExpBinaryTreeRightChildNode(Node
))
209 ExpDestroyBinaryTreeNode(Tree
, ExpBinaryTreeLeftChildNode(Node
));
210 /* FIXME: Throw exception */
211 DbgPrint("ExpCreateBinaryTreeNode() failed\n");
217 * Searches a tree for a node with the specified key. If a node with the
218 * specified key is not found, the external node where it should be is
220 * The lock for the tree must be acquired when this routine is called.
222 inline PBINARY_TREE_NODE
223 ExpSearchBinaryTree(PBINARY_TREE Tree
,
225 PBINARY_TREE_NODE Node
)
229 /* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
231 if (ExpIsExternalBinaryTreeNode(Node
))
236 Equality
= (*Tree
->Compare
)(Key
, ExpBinaryTreeNodeKey(Node
));
238 if (ExpBinaryTreeNodeEqual(Equality
))
243 if (ExpBinaryTreeNodeLess(Equality
))
245 return ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeLeftChildNode(Node
));
248 /* if (ExpBinaryTreeNodeMore(Equality)) */
250 return ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRightChildNode(Node
));
256 * Removes an external node and it's parent node from the tree.
257 * The lock for the tree must be acquired when this routine is called.
260 ExpRemoveAboveExternalBinaryTreeNode(PBINARY_TREE Tree
,
261 PBINARY_TREE_NODE Node
)
263 assertmsg(ExpIsExternalBinaryTreeNode(Node
), ("Node is not external"));
265 if (Node
== ExpBinaryTreeRootNode(Tree
))
271 PBINARY_TREE_NODE GrandParent
;
272 PBINARY_TREE_NODE NewChild
;
274 GrandParent
= ExpBinaryTreeParentNode(ExpBinaryTreeParentNode(Node
));
275 NewChild
= ExpSiblingBinaryTreeNode(Tree
, Node
);
277 if (GrandParent
!= NULL
)
279 ExpBinaryTreeReplaceChildNode(ExpBinaryTreeParentNode(Node
), NewChild
);
282 ExpDestroyBinaryTreeNode(Tree
, ExpBinaryTreeParentNode(Node
));
283 ExpDestroyBinaryTreeNode(Tree
, Node
);
289 * Release resources used by nodes of a binary (sub)tree.
292 ExpDeleteBinaryTree(PBINARY_TREE Tree
,
293 PBINARY_TREE_NODE Node
)
295 /* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
297 if (ExpIsInternalBinaryTreeNode(Node
))
299 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeLeftChildNode(Node
));
300 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeRightChildNode(Node
));
303 ExpDestroyBinaryTreeNode(Tree
, Node
);
308 * Default key compare function. Compares the integer values of the two keys.
311 ExpBinaryTreeDefaultCompare(PVOID Key1
,
317 return (((LONG_PTR
) Key1
< (LONG_PTR
) Key2
) ? -1 : 1);
322 * Initializes a binary tree.
325 ExInitializeBinaryTree(IN PBINARY_TREE Tree
,
326 IN PKEY_COMPARATOR Compare
,
327 IN BOOLEAN UseNonPagedPool
)
329 RtlZeroMemory(Tree
, sizeof(BINARY_TREE
));
331 Tree
->Compare
= (Compare
== NULL
)
332 ? ExpBinaryTreeDefaultCompare
: Compare
;
334 Tree
->UseNonPagedPool
= UseNonPagedPool
;
338 ExInitializeNPagedLookasideList(
339 &Tree
->List
.NonPaged
, /* Lookaside list */
340 NULL
, /* Allocate routine */
341 NULL
, /* Free routine */
343 sizeof(BINARY_TREE_NODE
), /* Size of each entry */
344 TAG('E','X','B','T'), /* Tag */
347 KeInitializeSpinLock(&Tree
->Lock
.NonPaged
);
351 ExInitializePagedLookasideList(
352 &Tree
->List
.Paged
, /* Lookaside list */
353 NULL
, /* Allocate routine */
354 NULL
, /* Free routine */
356 sizeof(BINARY_TREE_NODE
), /* Size of each entry */
357 TAG('E','X','B','T'), /* Tag */
360 ExInitializeFastMutex(&Tree
->Lock
.Paged
);
363 ExpBinaryTreeRootNode(Tree
) = ExpCreateBinaryTreeNode(Tree
, NULL
, NULL
);
365 if (ExpBinaryTreeRootNode(Tree
) == NULL
)
369 ExDeleteNPagedLookasideList(&Tree
->List
.NonPaged
);
373 ExDeletePagedLookasideList(&Tree
->List
.Paged
);
385 * Release resources used by a binary tree.
388 ExDeleteBinaryTree(IN PBINARY_TREE Tree
)
390 /* Remove all nodes */
391 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeRootNode(Tree
));
393 if (Tree
->UseNonPagedPool
)
395 ExDeleteNPagedLookasideList(&Tree
->List
.NonPaged
);
399 ExDeletePagedLookasideList(&Tree
->List
.Paged
);
405 * Insert a value in a binary tree.
408 ExInsertBinaryTree(IN PBINARY_TREE Tree
,
412 PBINARY_TREE_NODE Node
;
415 /* FIXME: Use SEH for error reporting */
417 ExpLockBinaryTree(Tree
, &OldIrql
);
418 Node
= ExpBinaryTreeRootNode(Tree
);
421 Node
= ExpSearchBinaryTree(Tree
, Key
, Node
);
423 if (ExpIsExternalBinaryTreeNode(Node
))
429 Node
= ExpBinaryTreeRightChildNode(Node
);
432 ExpExpandExternalBinaryTreeNode(Tree
, Node
);
433 ExpBinaryTreeNodeKey(Node
) = Key
;
434 ExpBinaryTreeNodeValue(Node
) = Value
;
435 ExpUnlockBinaryTree(Tree
, &OldIrql
);
440 * Search for a value associated with a given key in a binary tree.
443 ExSearchBinaryTree(IN PBINARY_TREE Tree
,
447 PBINARY_TREE_NODE Node
;
450 ExpLockBinaryTree(Tree
, &OldIrql
);
451 Node
= ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRootNode(Tree
));
453 if (ExpIsInternalBinaryTreeNode(Node
))
455 *Value
= ExpBinaryTreeNodeValue(Node
);
456 ExpUnlockBinaryTree(Tree
, &OldIrql
);
461 ExpUnlockBinaryTree(Tree
, &OldIrql
);
468 * Remove a value associated with a given key from a binary tree.
471 ExRemoveBinaryTree(IN PBINARY_TREE Tree
,
475 PBINARY_TREE_NODE Node
;
478 ExpLockBinaryTree(Tree
, &OldIrql
);
480 Node
= ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRootNode(Tree
));
482 if (ExpIsExternalBinaryTreeNode(Node
))
484 ExpUnlockBinaryTree(Tree
, &OldIrql
);
489 *Value
= ExpBinaryTreeNodeValue(Node
);
490 if (ExpIsExternalBinaryTreeNode(ExpBinaryTreeLeftChildNode(Node
)))
492 Node
= ExpBinaryTreeLeftChildNode(Node
);
494 else if (ExpIsExternalBinaryTreeNode(ExpBinaryTreeRightChildNode(Node
)))
496 Node
= ExpBinaryTreeRightChildNode(Node
);
500 // Node has internal children
501 PBINARY_TREE_NODE SwapNode
;
504 Node
= ExpBinaryTreeRightChildNode(SwapNode
);
507 Node
= ExpBinaryTreeLeftChildNode(Node
);
508 } while (ExpIsInternalBinaryTreeNode(Node
));
511 ExpRemoveAboveExternalBinaryTreeNode(Tree
, Node
);
512 ExpUnlockBinaryTree(Tree
, &OldIrql
);