Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / lib / rbtree.c
1 /*
2  * rbtree.c     Red-black balanced binary trees.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  *  Copyright 2004,2006  The FreeRADIUS server project
21  */
22
23 #include <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include <freeradius-devel/libradius.h>
27
28 /* red-black tree description */
29 typedef enum { Black, Red } NodeColor;
30
31 struct rbnode_t {
32     rbnode_t    *Left;          /* left child */
33     rbnode_t    *Right;         /* right child */
34     rbnode_t    *Parent;        /* parent */
35     NodeColor   Color;          /* node color (black, red) */
36     void        *Data;          /* data stored in node */
37 };
38
39 #define NIL &Sentinel           /* all leafs are sentinels */
40 static rbnode_t Sentinel = { NIL, NIL, NULL, Black, NULL};
41
42 struct rbtree_t {
43 #ifndef NDEBUG
44         uint32_t magic;
45 #endif
46         rbnode_t *Root;
47         int     num_elements;
48         int (*Compare)(const void *, const void *);
49         int replace_flag;
50         void (*freeNode)(void *);
51 };
52 #define RBTREE_MAGIC (0x5ad09c42)
53
54 /*
55  *      Walks the tree to delete all nodes.
56  *      Does NOT re-balance it!
57  */
58 static void FreeWalker(rbtree_t *tree, rbnode_t *X)
59 {
60         if (X->Left != NIL) FreeWalker(tree, X->Left);
61         if (X->Right != NIL) FreeWalker(tree, X->Right);
62
63         if (tree->freeNode) tree->freeNode(X->Data);
64         free(X);
65 }
66
67 void rbtree_free(rbtree_t *tree)
68 {
69         if (!tree) return;
70
71         /*
72          *      Walk the tree, deleting the nodes...
73          */
74         if (tree->Root != NIL) FreeWalker(tree, tree->Root);
75
76 #ifndef NDEBUG
77         tree->magic = 0;
78 #endif
79         tree->Root = NULL;
80         free(tree);
81 }
82
83 /*
84  *      Create a new red-black tree.
85  */
86 rbtree_t *rbtree_create(int (*Compare)(const void *, const void *),
87                         void (*freeNode)(void *),
88                         int replace_flag)
89 {
90         rbtree_t        *tree;
91
92         if (!Compare) return NULL;
93
94         tree = malloc(sizeof(*tree));
95         if (!tree) return NULL;
96
97         memset(tree, 0, sizeof(*tree));
98 #ifndef NDEBUG
99         tree->magic = RBTREE_MAGIC;
100 #endif
101         tree->Root = NIL;
102         tree->Compare = Compare;
103         tree->replace_flag = replace_flag;
104         tree->freeNode = freeNode;
105
106         return tree;
107 }
108
109
110 static void RotateLeft(rbtree_t *tree, rbnode_t *X)
111 {
112         /**************************
113          *  rotate Node X to left *
114          **************************/
115
116         rbnode_t *Y = X->Right;
117
118         /* establish X->Right link */
119         X->Right = Y->Left;
120         if (Y->Left != NIL) Y->Left->Parent = X;
121
122         /* establish Y->Parent link */
123         if (Y != NIL) Y->Parent = X->Parent;
124         if (X->Parent) {
125                 if (X == X->Parent->Left)
126                         X->Parent->Left = Y;
127                 else
128                         X->Parent->Right = Y;
129         } else {
130                 tree->Root = Y;
131         }
132
133         /* link X and Y */
134         Y->Left = X;
135         if (X != NIL) X->Parent = Y;
136 }
137
138 static void RotateRight(rbtree_t *tree, rbnode_t *X)
139 {
140         /****************************
141          *  rotate Node X to right  *
142          ****************************/
143
144         rbnode_t *Y = X->Left;
145
146         /* establish X->Left link */
147         X->Left = Y->Right;
148         if (Y->Right != NIL) Y->Right->Parent = X;
149
150         /* establish Y->Parent link */
151         if (Y != NIL) Y->Parent = X->Parent;
152         if (X->Parent) {
153                 if (X == X->Parent->Right)
154                         X->Parent->Right = Y;
155                 else
156                         X->Parent->Left = Y;
157         } else {
158                 tree->Root = Y;
159         }
160
161         /* link X and Y */
162         Y->Right = X;
163         if (X != NIL) X->Parent = Y;
164 }
165
166 static void InsertFixup(rbtree_t *tree, rbnode_t *X)
167 {
168         /*************************************
169          *  maintain red-black tree balance  *
170          *  after inserting node X           *
171          *************************************/
172
173         /* check red-black properties */
174         while (X != tree->Root && X->Parent->Color == Red) {
175                 /* we have a violation */
176                 if (X->Parent == X->Parent->Parent->Left) {
177                         rbnode_t *Y = X->Parent->Parent->Right;
178                         if (Y->Color == Red) {
179
180                                 /* uncle is red */
181                                 X->Parent->Color = Black;
182                                 Y->Color = Black;
183                                 X->Parent->Parent->Color = Red;
184                                 X = X->Parent->Parent;
185                         } else {
186
187                                 /* uncle is black */
188                                 if (X == X->Parent->Right) {
189                                         /* make X a left child */
190                                         X = X->Parent;
191                                         RotateLeft(tree, X);
192                                 }
193
194                                 /* recolor and rotate */
195                                 X->Parent->Color = Black;
196                                 X->Parent->Parent->Color = Red;
197                                 RotateRight(tree, X->Parent->Parent);
198                         }
199                 } else {
200
201                         /* mirror image of above code */
202                         rbnode_t *Y = X->Parent->Parent->Left;
203                         if (Y->Color == Red) {
204
205                                 /* uncle is red */
206                                 X->Parent->Color = Black;
207                                 Y->Color = Black;
208                                 X->Parent->Parent->Color = Red;
209                                 X = X->Parent->Parent;
210                         } else {
211
212                                 /* uncle is black */
213                                 if (X == X->Parent->Left) {
214                                         X = X->Parent;
215                                         RotateRight(tree, X);
216                                 }
217                                 X->Parent->Color = Black;
218                                 X->Parent->Parent->Color = Red;
219                                 RotateLeft(tree, X->Parent->Parent);
220                         }
221                 }
222         }
223
224         tree->Root->Color = Black;
225 }
226
227
228 /*
229  *      Insert an element into the tree.
230  */
231 int rbtree_insert(rbtree_t *tree, void *Data)
232 {
233         rbnode_t *Current, *Parent, *X;
234
235         /***********************************************
236          *  allocate node for Data and insert in tree  *
237          ***********************************************/
238
239         /* find where node belongs */
240         Current = tree->Root;
241         Parent = NULL;
242         while (Current != NIL) {
243                 int result;
244
245                 /*
246                  *      See if two entries are identical.
247                  */
248                 result = tree->Compare(Data, Current->Data);
249                 if (result == 0) {
250                         /*
251                          *      Don't replace the entry.
252                          */
253                         if (tree->replace_flag == 0) {
254                                 return 0;
255                         }
256
257                         /*
258                          *      Do replace the entry.
259                          */
260                         if (tree->freeNode) tree->freeNode(Current->Data);
261                         Current->Data = Data;
262                         return 1;
263                 }
264
265                 Parent = Current;
266                 Current = (result < 0) ? Current->Left : Current->Right;
267         }
268
269         /* setup new node */
270         if ((X = malloc (sizeof(*X))) == NULL) {
271                 exit(1);        /* FIXME! */
272         }
273
274         X->Data = Data;
275         X->Parent = Parent;
276         X->Left = NIL;
277         X->Right = NIL;
278         X->Color = Red;
279
280         /* insert node in tree */
281         if (Parent) {
282                 if (tree->Compare(Data, Parent->Data) <= 0)
283                         Parent->Left = X;
284                 else
285                         Parent->Right = X;
286         } else {
287                 tree->Root = X;
288         }
289
290         InsertFixup(tree, X);
291
292         tree->num_elements++;
293
294         return 1;
295 }
296
297 static void DeleteFixup(rbtree_t *tree, rbnode_t *X, rbnode_t *Parent)
298 {
299         /*************************************
300          *  maintain red-black tree balance  *
301          *  after deleting node X            *
302          *************************************/
303
304         while (X != tree->Root && X->Color == Black) {
305                 if (X == Parent->Left) {
306                         rbnode_t *W = Parent->Right;
307                         if (W->Color == Red) {
308                                 W->Color = Black;
309                                 Parent->Color = Red; /* Parent != NIL? */
310                                 RotateLeft(tree, Parent);
311                                 W = Parent->Right;
312                         }
313                         if (W->Left->Color == Black && W->Right->Color == Black) {
314                                 if (W != NIL) W->Color = Red;
315                                 X = Parent;
316                                 Parent = X->Parent;
317                         } else {
318                                 if (W->Right->Color == Black) {
319                                         if (W->Left != NIL) W->Left->Color = Black;
320                                         W->Color = Red;
321                                         RotateRight(tree, W);
322                                         W = Parent->Right;
323                                 }
324                                 W->Color = Parent->Color;
325                                 if (Parent != NIL) Parent->Color = Black;
326                                 if (W->Right->Color != Black) {
327                                         W->Right->Color = Black;
328                                 }
329                                 RotateLeft(tree, Parent);
330                                 X = tree->Root;
331                         }
332                 } else {
333                         rbnode_t *W = Parent->Left;
334                         if (W->Color == Red) {
335                                 W->Color = Black;
336                                 Parent->Color = Red; /* Parent != NIL? */
337                                 RotateRight(tree, Parent);
338                                 W = Parent->Left;
339                         }
340                         if (W->Right->Color == Black && W->Left->Color == Black) {
341                                 if (W != NIL) W->Color = Red;
342                                 X = Parent;
343                                 Parent = X->Parent;
344                         } else {
345                                 if (W->Left->Color == Black) {
346                                         if (W->Right != NIL) W->Right->Color = Black;
347                                         W->Color = Red;
348                                         RotateLeft(tree, W);
349                                         W = Parent->Left;
350                                 }
351                                 W->Color = Parent->Color;
352                                 if (Parent != NIL) Parent->Color = Black;
353                                 if (W->Left->Color != Black) {
354                                         W->Left->Color = Black;
355                                 }
356                                 RotateRight(tree, Parent);
357                                 X = tree->Root;
358                         }
359                 }
360         }
361         X->Color = Black;
362 }
363
364 /*
365  *      Delete an element from the tree.
366  */
367 void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
368 {
369         rbnode_t *X, *Y;
370         rbnode_t *Parent;
371
372         /*****************************
373          *  delete node Z from tree  *
374          *****************************/
375
376         if (!Z || Z == NIL) return;
377
378         if (Z->Left == NIL || Z->Right == NIL) {
379                 /* Y has a NIL node as a child */
380                 Y = Z;
381         } else {
382                 /* find tree successor with a NIL node as a child */
383                 Y = Z->Right;
384                 while (Y->Left != NIL) Y = Y->Left;
385         }
386
387         /* X is Y's only child */
388         if (Y->Left != NIL)
389                 X = Y->Left;
390         else
391                 X = Y->Right;   /* may be NIL! */
392
393         /* remove Y from the parent chain */
394         Parent = Y->Parent;
395         if (X != NIL) X->Parent = Parent;
396
397         if (Parent)
398                 if (Y == Parent->Left)
399                         Parent->Left = X;
400                 else
401                         Parent->Right = X;
402         else
403                 tree->Root = X;
404
405         if (Y != Z) {
406                 /*
407                  *      Move the child's data to here, and then
408                  *      re-balance the tree.
409                  */
410                 if (tree->freeNode) tree->freeNode(Z->Data);
411                 Z->Data = Y->Data;
412                 Y->Data = NULL;
413         } else if (tree->freeNode) {
414                 tree->freeNode(Z->Data);
415         }
416
417         if (Y->Color == Black && X != NIL)
418                 DeleteFixup(tree, X, Parent);
419
420         free(Y);
421
422         tree->num_elements--;
423 }
424
425 /*
426  *      Delete a node from the tree, based on given data, which MUST
427  *      have come from rbtree_finddata().
428  */
429 int rbtree_deletebydata(rbtree_t *tree, const void *data)
430 {
431         rbnode_t *node = rbtree_find(tree, data);
432         
433         if (!node) return 0;    /* false */
434
435         rbtree_delete(tree, node);
436
437         return 1;
438 }
439
440
441 /*
442  *      Find an element in the tree, returning the data, not the node.
443  */
444 rbnode_t *rbtree_find(rbtree_t *tree, const void *Data)
445 {
446         /*******************************
447          *  find node containing Data  *
448          *******************************/
449
450         rbnode_t *Current = tree->Root;
451
452         while (Current != NIL) {
453                 int result = tree->Compare(Data, Current->Data);
454
455                 if (result == 0) {
456                         return Current;
457                 } else {
458                         Current = (result < 0) ?
459                                 Current->Left : Current->Right;
460                 }
461         }
462         return NULL;
463 }
464
465 /*
466  *      Find the user data.
467  */
468 void *rbtree_finddata(rbtree_t *tree, const void *Data)
469 {
470         rbnode_t *X;
471
472         X = rbtree_find(tree, Data);
473         if (!X) return NULL;
474
475         return X->Data;
476 }
477
478 /*
479  *      Walk the tree, Pre-order
480  *
481  *      We call ourselves recursively for each function, but that's OK,
482  *      as the stack is only log(N) deep, which is ~12 entries deep.
483  */
484 static int WalkNodePreOrder(rbnode_t *X,
485                             int (*callback)(void *, void *), void *context)
486 {
487         int rcode;
488
489         rcode = callback(context, X->Data);
490         if (rcode != 0) return rcode;
491
492         if (X->Left != NIL) {
493                 rcode = WalkNodePreOrder(X->Left, callback, context);
494                 if (rcode != 0) return rcode;
495         }
496
497         if (X->Right != NIL) {
498                 rcode = WalkNodePreOrder(X->Right, callback, context);
499                 if (rcode != 0) return rcode;
500         }
501
502         return 0;               /* we know everything returned zero */
503 }
504
505 /*
506  *      Inorder
507  */
508 static int WalkNodeInOrder(rbnode_t *X,
509                            int (*callback)(void *, void *), void *context)
510 {
511         int rcode;
512
513         if (X->Left != NIL) {
514                 rcode = WalkNodeInOrder(X->Left, callback, context);
515                 if (rcode != 0) return rcode;
516         }
517
518         rcode = callback(context, X->Data);
519         if (rcode != 0) return rcode;
520
521         if (X->Right != NIL) {
522                 rcode = WalkNodeInOrder(X->Right, callback, context);
523                 if (rcode != 0) return rcode;
524         }
525
526         return 0;               /* we know everything returned zero */
527 }
528
529
530 /*
531  *      PostOrder
532  */
533 static int WalkNodePostOrder(rbnode_t *X,
534                              int (*callback)(void *, void*), void *context)
535 {
536         int rcode;
537
538         if (X->Left != NIL) {
539                 rcode = WalkNodeInOrder(X->Left, callback, context);
540                 if (rcode != 0) return rcode;
541         }
542
543         if (X->Right != NIL) {
544                 rcode = WalkNodeInOrder(X->Right, callback, context);
545                 if (rcode != 0) return rcode;
546         }
547
548         rcode = callback(context, X->Data);
549         if (rcode != 0) return rcode;
550
551         return 0;               /* we know everything returned zero */
552 }
553
554 /*
555  *      Walk the entire tree.  The callback function CANNOT modify
556  *      the tree.
557  *
558  *      The callback function should return 0 to continue walking.
559  *      Any other value stops the walk, and is returned.
560  */
561 int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
562                 int (*callback)(void *, void *), void *context)
563 {
564         switch (order) {
565         case PreOrder:
566                 return WalkNodePreOrder(tree->Root, callback, context);
567         case InOrder:
568                 return WalkNodeInOrder(tree->Root, callback, context);
569         case PostOrder:
570                 return WalkNodePostOrder(tree->Root, callback, context);
571
572         default:
573                 break;
574         }
575
576         return -1;
577 }
578
579 int rbtree_num_elements(rbtree_t *tree)
580 {
581         if (!tree) return 0;
582
583         return tree->num_elements;
584 }
585
586
587 /*
588  *      Given a Node, return the data.
589  */
590 void *rbtree_node2data(rbtree_t *tree, rbnode_t *node)
591 {
592         tree = tree;            /* -Wunused */
593
594         if (!node) return NULL;
595
596         return node->Data;
597 }