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 * Allocate resources for a new node and initialize it.
62 inline PBINARY_TREE_NODE
63 ExpCreateBinaryTreeNode(PBINARY_TREE Tree
,
64 PBINARY_TREE_NODE Parent
,
67 PBINARY_TREE_NODE Node
;
69 Node
= (PBINARY_TREE_NODE
) ExAllocateFromPagedLookasideList(&Tree
->LookasideList
);
73 ExpBinaryTreeParentNode(Node
) = Parent
;
74 ExpBinaryTreeLeftChildNode(Node
) = NULL
;
75 ExpBinaryTreeRightChildNode(Node
) = NULL
;
76 ExpBinaryTreeNodeValue(Node
) = Value
;
84 * Release resources for the node.
87 ExpDestroyBinaryTreeNode(PBINARY_TREE Tree
,
88 PBINARY_TREE_NODE Node
)
90 ExFreeToPagedLookasideList(&Tree
->LookasideList
, Node
);
95 * Replaces a child node of a node with a new node.
96 * The lock for the tree must be acquired when this routine is called.
99 ExpBinaryTreeReplaceChildNode(PBINARY_TREE_NODE Child
,
100 PBINARY_TREE_NODE NewChild
)
102 if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child
)) == Child
)
104 ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child
)) = NewChild
;
108 ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Child
)) = NewChild
;
114 * Returns the sibling node of a node.
115 * The lock for the tree must be acquired when this routine is called.
117 inline PBINARY_TREE_NODE
118 ExpSiblingBinaryTreeNode(PBINARY_TREE Tree
,
119 PBINARY_TREE_NODE Node
)
121 if (Node
== ExpBinaryTreeRootNode(Tree
))
127 if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node
)) == Node
)
129 return ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Node
));
133 return ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node
));
140 * Expands an external node to an internal node.
141 * The lock for the tree must be acquired when this routine is called.
144 ExpExpandExternalBinaryTreeNode(PBINARY_TREE Tree
,
145 PBINARY_TREE_NODE Node
)
147 ExpBinaryTreeLeftChildNode(Node
) = ExpCreateBinaryTreeNode(Tree
, Node
, NULL
);
149 if (!ExpBinaryTreeLeftChildNode(Node
))
151 /* FIXME: Throw exception */
152 DbgPrint("ExpCreateBinaryTreeNode() failed\n");
155 ExpBinaryTreeRightChildNode(Node
) = ExpCreateBinaryTreeNode(Tree
, Node
, NULL
);
157 if (!ExpBinaryTreeRightChildNode(Node
))
159 ExpDestroyBinaryTreeNode(Tree
, ExpBinaryTreeLeftChildNode(Node
));
160 /* FIXME: Throw exception */
161 DbgPrint("ExpCreateBinaryTreeNode() failed\n");
167 * Searches a tree for a node with the specified key. If a node with the
168 * specified key is not found, the external node where it should be is
170 * The lock for the tree must be acquired when this routine is called.
172 inline PBINARY_TREE_NODE
173 ExpSearchBinaryTree(PBINARY_TREE Tree
,
175 PBINARY_TREE_NODE Node
)
179 /* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
181 if (ExpIsExternalBinaryTreeNode(Node
))
186 Equality
= (*Tree
->Compare
)(Key
, ExpBinaryTreeNodeKey(Node
));
188 if (ExpBinaryTreeNodeEqual(Equality
))
193 if (ExpBinaryTreeNodeLess(Equality
))
195 return ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeLeftChildNode(Node
));
198 /* if (ExpBinaryTreeNodeMore(Equality)) */
200 return ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRightChildNode(Node
));
206 * Removes an external node and it's parent node from the tree.
207 * The lock for the tree must be acquired when this routine is called.
210 ExpRemoveAboveExternalBinaryTreeNode(PBINARY_TREE Tree
,
211 PBINARY_TREE_NODE Node
)
213 assertmsg(ExpIsExternalBinaryTreeNode(Node
), ("Node is not external"));
215 if (Node
== ExpBinaryTreeRootNode(Tree
))
221 PBINARY_TREE_NODE GrandParent
;
222 PBINARY_TREE_NODE NewChild
;
224 GrandParent
= ExpBinaryTreeParentNode(ExpBinaryTreeParentNode(Node
));
225 NewChild
= ExpSiblingBinaryTreeNode(Tree
, Node
);
227 if (GrandParent
!= NULL
)
229 ExpBinaryTreeReplaceChildNode(ExpBinaryTreeParentNode(Node
), NewChild
);
232 ExpDestroyBinaryTreeNode(Tree
, ExpBinaryTreeParentNode(Node
));
233 ExpDestroyBinaryTreeNode(Tree
, Node
);
239 * Release resources used by nodes of a binary (sub)tree.
242 ExpDeleteBinaryTree(PBINARY_TREE Tree
,
243 PBINARY_TREE_NODE Node
)
245 /* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
247 if (ExpIsInternalBinaryTreeNode(Node
))
249 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeLeftChildNode(Node
));
250 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeRightChildNode(Node
));
253 ExpDestroyBinaryTreeNode(Tree
, Node
);
258 * Default key compare function. Compares the integer values of the two keys.
261 ExpBinaryTreeDefaultCompare(PVOID Key1
,
267 return (((LONG_PTR
) Key1
< (LONG_PTR
) Key2
) ? -1 : 1);
272 * Initializes a binary tree.
275 ExInitializeBinaryTree(IN PBINARY_TREE Tree
,
276 IN PKEY_COMPARATOR Compare
)
278 RtlZeroMemory(Tree
, sizeof(BINARY_TREE
));
280 Tree
->Compare
= (Compare
== NULL
)
281 ? ExpBinaryTreeDefaultCompare
: Compare
;
283 ExInitializePagedLookasideList(
284 &Tree
->LookasideList
, /* Lookaside list */
285 NULL
, /* Allocate routine */
286 NULL
, /* Free routine */
288 sizeof(BINARY_TREE_NODE
), /* Size of each entry */
289 TAG('E','X','B','T'), /* Tag */
292 ExInitializeFastMutex(&Tree
->Lock
);
294 ExpBinaryTreeRootNode(Tree
) = ExpCreateBinaryTreeNode(Tree
, NULL
, NULL
);
296 if (ExpBinaryTreeRootNode(Tree
) == NULL
)
298 ExDeletePagedLookasideList(&Tree
->LookasideList
);
309 * Release resources used by a binary tree.
312 ExDeleteBinaryTree(IN PBINARY_TREE Tree
)
314 /* Remove all nodes */
315 ExpDeleteBinaryTree(Tree
, ExpBinaryTreeRootNode(Tree
));
317 ExDeletePagedLookasideList(&Tree
->LookasideList
);
322 * Insert a value in a binary tree.
325 ExInsertBinaryTree(IN PBINARY_TREE Tree
,
329 PBINARY_TREE_NODE Node
;
331 /* FIXME: Use SEH for error reporting */
333 ExAcquireFastMutex(&Tree
->Lock
);
334 Node
= ExpBinaryTreeRootNode(Tree
);
337 Node
= ExpSearchBinaryTree(Tree
, Key
, Node
);
339 if (ExpIsExternalBinaryTreeNode(Node
))
345 Node
= ExpBinaryTreeRightChildNode(Node
);
348 ExpExpandExternalBinaryTreeNode(Tree
, Node
);
349 ExpBinaryTreeNodeKey(Node
) = Key
;
350 ExpBinaryTreeNodeValue(Node
) = Value
;
351 ExReleaseFastMutex(&Tree
->Lock
);
356 * Search for a value associated with a given key in a binary tree.
359 ExSearchBinaryTree(IN PBINARY_TREE Tree
,
363 PBINARY_TREE_NODE Node
;
365 ExAcquireFastMutex(&Tree
->Lock
);
366 Node
= ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRootNode(Tree
));
368 if (ExpIsInternalBinaryTreeNode(Node
))
370 *Value
= ExpBinaryTreeNodeValue(Node
);
371 ExReleaseFastMutex(&Tree
->Lock
);
376 ExReleaseFastMutex(&Tree
->Lock
);
383 * Remove a value associated with a given key from a binary tree.
386 ExRemoveBinaryTree(IN PBINARY_TREE Tree
,
390 PBINARY_TREE_NODE Node
;
392 ExAcquireFastMutex(&Tree
->Lock
);
393 Node
= ExpSearchBinaryTree(Tree
, Key
, ExpBinaryTreeRootNode(Tree
));
395 if (ExpIsExternalBinaryTreeNode(Node
))
397 ExReleaseFastMutex(&Tree
->Lock
);
402 *Value
= ExpBinaryTreeNodeValue(Node
);
403 if (ExpIsExternalBinaryTreeNode(ExpBinaryTreeLeftChildNode(Node
)))
405 Node
= ExpBinaryTreeLeftChildNode(Node
);
407 else if (ExpIsExternalBinaryTreeNode(ExpBinaryTreeRightChildNode(Node
)))
409 Node
= ExpBinaryTreeRightChildNode(Node
);
413 // Node has internal children
414 PBINARY_TREE_NODE SwapNode
;
417 Node
= ExpBinaryTreeRightChildNode(SwapNode
);
420 Node
= ExpBinaryTreeLeftChildNode(Node
);
421 } while (ExpIsInternalBinaryTreeNode(Node
));
424 ExpRemoveAboveExternalBinaryTreeNode(Tree
, Node
);
425 ExReleaseFastMutex(&Tree
->Lock
);