b5925463a2f895d18c6a1909aaebe14d79460f91
[reactos.git] / reactos / ntoskrnl / ex / stree.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998-2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: stree.c
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
27 * UPDATE HISTORY:
28 * 15-03-2002 CSH Created
29 */
30 #include <ddk/ntddk.h>
31 #include <internal/ex.h>
32
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* DATA **********************************************************************/
37
38 #define WEIGHT 1
39 #undef UNIQUE_KEYS
40
41 typedef struct _SPLAY_TREE_NODE
42 {
43 /* Children on this branch has smaller keys than this node */
44 struct _SPLAY_TREE_NODE * SmallerChild;
45
46 /* Children on this branch has larger keys than this node */
47 struct _SPLAY_TREE_NODE * LargerChild;
48
49 /* Points to a node with identical key */
50 struct _SPLAY_TREE_NODE * Same;
51
52 /* Key of this node */
53 PVOID Key;
54
55 /* Value of this node */
56 PVOID Value;
57
58 /* The number of nodes rooted here */
59 LONG Weight;
60 } SPLAY_TREE_NODE, *PSPLAY_TREE_NODE;
61
62 #define SPLAY_INDEX 0
63 #define SEARCH_INDEX 1
64 #define INSERT_INDEX 2
65 #define REMOVE_INDEX 3
66
67 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_SPLAY)(PSPLAY_TREE Tree,
68 PVOID Key,
69 PSPLAY_TREE_NODE Node);
70
71 typedef BOOLEAN (*PSPLAY_TREE_SEARCH)(PSPLAY_TREE Tree,
72 PVOID Key,
73 PSPLAY_TREE_NODE Node,
74 PSPLAY_TREE_NODE * ReturnNode);
75
76 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_INSERT)(PSPLAY_TREE Tree,
77 PVOID Key,
78 PSPLAY_TREE_NODE Node,
79 PSPLAY_TREE_NODE New);
80
81 typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_REMOVE)(PSPLAY_TREE Tree,
82 PVOID Key,
83 PSPLAY_TREE_NODE Node,
84 PSPLAY_TREE_NODE * RemovedNode);
85
86 /* FUNCTIONS ****************************************************************/
87
88 #define ExpSplayTreeRootNode(Tree)(((PSPLAY_TREE) (Tree))->RootNode)
89 #define ExpSplayTreeNodeKey(Node)((Node)->Key)
90 #define ExpSplayTreeNodeValue(Node)((Node)->Value)
91 #define ExpSplayTreeSmallerChildNode(Node)((Node)->SmallerChild)
92 #define ExpSplayTreeLargerChildNode(Node)((Node)->LargerChild)
93 #define ExpSplayTreeNodeEqual(Equality)((Equality) == 0)
94 #define ExpSplayTreeNodeLess(Equality)((Equality) < 0)
95 #define ExpSplayTreeNodeMore(Equality)((Equality) > 0)
96 #define ExpSplayTreeNodeSame(Node)((Node)->Same)
97 #define ExpSplayTreeNodeWeight(Node)((Node)->Weight)
98 #define ExpSplayTreeNodeGetWeight(Node)(((Node) == NULL) ? 0 : ((Node)->Weight))
99 #define ExpSplayTreeNodeSetWeight(Node, _Weight)((Node)->Weight = (_Weight))
100
101 #define KEY_NOTUSED (PVOID)-1
102
103
104 /*
105 * Allocate resources for a new node and initialize it.
106 */
107 inline PSPLAY_TREE_NODE
108 ExpCreateSplayTreeNode(PSPLAY_TREE Tree,
109 PVOID Value)
110 {
111 PSPLAY_TREE_NODE Node;
112
113 Node = (PSPLAY_TREE_NODE) ExAllocateFromPagedLookasideList(&Tree->LookasideList);
114
115 if (Node)
116 {
117 ExpSplayTreeSmallerChildNode(Node) = NULL;
118 ExpSplayTreeLargerChildNode(Node) = NULL;
119 ExpSplayTreeNodeValue(Node) = Value;
120 }
121
122 return Node;
123 }
124
125 /*
126 * Release resources for the node.
127 */
128 inline VOID
129 ExpDestroySplayTreeNode(PSPLAY_TREE Tree,
130 PSPLAY_TREE_NODE Node)
131 {
132 ExFreeToPagedLookasideList(&Tree->LookasideList, Node);
133 }
134
135
136 /*
137 * Splay using the key 'Key' (which may or may not be in the tree). The starting
138 * root is Node. Weight fields are maintained.
139 * The lock for the tree must be acquired when this routine is called.
140 * This routine does not maintain weight information.
141 */
142 PSPLAY_TREE_NODE
143 ExpSplayTreeNoWeight(PSPLAY_TREE Tree,
144 PVOID Key,
145 PSPLAY_TREE_NODE Node)
146 {
147 PSPLAY_TREE_NODE l;
148 PSPLAY_TREE_NODE r;
149 PSPLAY_TREE_NODE y;
150 LONG ChildEquality;
151 SPLAY_TREE_NODE N;
152 LONG Equality;
153
154 if (Node == NULL)
155 return Node;
156
157 ExpSplayTreeSmallerChildNode(&N) = NULL;
158 ExpSplayTreeLargerChildNode(&N) = NULL;
159 l = &N;
160 r = &N;
161
162 for (;;)
163 {
164 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
165
166 if (ExpSplayTreeNodeLess(Equality))
167 {
168 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
169 break;
170
171 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node)));
172 if (ExpSplayTreeNodeLess(ChildEquality))
173 {
174 y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */
175 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y);
176 ExpSplayTreeLargerChildNode(y) = Node;
177
178 Node = y;
179 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
180 break;
181 }
182
183 ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */
184 r = Node;
185 Node = ExpSplayTreeSmallerChildNode(Node);
186 }
187 else if (ExpSplayTreeNodeMore(Equality))
188 {
189 if (ExpSplayTreeLargerChildNode(Node) == NULL)
190 break;
191
192 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node)));
193 if (ExpSplayTreeNodeMore(ChildEquality))
194 {
195 y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */
196 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y);
197 ExpSplayTreeSmallerChildNode(y) = Node;
198
199 Node = y;
200 if (ExpSplayTreeLargerChildNode(Node) == NULL)
201 break;
202 }
203
204 ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */
205 l = Node;
206 Node = ExpSplayTreeLargerChildNode(Node);
207 }
208 else
209 {
210 break;
211 }
212 }
213
214 ExpSplayTreeLargerChildNode(l) = NULL;
215 ExpSplayTreeSmallerChildNode(r) = NULL;
216
217 ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */
218 ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node);
219 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N);
220 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N);
221
222 return Node;
223 }
224
225
226 /*
227 * Splay using the key 'Key' (which may or may not be in the tree). The starting
228 * root is Node. Weight fields are maintained.
229 * The lock for the tree must be acquired when this routine is called.
230 * This routine maintains weight information.
231 */
232 PSPLAY_TREE_NODE
233 ExpSplayTreeWeight(PSPLAY_TREE Tree,
234 PVOID Key,
235 PSPLAY_TREE_NODE Node)
236 {
237 PSPLAY_TREE_NODE l;
238 PSPLAY_TREE_NODE r;
239 PSPLAY_TREE_NODE y;
240 LONG ChildEquality;
241 SPLAY_TREE_NODE N;
242 LONG Equality;
243 #ifdef WEIGHT
244 LONG RootWeight;
245 LONG Weight1;
246 LONG Weight2;
247 #endif
248
249 if (Node == NULL)
250 return Node;
251
252 ExpSplayTreeSmallerChildNode(&N) = NULL;
253 ExpSplayTreeLargerChildNode(&N) = NULL;
254 l = &N;
255 r = &N;
256
257 #ifdef WEIGHT
258 RootWeight = ExpSplayTreeNodeGetWeight(Node);
259 Weight1 = 0;
260 Weight2 = 0;
261 #endif
262
263 for (;;)
264 {
265 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
266
267 if (ExpSplayTreeNodeLess(Equality))
268 {
269 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
270 break;
271
272 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node)));
273 if (ExpSplayTreeNodeLess(ChildEquality))
274 {
275 y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */
276 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y);
277 ExpSplayTreeLargerChildNode(y) = Node;
278
279 #ifdef WEIGHT
280 ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
281 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1);
282 #endif
283
284 Node = y;
285 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
286 break;
287 }
288
289 ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */
290 r = Node;
291 Node = ExpSplayTreeSmallerChildNode(Node);
292
293 #ifdef WEIGHT
294 Weight2 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(r));
295 #endif
296 }
297 else if (ExpSplayTreeNodeMore(Equality))
298 {
299 if (ExpSplayTreeLargerChildNode(Node) == NULL)
300 break;
301
302 ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node)));
303 if (ExpSplayTreeNodeMore(ChildEquality))
304 {
305 y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */
306 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y);
307 ExpSplayTreeSmallerChildNode(y) = Node;
308
309 #ifdef WEIGHT
310 ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
311 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1);
312 #endif
313
314 Node = y;
315 if (ExpSplayTreeLargerChildNode(Node) == NULL)
316 break;
317 }
318
319 ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */
320 l = Node;
321 Node = ExpSplayTreeLargerChildNode(Node);
322
323 #ifdef WEIGHT
324 Weight1 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(l));
325 #endif
326
327 }
328 else
329 {
330 break;
331 }
332 }
333
334 #ifdef WEIGHT
335 Weight1 += ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)); /* Now Weight1 and Weight2 are the weights of */
336 Weight2 += ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)); /* The 'smaller' and 'larger' trees we just built. */
337 ExpSplayTreeNodeSetWeight(Node, Weight1 + Weight2 + 1);
338 #endif
339
340 ExpSplayTreeLargerChildNode(l) = NULL;
341 ExpSplayTreeSmallerChildNode(r) = NULL;
342
343 #ifdef WEIGHT
344 /* The following two loops correct the weight fields of the right path from
345 * the left child of the root and the right path from the left child of the
346 * root.
347 */
348 for (y = ExpSplayTreeLargerChildNode(&N); y != NULL; y = ExpSplayTreeLargerChildNode(y)) {
349 ExpSplayTreeNodeSetWeight(y, Weight1);
350 Weight1 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(y));
351 }
352 for (y = ExpSplayTreeSmallerChildNode(&N); y != NULL; y = ExpSplayTreeSmallerChildNode(y)) {
353 ExpSplayTreeNodeSetWeight(y, Weight2);
354 Weight2 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(y));
355 }
356 #endif
357
358 ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */
359 ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node);
360 ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N);
361 ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N);
362
363 return Node;
364 }
365
366
367 inline PSPLAY_TREE_NODE
368 ExpSplayTree(PSPLAY_TREE Tree,
369 PVOID Key,
370 PSPLAY_TREE_NODE Node)
371 {
372 return (*((PSPLAY_TREE_SPLAY)Tree->Reserved[SPLAY_INDEX]))(Tree, Key, Node);
373 }
374
375
376 /*
377 * The lock for the tree must be acquired when this routine is called.
378 * This routine does not maintain weight information.
379 */
380 BOOLEAN
381 ExpSearchSplayTreeNoWeight(PSPLAY_TREE Tree,
382 PVOID Key,
383 PSPLAY_TREE_NODE Node,
384 PSPLAY_TREE_NODE * ReturnNode)
385 {
386 LONG Equality;
387
388 if (Node == NULL)
389 return FALSE;
390
391 Node = ExpSplayTree(Tree, Key, Node);
392
393 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
394 if (ExpSplayTreeNodeEqual(Equality))
395 {
396 /* Found the key */
397
398 *ReturnNode = Node;
399 return TRUE;
400 }
401 else
402 {
403 *ReturnNode = NULL; /* No match */
404 return FALSE; /* It wasn't there */
405 }
406 }
407
408
409 /*
410 * The lock for the tree must be acquired when this routine is called.
411 * This routine maintains weight information.
412 */
413 BOOLEAN
414 ExpSearchSplayTreeWeight(PSPLAY_TREE Tree,
415 PVOID Key,
416 PSPLAY_TREE_NODE Node,
417 PSPLAY_TREE_NODE * ReturnNode)
418 {
419 PSPLAY_TREE_NODE x;
420 LONG Equality;
421 #ifdef WEIGHT
422 LONG tweight;
423 #endif
424
425 if (Node == NULL)
426 return FALSE;
427
428 #ifdef WEIGHT
429 tweight = ExpSplayTreeNodeGetWeight(Node);
430 #endif
431
432 Node = ExpSplayTree(Tree, Key, Node);
433
434 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
435 if (ExpSplayTreeNodeEqual(Equality))
436 {
437 /* Found the key */
438
439 #ifdef WEIGHT
440 if (x != NULL)
441 {
442 ExpSplayTreeNodeSetWeight(x, tweight - 1);
443 }
444 #endif
445
446 *ReturnNode = Node;
447 return TRUE;
448 }
449 else
450 {
451 *ReturnNode = NULL; /* No match */
452 return FALSE; /* It wasn't there */
453 }
454 }
455
456
457 inline BOOLEAN
458 ExpSearchSplayTree(PSPLAY_TREE Tree,
459 PVOID Key,
460 PSPLAY_TREE_NODE Node,
461 PSPLAY_TREE_NODE * ReturnNode)
462 {
463 return (*((PSPLAY_TREE_SEARCH)Tree->Reserved[SEARCH_INDEX]))(Tree, Key, Node, ReturnNode);
464 }
465
466
467 /*
468 * The lock for the tree must be acquired when this routine is called.
469 * This routine does not maintain weight information.
470 */
471 PSPLAY_TREE_NODE
472 ExpInsertSplayTreeNoWeight(PSPLAY_TREE Tree,
473 PVOID Key,
474 PSPLAY_TREE_NODE Node,
475 PSPLAY_TREE_NODE New)
476 {
477 if (New == NULL)
478 return Node;
479
480 if (Node != NULL)
481 {
482 LONG Equality;
483
484 Node = ExpSplayTree(Tree, Key, Node);
485
486 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
487 if (ExpSplayTreeNodeEqual(Equality))
488 {
489
490 #ifdef UNIQUE_KEYS
491
492 /* This is how to prevent the same node key getting added twice */
493 return NULL;
494
495 #else
496
497 /* It already exists one of this size */
498
499 ExpSplayTreeNodeSame(New) = Node;
500 ExpSplayTreeNodeKey(New) = Key;
501 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
502 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
503
504 ExpSplayTreeSmallerChildNode(Node) = New;
505 ExpSplayTreeNodeKey(Node) = KEY_NOTUSED;
506
507 /* New root node */
508 return New;
509
510 #endif
511
512 }
513 }
514
515 if (Node == NULL)
516 {
517 ExpSplayTreeSmallerChildNode(New) = NULL;
518 ExpSplayTreeLargerChildNode(New) = NULL;
519 }
520 else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node))))
521 {
522 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
523 ExpSplayTreeLargerChildNode(New) = Node;
524 ExpSplayTreeSmallerChildNode(Node) = NULL;
525 }
526 else
527 {
528 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
529 ExpSplayTreeSmallerChildNode(New) = Node;
530 ExpSplayTreeLargerChildNode(Node) = NULL;
531 }
532
533 ExpSplayTreeNodeKey(New) = Key;
534
535 #ifndef UNIQUE_KEYS
536 /* No identical nodes (yet) */
537 ExpSplayTreeNodeSame(New) = NULL;
538 #endif
539
540 return New;
541 }
542
543
544 /*
545 * The lock for the tree must be acquired when this routine is called.
546 * This routine maintains weight information.
547 */
548 PSPLAY_TREE_NODE
549 ExpInsertSplayTreeWeight(PSPLAY_TREE Tree,
550 PVOID Key,
551 PSPLAY_TREE_NODE Node,
552 PSPLAY_TREE_NODE New)
553 {
554 if (New == NULL)
555 return Node;
556
557 if (Node != NULL)
558 {
559 LONG Equality;
560
561 Node = ExpSplayTree(Tree, Key, Node);
562
563 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
564 if (ExpSplayTreeNodeEqual(Equality))
565 {
566
567 #ifdef UNIQUE_KEYS
568
569 /* This is how to prevent the same node key getting added twice */
570 return NULL;
571
572 #else
573
574 /* It already exists one of this size */
575
576 ExpSplayTreeNodeSame(New) = Node;
577 ExpSplayTreeNodeKey(New) = Key;
578 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
579 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
580
581 #ifdef WEIGHT
582 ExpSplayTreeNodeSetWeight(New, ExpSplayTreeNodeGetWeight(Node));
583 #endif
584
585 ExpSplayTreeSmallerChildNode(Node) = New;
586 ExpSplayTreeNodeKey(Node) = KEY_NOTUSED;
587
588 /* New root node */
589 return New;
590
591 #endif
592
593 }
594 }
595
596 if (Node == NULL)
597 {
598 ExpSplayTreeSmallerChildNode(New) = NULL;
599 ExpSplayTreeLargerChildNode(New) = NULL;
600 }
601 else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node))))
602 {
603 ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node);
604 ExpSplayTreeLargerChildNode(New) = Node;
605 ExpSplayTreeSmallerChildNode(Node) = NULL;
606
607 #ifdef WEIGHT
608 ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)));
609 #endif
610
611 }
612 else
613 {
614 ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node);
615 ExpSplayTreeSmallerChildNode(New) = Node;
616 ExpSplayTreeLargerChildNode(Node) = NULL;
617
618 #ifdef WEIGHT
619 ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)));
620 #endif
621
622 }
623
624 ExpSplayTreeNodeKey(New) = Key;
625
626 #ifdef WEIGHT
627 ExpSplayTreeNodeSetWeight(New, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(New))
628 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(New)));
629 #endif
630
631 #ifndef UNIQUE_KEYS
632 /* No identical nodes (yet) */
633 ExpSplayTreeNodeSame(New) = NULL;
634 #endif
635
636 return New;
637 }
638
639
640 inline PSPLAY_TREE_NODE
641 ExpInsertSplayTree(PSPLAY_TREE Tree,
642 PVOID Key,
643 PSPLAY_TREE_NODE Node,
644 PSPLAY_TREE_NODE New)
645 {
646 return (*((PSPLAY_TREE_INSERT)Tree->Reserved[INSERT_INDEX]))(Tree, Key, Node, New);
647 }
648
649
650 /*
651 * Deletes the node with key 'Key' from the tree if it's there.
652 * Return a pointer to the resulting tree.
653 * The lock for the tree must be acquired when this routine is called.
654 * This routine does not maintain weight information.
655 */
656 PSPLAY_TREE_NODE
657 ExpRemoveSplayTreeNoWeight(PSPLAY_TREE Tree,
658 PVOID Key,
659 PSPLAY_TREE_NODE Node,
660 PSPLAY_TREE_NODE * RemovedNode)
661 {
662 PSPLAY_TREE_NODE x;
663 LONG Equality;
664
665 if (Node == NULL)
666 return NULL;
667
668 Node = ExpSplayTree(Tree, Key, Node);
669
670 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
671 if (ExpSplayTreeNodeEqual(Equality))
672 {
673 /* Found the key */
674
675 #ifndef UNIQUE_KEYS
676 /* FIRST! Check if there is a list with identical sizes */
677 x = ExpSplayTreeNodeSame(Node);
678 if (x)
679 {
680 /* There is several, pick one from the list */
681
682 /* 'x' is the new root node */
683
684 ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node);
685 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
686 ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node);
687
688 *RemovedNode = Node;
689 return x;
690 }
691 #endif
692
693 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
694 {
695 x = ExpSplayTreeLargerChildNode(Node);
696 }
697 else
698 {
699 x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node));
700 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
701 }
702 *RemovedNode = Node;
703
704 return x;
705 }
706 else
707 {
708 *RemovedNode = NULL; /* No match */
709 return Node; /* It wasn't there */
710 }
711 }
712
713
714 /*
715 * Deletes the node with key 'Key' from the tree if it's there.
716 * Return a pointer to the resulting tree.
717 * The lock for the tree must be acquired when this routine is called.
718 * This routine maintains weight information.
719 */
720 PSPLAY_TREE_NODE
721 ExpRemoveSplayTreeWeight(PSPLAY_TREE Tree,
722 PVOID Key,
723 PSPLAY_TREE_NODE Node,
724 PSPLAY_TREE_NODE * RemovedNode)
725 {
726 PSPLAY_TREE_NODE x;
727 LONG Equality;
728
729 #ifdef WEIGHT
730 LONG tweight;
731 #endif
732
733 if (Node == NULL)
734 return NULL;
735
736 #ifdef WEIGHT
737 tweight = ExpSplayTreeNodeGetWeight(Node);
738 #endif
739
740 Node = ExpSplayTree(Tree, Key, Node);
741
742 Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node));
743 if (ExpSplayTreeNodeEqual(Equality))
744 {
745 /* Found the key */
746
747 #ifndef UNIQUE_KEYS
748 /* FIRST! Check if there is a list with identical sizes */
749 x = ExpSplayTreeNodeSame(Node);
750 if (x)
751 {
752 /* There is several, pick one from the list */
753
754 /* 'x' is the new root node */
755
756 ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node);
757 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
758 ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node);
759
760 #ifdef WEIGHT
761 ExpSplayTreeNodeSetWeight(x, ExpSplayTreeNodeGetWeight(Node));
762 #endif
763
764 *RemovedNode = Node;
765 return x;
766 }
767 #endif
768
769 if (ExpSplayTreeSmallerChildNode(Node) == NULL)
770 {
771 x = ExpSplayTreeLargerChildNode(Node);
772 }
773 else
774 {
775 x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node));
776 ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node);
777 }
778 *RemovedNode = Node;
779
780 #ifdef WEIGHT
781 if (x != NULL)
782 {
783 ExpSplayTreeNodeSetWeight(x, tweight - 1);
784 }
785 #endif
786
787 return x;
788 }
789 else
790 {
791 *RemovedNode = NULL; /* No match */
792 return Node; /* It wasn't there */
793 }
794 }
795
796
797 inline PSPLAY_TREE_NODE
798 ExpRemoveSplayTree(PSPLAY_TREE Tree,
799 PVOID Key,
800 PSPLAY_TREE_NODE Node,
801 PSPLAY_TREE_NODE * RemovedNode)
802 {
803 return (*((PSPLAY_TREE_REMOVE)Tree->Reserved[REMOVE_INDEX]))(Tree, Key, Node, RemovedNode);
804 }
805
806
807 /*
808 * The lock for the tree must be acquired when this routine is called.
809 */
810 ULONG
811 ExpPrintSplayTree(PSPLAY_TREE Tree,
812 PSPLAY_TREE_NODE Node,
813 ULONG Distance)
814 {
815 PSPLAY_TREE_NODE n;
816 ULONG d = 0;
817 ULONG i;
818
819 if (Node == NULL)
820 return 0;
821
822 Distance += ExpPrintSplayTree(Tree, ExpSplayTreeLargerChildNode(Node), Distance + 1);
823
824 for (i = 0; i < Distance; i++)
825 {
826 DbgPrint(" ");
827 }
828
829 if (Tree->Weighted)
830 {
831 DbgPrint("%d(%d)[%d]", ExpSplayTreeNodeKey(Node), ExpSplayTreeNodeGetWeight(Node), i);
832 }
833 else
834 {
835 DbgPrint("%d[%d]", ExpSplayTreeNodeKey(Node), i);
836 }
837
838 for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n))
839 {
840 d += i;
841
842 DbgPrint(" [+]");
843 }
844
845 d += i;
846
847 d += ExpPrintSplayTree(Tree, ExpSplayTreeSmallerChildNode(Node), Distance + 1);
848
849 return d;
850 }
851
852
853 #define MAX_DIFF 4
854
855 #ifdef WEIGHT
856
857 /*
858 * The lock for the tree must be acquired when this routine is called.
859 * Returns the new root of the tree.
860 * Use of this routine could improve performance, or it might not.
861 * FIXME: Do some performance tests
862 */
863 PSPLAY_TREE_NODE
864 ExpSplayTreeMaxTreeWeight(PSPLAY_TREE Tree,
865 PSPLAY_TREE_NODE Node)
866 {
867 PSPLAY_TREE_NODE First = Node;
868 LONG Diff;
869
870 do
871 {
872 Diff = ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))
873 - ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node));
874
875 if (Diff >= MAX_DIFF)
876 {
877 Node = ExpSplayTreeSmallerChildNode(Node);
878 }
879 else if (Diff <= -MAX_DIFF)
880 {
881 Node = ExpSplayTreeLargerChildNode(Node);
882 }
883 else
884 break;
885 } while (abs(Diff) >= MAX_DIFF);
886
887 if (Node != First)
888 return ExpSplayTree(Tree, ExpSplayTreeNodeKey(Node), First);
889 else
890 return First;
891 }
892
893 #endif
894
895
896 /*
897 * Default key compare function. Compares the integer values of the two keys.
898 */
899 LONG STDCALL
900 ExpSplayTreeDefaultCompare(IN PVOID Key1,
901 IN PVOID Key2)
902 {
903 if (Key1 == Key2)
904 return 0;
905
906 return (((LONG_PTR) Key1 < (LONG_PTR) Key2) ? -1 : 1);
907 }
908
909
910 /*
911 * Initializes a splay tree.
912 */
913 BOOLEAN STDCALL
914 ExInitializeSplayTree(IN PSPLAY_TREE Tree,
915 IN PKEY_COMPARATOR Compare,
916 IN BOOLEAN Weighted)
917 {
918 RtlZeroMemory(Tree, sizeof(SPLAY_TREE));
919
920 Tree->Compare = (Compare == NULL)
921 ? ExpSplayTreeDefaultCompare : Compare;
922
923 Tree->Weighted = Weighted;
924
925 if (Weighted)
926 {
927 Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeWeight;
928 Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeWeight;
929 Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeWeight;
930 Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeWeight;
931 }
932 else
933 {
934 Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeNoWeight;
935 Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeNoWeight;
936 Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeNoWeight;
937 Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeNoWeight;
938 }
939
940 ExInitializePagedLookasideList(
941 &Tree->LookasideList, /* Lookaside list */
942 NULL, /* Allocate routine */
943 NULL, /* Free routine */
944 0, /* Flags */
945 sizeof(SPLAY_TREE_NODE), /* Size of each entry */
946 TAG('E','X','S','T'), /* Tag */
947 0); /* Depth */
948
949 ExInitializeFastMutex(&Tree->Lock);
950
951 return TRUE;
952 }
953
954
955 /*
956 * Release resources used by a splay tree.
957 */
958 VOID STDCALL
959 ExDeleteSplayTree(IN PSPLAY_TREE Tree)
960 {
961 PSPLAY_TREE_NODE RemovedNode;
962 PSPLAY_TREE_NODE Node;
963
964 /* Remove all nodes */
965 Node = ExpSplayTreeRootNode(Tree);
966 while (Node != NULL)
967 {
968 Node = ExpRemoveSplayTree(Tree, Node->Key, Node, &RemovedNode);
969
970 if (RemovedNode != NULL)
971 {
972 ExpDestroySplayTreeNode(Tree, RemovedNode);
973 }
974 }
975
976 ExDeletePagedLookasideList(&Tree->LookasideList);
977 }
978
979
980 /*
981 * Insert a value in a splay tree.
982 */
983 VOID STDCALL
984 ExInsertSplayTree(IN PSPLAY_TREE Tree,
985 IN PVOID Key,
986 IN PVOID Value)
987 {
988 PSPLAY_TREE_NODE Node;
989 PSPLAY_TREE_NODE NewNode;
990
991 /* FIXME: Use SEH for error reporting */
992
993 NewNode = ExpCreateSplayTreeNode(Tree, Value);
994
995 ExAcquireFastMutex(&Tree->Lock);
996 Node = ExpInsertSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), NewNode);
997 ExpSplayTreeRootNode(Tree) = Node;
998 ExReleaseFastMutex(&Tree->Lock);
999 }
1000
1001
1002 /*
1003 * Search for a value associated with a given key in a splay tree.
1004 */
1005 BOOLEAN STDCALL
1006 ExSearchSplayTree(IN PSPLAY_TREE Tree,
1007 IN PVOID Key,
1008 OUT PVOID * Value)
1009 {
1010 PSPLAY_TREE_NODE Node;
1011 BOOLEAN Status;
1012
1013 ExAcquireFastMutex(&Tree->Lock);
1014 Status = ExpSearchSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &Node);
1015
1016 if (Status)
1017 {
1018 ExpSplayTreeRootNode(Tree) = Node;
1019 *Value = ExpSplayTreeNodeValue(Node);
1020 ExReleaseFastMutex(&Tree->Lock);
1021 return TRUE;
1022 }
1023 else
1024 {
1025 ExReleaseFastMutex(&Tree->Lock);
1026 return FALSE;
1027 }
1028 }
1029
1030
1031 /*
1032 * Remove a value associated with a given key from a splay tree.
1033 */
1034 BOOLEAN STDCALL
1035 ExRemoveSplayTree(IN PSPLAY_TREE Tree,
1036 IN PVOID Key,
1037 IN PVOID * Value)
1038 {
1039 PSPLAY_TREE_NODE RemovedNode;
1040 PSPLAY_TREE_NODE Node;
1041
1042 ExAcquireFastMutex(&Tree->Lock);
1043 Node = ExpRemoveSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &RemovedNode);
1044 ExpSplayTreeRootNode(Tree) = Node;
1045 ExReleaseFastMutex(&Tree->Lock);
1046
1047 if (RemovedNode != NULL)
1048 {
1049 *Value = ExpSplayTreeNodeValue(RemovedNode);
1050 ExpDestroySplayTreeNode(Tree, RemovedNode);
1051 return TRUE;
1052 }
1053 else
1054 {
1055 return FALSE;
1056 }
1057 }
1058
1059
1060 /*
1061 * Return the weight of the root node in the splay tree.
1062 * The returned value is the number of nodes in the tree.
1063 */
1064 BOOLEAN STDCALL
1065 ExWeightOfSplayTree(IN PSPLAY_TREE Tree,
1066 OUT PULONG Weight)
1067 {
1068 ExAcquireFastMutex(&Tree->Lock);
1069
1070 if (!Tree->Weighted)
1071 {
1072 ExReleaseFastMutex(&Tree->Lock);
1073 return FALSE;
1074 }
1075
1076 *Weight = ExpSplayTreeNodeWeight(ExpSplayTreeRootNode(Tree));
1077 ExReleaseFastMutex(&Tree->Lock);
1078 return TRUE;
1079 }
1080
1081 /* EOF */