Process Hacker
collect.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * additional collection types
4  *
5  * Copyright (C) 2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phbase.h>
24 
32  _Out_ PPH_AVL_TREE Tree,
33  _In_ PPH_AVL_TREE_COMPARE_FUNCTION CompareFunction
34  )
35 {
36  Tree->Root.Parent = NULL;
37  Tree->Root.Left = NULL;
38  Tree->Root.Right = NULL;
39  Tree->Root.Balance = 0;
40  Tree->Count = 0;
41 
42  Tree->CompareFunction = CompareFunction;
43 }
44 
53  _In_ PPH_AVL_TREE Tree,
54  _In_ PPH_AVL_LINKS Element,
55  _Out_ PLONG Result
56  )
57 {
58  PPH_AVL_LINKS links;
59  LONG result;
60 
61  links = PhRootElementAvlTree(Tree);
62 
63  if (!links)
64  {
65  *Result = 1;
66 
67  return &Tree->Root;
68  }
69 
70  while (TRUE)
71  {
72  result = Tree->CompareFunction(Element, links);
73 
74  if (result == 0)
75  {
76  *Result = 0;
77 
78  return links;
79  }
80  else if (result < 0)
81  {
82  if (links->Left)
83  {
84  links = links->Left;
85  }
86  else
87  {
88  *Result = -1;
89 
90  return links;
91  }
92  }
93  else
94  {
95  if (links->Right)
96  {
97  links = links->Right;
98  }
99  else
100  {
101  *Result = 1;
102 
103  return links;
104  }
105  }
106  }
107 }
108 
110  _Inout_ PPH_AVL_LINKS *Root
111  )
112 {
114  PPH_AVL_LINKS Q;
115 
116  // P
117  // | |
118  // A Q
119  // | |
120  // B C
121  //
122  // becomes
123  //
124  // Q
125  // | |
126  // P C
127  // | |
128  // A B
129  //
130  // P and Q must exist.
131  // B may not exist.
132  // A and C are not affected.
133 
134  P = *Root;
135  Q = P->Right;
136 
137  // The new root is Q
138 
139  *Root = Q;
140  Q->Parent = P->Parent;
141 
142  // P.Right = Q.Left (transfer B)
143 
144  P->Right = Q->Left;
145 
146  if (P->Right)
147  P->Right->Parent = P;
148 
149  // Q.Left = P
150 
151  Q->Left = P;
152  P->Parent = Q;
153 }
154 
156  _Inout_ PPH_AVL_LINKS *Root
157  )
158 {
160  PPH_AVL_LINKS Q;
162 
163  // P
164  // | |
165  // A Q
166  // | |
167  // R D
168  // | |
169  // B C
170  //
171  // becomes
172  //
173  // R
174  // | |
175  // P Q
176  // | | | |
177  // A B C D
178  //
179  // P, Q, and R must exist.
180  // B and C may not exist.
181  // A and D are not affected.
182 
183  // PhpRotateRightAvlLinks(&(*Root)->Right);
184  // PhpRotateLeftAvlLinks(Root);
185 
186  // P is the current root
187  // Q is P.Right
188  // R is Q.Left (P.Right.Left)
189 
190  P = *Root;
191  Q = P->Right;
192  R = Q->Left;
193 
194  // The new root is R
195 
196  *Root = R;
197  R->Parent = P->Parent;
198 
199  // Q.Left = R.Right (transfer C)
200 
201  Q->Left = R->Right;
202 
203  if (Q->Left)
204  Q->Left->Parent = Q;
205 
206  // R.Right = Q
207 
208  R->Right = Q;
209  Q->Parent = R;
210 
211  // P.Right = R.Left (transfer B)
212 
213  P->Right = R->Left;
214 
215  if (P->Right)
216  P->Right->Parent = P;
217 
218  // R.Left = P
219 
220  R->Left = P;
221  P->Parent = R;
222 }
223 
225  _Inout_ PPH_AVL_LINKS *Root
226  )
227 {
228  PPH_AVL_LINKS Q;
230 
231  // Q
232  // | |
233  // P C
234  // | |
235  // A B
236  //
237  // becomes
238  //
239  // P
240  // | |
241  // A Q
242  // | |
243  // B C
244  //
245  // Q and P must exist.
246  // B may not exist.
247  // A and C are not affected.
248 
249  Q = *Root;
250  P = Q->Left;
251 
252  // The new root is P
253 
254  *Root = P;
255  P->Parent = Q->Parent;
256 
257  // Q.Left = P.Right (transfer B)
258 
259  Q->Left = P->Right;
260 
261  if (Q->Left)
262  Q->Left->Parent = Q;
263 
264  // P.Right = Q
265 
266  P->Right = Q;
267  Q->Parent = P;
268 }
269 
271  _Inout_ PPH_AVL_LINKS *Root
272  )
273 {
275  PPH_AVL_LINKS Q;
277 
278  // P
279  // | |
280  // Q D
281  // | |
282  // A R
283  // | |
284  // B C
285  //
286  // becomes
287  //
288  // R
289  // | |
290  // Q P
291  // | | | |
292  // A B C D
293  //
294  // P, Q, and R must exist.
295  // B and C may not exist.
296  // A and D are not affected.
297 
298  // PhpRotateLeftAvlLinks(&(*Root)->Left);
299  // PhpRotateRightAvlLinks(Root);
300 
301  // P is the current root
302  // Q is P.Left
303  // R is Q.Right (P.Left.Right)
304 
305  P = *Root;
306  Q = P->Left;
307  R = Q->Right;
308 
309  // The new root is R
310 
311  *Root = R;
312  R->Parent = P->Parent;
313 
314  // Q.Right = R.Left (transfer B)
315 
316  Q->Right = R->Left;
317 
318  if (Q->Right)
319  Q->Right->Parent = Q;
320 
321  // R.Left = Q
322 
323  R->Left = Q;
324  Q->Parent = R;
325 
326  // P.Left = R.Right (transfer C)
327 
328  P->Left = R->Right;
329 
330  if (P->Left)
331  P->Left->Parent = P;
332 
333  // R.Right = P
334 
335  R->Right = P;
336  P->Parent = R;
337 }
338 
340  _Inout_ PPH_AVL_LINKS *Root
341  )
342 {
344  PPH_AVL_LINKS Q;
346 
347  P = *Root;
348 
349  if (P->Balance == -1)
350  {
351  Q = P->Left;
352 
353  if (Q->Balance == -1)
354  {
355  // Left-left
356 
358 
359  P->Balance = 0;
360  Q->Balance = 0;
361 
362  return 1;
363  }
364  else if (Q->Balance == 1)
365  {
366  // Left-right
367 
368  R = Q->Right;
369 
371 
372  if (R->Balance == -1)
373  {
374  P->Balance = 1;
375  Q->Balance = 0;
376  }
377  else if (R->Balance == 1)
378  {
379  P->Balance = 0;
380  Q->Balance = -1;
381  }
382  else
383  {
384  P->Balance = 0;
385  Q->Balance = 0;
386  }
387 
388  R->Balance = 0;
389 
390  return 2;
391  }
392  else
393  {
394  // Special (only occurs when removing)
395 
396  // D
397  // | |
398  // B E
399  // | |
400  // A C
401  //
402  // Removing E results in:
403  //
404  // D
405  // |
406  // B
407  // | |
408  // A C
409  //
410  // which is unbalanced. Rotating right at B results in:
411  //
412  // B
413  // | |
414  // A D
415  // |
416  // C
417  //
418  // The same applies for the mirror case.
419 
421 
422  Q->Balance = 1;
423 
424  return 3;
425  }
426  }
427  else
428  {
429  Q = P->Right;
430 
431  if (Q->Balance == 1)
432  {
433  // Right-right
434 
435  PhpRotateLeftAvlLinks(Root);
436 
437  P->Balance = 0;
438  Q->Balance = 0;
439 
440  return 1;
441  }
442  else if (Q->Balance == -1)
443  {
444  // Right-left
445 
446  R = Q->Left;
447 
449 
450  if (R->Balance == -1)
451  {
452  P->Balance = 0;
453  Q->Balance = 1;
454  }
455  else if (R->Balance == 1)
456  {
457  P->Balance = -1;
458  Q->Balance = 0;
459  }
460  else
461  {
462  P->Balance = 0;
463  Q->Balance = 0;
464  }
465 
466  R->Balance = 0;
467 
468  return 2;
469  }
470  else
471  {
472  // Special (only occurs when removing)
473 
474  PhpRotateLeftAvlLinks(Root);
475 
476  Q->Balance = -1;
477 
478  return 3;
479  }
480  }
481 }
482 
493  _Inout_ PPH_AVL_TREE Tree,
494  _Out_ PPH_AVL_LINKS Element
495  )
496 {
497  LONG result;
499  PPH_AVL_LINKS root;
500  LONG balance;
501 
502  P = PhpFindElementAvlTree(Tree, Element, &result);
503 
504  if (result < 0)
505  P->Left = Element;
506  else if (result > 0)
507  P->Right = Element;
508  else
509  return P;
510 
511  Element->Parent = P;
512  Element->Left = NULL;
513  Element->Right = NULL;
514  Element->Balance = 0;
515 
516  // Balance the tree.
517 
518  P = Element;
519  root = PhRootElementAvlTree(Tree);
520 
521  while (P != root)
522  {
523  // In this implementation, the balance factor is the right height minus left height.
524 
525  if (P->Parent->Left == P)
526  balance = -1;
527  else
528  balance = 1;
529 
530  P = P->Parent;
531 
532  if (P->Balance == 0)
533  {
534  // The balance becomes -1 or 1. Rotations are not needed
535  // yet, but we should keep tracing upwards.
536 
537  P->Balance = balance;
538  }
539  else if (P->Balance != balance)
540  {
541  // The balance is opposite the new balance, so it now
542  // becomes 0.
543 
544  P->Balance = 0;
545 
546  break;
547  }
548  else
549  {
550  PPH_AVL_LINKS *ref;
551 
552  // The balance is the same as the new balance, meaning
553  // it now becomes -2 or 2. Rotations are needed.
554 
555  if (P->Parent->Left == P)
556  ref = &P->Parent->Left;
557  else
558  ref = &P->Parent->Right;
559 
561 
562  break;
563  }
564  }
565 
566  Tree->Count++;
567 
568  return NULL;
569 }
570 
578  _Inout_ PPH_AVL_TREE Tree,
579  _Inout_ PPH_AVL_LINKS Element
580  )
581 {
582  PPH_AVL_LINKS newElement;
583  PPH_AVL_LINKS *replace;
585  PPH_AVL_LINKS root;
586  LONG balance;
587 
588  if (!Element->Left || !Element->Right)
589  {
590  newElement = Element;
591  }
592  else if (Element->Balance >= 0) // pick the side depending on the balance to minimize rebalances
593  {
594  newElement = Element->Right;
595 
596  while (newElement->Left)
597  newElement = newElement->Left;
598  }
599  else
600  {
601  newElement = Element->Left;
602 
603  while (newElement->Right)
604  newElement = newElement->Right;
605  }
606 
607  if (newElement->Parent->Left == newElement)
608  {
609  replace = &newElement->Parent->Left;
610  balance = -1;
611  }
612  else
613  {
614  replace = &newElement->Parent->Right;
615  balance = 1;
616  }
617 
618  if (!newElement->Right)
619  {
620  *replace = newElement->Left;
621 
622  if (newElement->Left)
623  newElement->Left->Parent = newElement->Parent;
624  }
625  else
626  {
627  *replace = newElement->Right;
628  newElement->Right->Parent = newElement->Parent; // we know Right exists
629  }
630 
631  P = newElement->Parent;
632  root = &Tree->Root;
633 
634  while (P != root)
635  {
636  if (P->Balance == balance)
637  {
638  // The balance is cancelled by the remove operation and becomes 0.
639  // Rotations are not needed yet, but we should keep tracing upwards.
640 
641  P->Balance = 0;
642  }
643  else if (P->Balance == 0)
644  {
645  // The balance is 0, so it now becomes -1 or 1.
646 
647  P->Balance = -balance;
648 
649  break;
650  }
651  else
652  {
653  PPH_AVL_LINKS *ref;
654 
655  // The balance is the same as the new balance, meaning
656  // it now becomes -2 or 2. Rotations are needed.
657 
658  if (P->Parent->Left == P)
659  ref = &P->Parent->Left;
660  else
661  ref = &P->Parent->Right;
662 
663  // We can stop tracing if we have a special case rotation.
664  if (PhpRebalanceAvlLinks(ref) == 3)
665  break;
666 
667  P = P->Parent;
668  }
669 
670  if (P->Parent->Left == P)
671  balance = -1;
672  else
673  balance = 1;
674 
675  P = P->Parent;
676  }
677 
678  if (newElement != Element)
679  {
680  // Replace the subject with the new subject.
681 
682  *newElement = *Element;
683 
684  if (Element->Parent->Left == Element)
685  newElement->Parent->Left = newElement;
686  else
687  newElement->Parent->Right = newElement;
688 
689  if (newElement->Left)
690  newElement->Left->Parent = newElement;
691  if (newElement->Right)
692  newElement->Right->Parent = newElement;
693  }
694 
695  Tree->Count--;
696 }
697 
707  _In_ PPH_AVL_TREE Tree,
708  _In_ PPH_AVL_LINKS Element
709  )
710 {
711  PPH_AVL_LINKS links;
712  LONG result;
713 
714  links = PhpFindElementAvlTree(Tree, Element, &result);
715 
716  if (result == 0)
717  return links;
718  else
719  return NULL;
720 }
721 
732  _In_ PPH_AVL_TREE Tree,
733  _In_ PPH_AVL_LINKS Element,
734  _Out_ PLONG Result
735  )
736 {
737  PPH_AVL_LINKS links;
738  LONG result;
739 
740  links = PhpFindElementAvlTree(Tree, Element, &result);
741 
742  if (links == &Tree->Root)
743  return NULL;
744 
745  *Result = result;
746 
747  return links;
748 }
749 
758  _In_ PPH_AVL_TREE Tree
759  )
760 {
761  PPH_AVL_LINKS links;
762 
763  links = PhRootElementAvlTree(Tree);
764 
765  if (!links)
766  return NULL;
767 
768  while (links->Left)
769  links = links->Left;
770 
771  return links;
772 }
773 
782  _In_ PPH_AVL_TREE Tree
783  )
784 {
785  PPH_AVL_LINKS links;
786 
787  links = PhRootElementAvlTree(Tree);
788 
789  if (!links)
790  return NULL;
791 
792  while (links->Right)
793  links = links->Right;
794 
795  return links;
796 }
797 
807  _In_ PPH_AVL_LINKS Element
808  )
809 {
810  PPH_AVL_LINKS links;
811 
812  if (Element->Right)
813  {
814  Element = Element->Right;
815 
816  while (Element->Left)
817  Element = Element->Left;
818 
819  return Element;
820  }
821  else
822  {
823  // Trace back to the next vertical level. Note
824  // that this code does in fact return NULL when there
825  // are no more elements because of the way the root
826  // element is constructed.
827 
828  links = Element->Parent;
829 
830  while (links && links->Right == Element)
831  {
832  Element = links;
833  links = links->Parent;
834  }
835 
836  return links;
837  }
838 }
839 
849  _In_ PPH_AVL_LINKS Element
850  )
851 {
852  PPH_AVL_LINKS links;
853 
854  if (Element->Left)
855  {
856  Element = Element->Left;
857 
858  while (Element->Right)
859  Element = Element->Right;
860 
861  return Element;
862  }
863  else
864  {
865  links = Element->Parent;
866 
867  while (links && links->Left == Element)
868  {
869  Element = links;
870  links = links->Parent;
871  }
872 
873  if (links)
874  {
875  // We need an additional check because the tree root is
876  // stored in Root.Right, not Left.
877  if (!links->Parent)
878  return NULL; // reached Root, so no more elements
879  }
880 
881  return links;
882  }
883 }
884 
895  _In_ PPH_AVL_TREE Tree,
896  _In_ PH_TREE_ENUMERATION_ORDER Order,
897  _In_ PPH_ENUM_AVL_TREE_CALLBACK Callback,
898  _In_opt_ PVOID Context
899  )
900 {
901  // The maximum height of an AVL tree is around 1.44 * log2(n).
902  // The maximum number of elements in this implementation is
903  // 2^32, so the maximum height is around 46.08.
904  PPH_AVL_LINKS stackBase[47];
905  PPH_AVL_LINKS *stack;
906  PPH_AVL_LINKS links;
907 
908  stack = stackBase;
909 
910  switch (Order)
911  {
913  links = PhRootElementAvlTree(Tree);
914 
915  while (links)
916  {
917  *stack++ = links;
918  links = links->Left;
919  }
920 
921  while (stack != stackBase)
922  {
923  links = *--stack;
924 
925  if (!Callback(Tree, links, Context))
926  break;
927 
928  links = links->Right;
929 
930  while (links)
931  {
932  *stack++ = links;
933  links = links->Left;
934  }
935  }
936 
937  break;
939  links = PhRootElementAvlTree(Tree);
940 
941  while (links)
942  {
943  *stack++ = links;
944  links = links->Right;
945  }
946 
947  while (stack != stackBase)
948  {
949  links = *--stack;
950 
951  if (!Callback(Tree, links, Context))
952  break;
953 
954  links = links->Left;
955 
956  while (links)
957  {
958  *stack++ = links;
959  links = links->Right;
960  }
961  }
962 
963  break;
964  }
965 }