import from branch_1_1:
[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 rbnode_t *rbtree_insertnode(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 NULL;
255                         }
256
257                         /*
258                          *      Do replace the entry.
259                          */
260                         if (tree->freeNode) tree->freeNode(Current->Data);
261                         Current->Data = Data;
262                         return Current;
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 X;
295 }
296
297 int rbtree_insert(rbtree_t *tree, void *Data)
298 {
299         if (rbtree_insertnode(tree, Data)) return 1;
300         return 0;
301 }
302
303 static void DeleteFixup(rbtree_t *tree, rbnode_t *X, rbnode_t *Parent)
304 {
305         /*************************************
306          *  maintain red-black tree balance  *
307          *  after deleting node X            *
308          *************************************/
309
310         while (X != tree->Root && X->Color == Black) {
311                 if (X == Parent->Left) {
312                         rbnode_t *W = Parent->Right;
313                         if (W->Color == Red) {
314                                 W->Color = Black;
315                                 Parent->Color = Red; /* Parent != NIL? */
316                                 RotateLeft(tree, Parent);
317                                 W = Parent->Right;
318                         }
319                         if (W->Left->Color == Black && W->Right->Color == Black) {
320                                 if (W != NIL) W->Color = Red;
321                                 X = Parent;
322                                 Parent = X->Parent;
323                         } else {
324                                 if (W->Right->Color == Black) {
325                                         if (W->Left != NIL) W->Left->Color = Black;
326                                         W->Color = Red;
327                                         RotateRight(tree, W);
328                                         W = Parent->Right;
329                                 }
330                                 W->Color = Parent->Color;
331                                 if (Parent != NIL) Parent->Color = Black;
332                                 if (W->Right->Color != Black) {
333                                         W->Right->Color = Black;
334                                 }
335                                 RotateLeft(tree, Parent);
336                                 X = tree->Root;
337                         }
338                 } else {
339                         rbnode_t *W = Parent->Left;
340                         if (W->Color == Red) {
341                                 W->Color = Black;
342                                 Parent->Color = Red; /* Parent != NIL? */
343                                 RotateRight(tree, Parent);
344                                 W = Parent->Left;
345                         }
346                         if (W->Right->Color == Black && W->Left->Color == Black) {
347                                 if (W != NIL) W->Color = Red;
348                                 X = Parent;
349                                 Parent = X->Parent;
350                         } else {
351                                 if (W->Left->Color == Black) {
352                                         if (W->Right != NIL) W->Right->Color = Black;
353                                         W->Color = Red;
354                                         RotateLeft(tree, W);
355                                         W = Parent->Left;
356                                 }
357                                 W->Color = Parent->Color;
358                                 if (Parent != NIL) Parent->Color = Black;
359                                 if (W->Left->Color != Black) {
360                                         W->Left->Color = Black;
361                                 }
362                                 RotateRight(tree, Parent);
363                                 X = tree->Root;
364                         }
365                 }
366         }
367         X->Color = Black;
368 }
369
370 /*
371  *      Delete an element from the tree.
372  */
373 void rbtree_delete(rbtree_t *tree, rbnode_t *Z)
374 {
375         int fixup = 0;
376         rbnode_t *X, *Y;
377         rbnode_t *Parent;
378
379         /*****************************
380          *  delete node Z from tree  *
381          *****************************/
382
383         if (!Z || Z == NIL) return;
384
385         if (Z->Left == NIL || Z->Right == NIL) {
386                 /* Y has a NIL node as a child */
387                 Y = Z;
388         } else {
389                 /* find tree successor with a NIL node as a child */
390                 Y = Z->Right;
391                 while (Y->Left != NIL) Y = Y->Left;
392         }
393
394         /* X is Y's only child */
395         if (Y->Left != NIL)
396                 X = Y->Left;
397         else
398                 X = Y->Right;   /* may be NIL! */
399
400         /* remove Y from the parent chain */
401         Parent = Y->Parent;
402         if (X != NIL) X->Parent = Parent;
403
404         if (Parent)
405                 if (Y == Parent->Left)
406                         Parent->Left = X;
407                 else
408                         Parent->Right = X;
409         else
410                 tree->Root = X;
411
412         if (Y != Z) {
413                 if (tree->freeNode) tree->freeNode(Z->Data);
414                 Z->Data = Y->Data;
415                 Y->Data = NULL;
416
417                 if (Y->Color == Black && X != NIL)
418                         DeleteFixup(tree, X, Parent);
419
420                 /*
421                  *      The user structure in Y->Data MAY include a
422                  *      pointer to Y.  In that case, we CANNOT delete
423                  *      Y.  Instead, we copy Z (which is now in the
424                  *      tree) to Y, and fix up the parent/child
425                  *      pointers.
426                  */
427                 memcpy(Y, Z, sizeof(*Y));
428
429                 if (!Y->Parent) {
430                         tree->Root = Y;
431                 } else {
432                         if (Y->Parent->Left == Z) Y->Parent->Left = Y;
433                         if (Y->Parent->Right == Z) Y->Parent->Right = Y;
434                 }
435                 if (Y->Left->Parent == Z) Y->Left->Parent = Y;
436                 if (Y->Right->Parent == Z) Y->Right->Parent = Y;
437
438                 free(Z);
439
440         } else {
441                 if (tree->freeNode) tree->freeNode(Y->Data);
442
443                 if (Y->Color == Black && X != NIL)
444                         DeleteFixup(tree, X, Parent);
445
446                 free(Y);
447         }
448
449         tree->num_elements--;
450 }
451
452 /*
453  *      Delete a node from the tree, based on given data, which MUST
454  *      have come from rbtree_finddata().
455  */
456 int rbtree_deletebydata(rbtree_t *tree, const void *data)
457 {
458         rbnode_t *node = rbtree_find(tree, data);
459
460         if (!node) return 0;    /* false */
461
462         rbtree_delete(tree, node);
463
464         return 1;
465 }
466
467
468 /*
469  *      Find an element in the tree, returning the data, not the node.
470  */
471 rbnode_t *rbtree_find(rbtree_t *tree, const void *Data)
472 {
473         /*******************************
474          *  find node containing Data  *
475          *******************************/
476
477         rbnode_t *Current = tree->Root;
478
479         while (Current != NIL) {
480                 int result = tree->Compare(Data, Current->Data);
481
482                 if (result == 0) {
483                         return Current;
484                 } else {
485                         Current = (result < 0) ?
486                                 Current->Left : Current->Right;
487                 }
488         }
489         return NULL;
490 }
491
492 /*
493  *      Find the user data.
494  */
495 void *rbtree_finddata(rbtree_t *tree, const void *Data)
496 {
497         rbnode_t *X;
498
499         X = rbtree_find(tree, Data);
500         if (!X) return NULL;
501
502         return X->Data;
503 }
504
505 /*
506  *      Walk the tree, Pre-order
507  *
508  *      We call ourselves recursively for each function, but that's OK,
509  *      as the stack is only log(N) deep, which is ~12 entries deep.
510  */
511 static int WalkNodePreOrder(rbnode_t *X,
512                             int (*callback)(void *, void *), void *context)
513 {
514         int rcode;
515
516         rcode = callback(context, X->Data);
517         if (rcode != 0) return rcode;
518
519         if (X->Left != NIL) {
520                 rcode = WalkNodePreOrder(X->Left, callback, context);
521                 if (rcode != 0) return rcode;
522         }
523
524         if (X->Right != NIL) {
525                 rcode = WalkNodePreOrder(X->Right, callback, context);
526                 if (rcode != 0) return rcode;
527         }
528
529         return 0;               /* we know everything returned zero */
530 }
531
532 /*
533  *      Inorder
534  */
535 static int WalkNodeInOrder(rbnode_t *X,
536                            int (*callback)(void *, void *), void *context)
537 {
538         int rcode;
539
540         if (X->Left != NIL) {
541                 rcode = WalkNodeInOrder(X->Left, callback, context);
542                 if (rcode != 0) return rcode;
543         }
544
545         rcode = callback(context, X->Data);
546         if (rcode != 0) return rcode;
547
548         if (X->Right != NIL) {
549                 rcode = WalkNodeInOrder(X->Right, callback, context);
550                 if (rcode != 0) return rcode;
551         }
552
553         return 0;               /* we know everything returned zero */
554 }
555
556
557 /*
558  *      PostOrder
559  */
560 static int WalkNodePostOrder(rbnode_t *X,
561                              int (*callback)(void *, void*), void *context)
562 {
563         int rcode;
564
565         if (X->Left != NIL) {
566                 rcode = WalkNodeInOrder(X->Left, callback, context);
567                 if (rcode != 0) return rcode;
568         }
569
570         if (X->Right != NIL) {
571                 rcode = WalkNodeInOrder(X->Right, callback, context);
572                 if (rcode != 0) return rcode;
573         }
574
575         rcode = callback(context, X->Data);
576         if (rcode != 0) return rcode;
577
578         return 0;               /* we know everything returned zero */
579 }
580
581 /*
582  *      Walk the entire tree.  The callback function CANNOT modify
583  *      the tree.
584  *
585  *      The callback function should return 0 to continue walking.
586  *      Any other value stops the walk, and is returned.
587  */
588 int rbtree_walk(rbtree_t *tree, RBTREE_ORDER order,
589                 int (*callback)(void *, void *), void *context)
590 {
591         switch (order) {
592         case PreOrder:
593                 return WalkNodePreOrder(tree->Root, callback, context);
594         case InOrder:
595                 return WalkNodeInOrder(tree->Root, callback, context);
596         case PostOrder:
597                 return WalkNodePostOrder(tree->Root, callback, context);
598
599         default:
600                 break;
601         }
602
603         return -1;
604 }
605
606 int rbtree_num_elements(rbtree_t *tree)
607 {
608         if (!tree) return 0;
609
610         return tree->num_elements;
611 }
612
613
614 /*
615  *      Given a Node, return the data.
616  */
617 void *rbtree_node2data(rbtree_t *tree, rbnode_t *node)
618 {
619         tree = tree;            /* -Wunused */
620
621         if (!node) return NULL;
622
623         return node->Data;
624 }
625
626 /*
627  *      Return left-most child.
628  */
629 void *rbtree_min(rbtree_t *tree)
630 {
631         rbnode_t *Current;
632
633         if (!tree || !tree->Root) return NULL;
634
635         Current = tree->Root;
636         while (Current->Left != NIL) Current = Current->Left;
637
638         return Current->Data;
639 }