]> git.sur5r.net Git - openldap/blob - libraries/libavl/avl.c
Merge in all -devel changes made since branch was created.
[openldap] / libraries / libavl / avl.c
1 /* avl.c - routines to implement an avl tree */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1993 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #ifndef lint
21 static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
22 static char avl_version[] = "AVL library version 1.0\n";
23 #endif
24
25 #include <stdio.h>
26 #include <ac/stdlib.h>
27
28 #define AVL_INTERNAL
29 #include "avl.h"
30
31 #define ROTATERIGHT(x)  { \
32         Avlnode *tmp;\
33         if ( *(x) == NULL || (*(x))->avl_left == NULL ) {\
34                 (void) fputs("RR error\n", stderr); exit( EXIT_FAILURE ); \
35         }\
36         tmp = (*(x))->avl_left;\
37         (*(x))->avl_left = tmp->avl_right;\
38         tmp->avl_right = *(x);\
39         *(x) = tmp;\
40 }
41 #define ROTATELEFT(x)   { \
42         Avlnode *tmp;\
43         if ( *(x) == NULL || (*(x))->avl_right == NULL ) {\
44                 (void) fputs("RL error\n", stderr); exit( EXIT_FAILURE ); \
45         }\
46         tmp = (*(x))->avl_right;\
47         (*(x))->avl_right = tmp->avl_left;\
48         tmp->avl_left = *(x);\
49         *(x) = tmp;\
50 }
51
52 /*
53  * ravl_insert - called from avl_insert() to do a recursive insert into
54  * and balance of an avl tree.
55  */
56
57 static int
58 ravl_insert(
59     Avlnode     **iroot,
60     void*       data,
61     int         *taller,
62     AVL_CMP             fcmp,                   /* comparison function */
63     AVL_DUP             fdup,                   /* function to call for duplicates */
64     int         depth
65 )
66 {
67         int     rc, cmp, tallersub;
68         Avlnode *l, *r;
69
70         if ( *iroot == 0 ) {
71                 if ( (*iroot = (Avlnode *) malloc( sizeof( Avlnode ) ))
72                     == NULL ) {
73                         return( -1 );
74                 }
75                 (*iroot)->avl_left = 0;
76                 (*iroot)->avl_right = 0;
77                 (*iroot)->avl_bf = 0;
78                 (*iroot)->avl_data = data;
79                 *taller = 1;
80                 return( 0 );
81         }
82
83         cmp = (*fcmp)( data, (*iroot)->avl_data );
84
85         /* equal - duplicate name */
86         if ( cmp == 0 ) {
87                 *taller = 0;
88                 return( (*fdup)( (*iroot)->avl_data, data ) );
89         }
90
91         /* go right */
92         else if ( cmp > 0 ) {
93                 rc = ravl_insert( &((*iroot)->avl_right), data, &tallersub,
94                    fcmp, fdup, depth );
95                 if ( tallersub )
96                         switch ( (*iroot)->avl_bf ) {
97                         case LH : /* left high - balance is restored */
98                                 (*iroot)->avl_bf = EH;
99                                 *taller = 0;
100                                 break;
101                         case EH : /* equal height - now right heavy */
102                                 (*iroot)->avl_bf = RH;
103                                 *taller = 1;
104                                 break;
105                         case RH : /* right heavy to start - right balance */
106                                 r = (*iroot)->avl_right;
107                                 switch ( r->avl_bf ) {
108                                 case LH : /* double rotation left */
109                                         l = r->avl_left;
110                                         switch ( l->avl_bf ) {
111                                         case LH : (*iroot)->avl_bf = EH;
112                                                   r->avl_bf = RH;
113                                                   break;
114                                         case EH : (*iroot)->avl_bf = EH;
115                                                   r->avl_bf = EH;
116                                                   break;
117                                         case RH : (*iroot)->avl_bf = LH;
118                                                   r->avl_bf = EH;
119                                                   break;
120                                         }
121                                         l->avl_bf = EH;
122                                         ROTATERIGHT( (&r) )
123                                         (*iroot)->avl_right = r;
124                                         ROTATELEFT( iroot )
125                                         *taller = 0;
126                                         break;
127                                 case EH : /* This should never happen */
128                                         break;
129                                 case RH : /* single rotation left */
130                                         (*iroot)->avl_bf = EH;
131                                         r->avl_bf = EH;
132                                         ROTATELEFT( iroot )
133                                         *taller = 0;
134                                         break;
135                                 }
136                                 break;
137                         }
138                 else
139                         *taller = 0;
140         }
141
142         /* go left */
143         else {
144                 rc = ravl_insert( &((*iroot)->avl_left), data, &tallersub,
145                    fcmp, fdup, depth );
146                 if ( tallersub )
147                         switch ( (*iroot)->avl_bf ) {
148                         case LH : /* left high to start - left balance */
149                                 l = (*iroot)->avl_left;
150                                 switch ( l->avl_bf ) {
151                                 case LH : /* single rotation right */
152                                         (*iroot)->avl_bf = EH;
153                                         l->avl_bf = EH;
154                                         ROTATERIGHT( iroot )
155                                         *taller = 0;
156                                         break;
157                                 case EH : /* this should never happen */
158                                         break;
159                                 case RH : /* double rotation right */
160                                         r = l->avl_right;
161                                         switch ( r->avl_bf ) {
162                                         case LH : (*iroot)->avl_bf = RH;
163                                                   l->avl_bf = EH;
164                                                   break;
165                                         case EH : (*iroot)->avl_bf = EH;
166                                                   l->avl_bf = EH;
167                                                   break;
168                                         case RH : (*iroot)->avl_bf = EH;
169                                                   l->avl_bf = LH;
170                                                   break;
171                                         }
172                                         r->avl_bf = EH;
173                                         ROTATELEFT( (&l) )
174                                         (*iroot)->avl_left = l;
175                                         ROTATERIGHT( iroot )
176                                         *taller = 0;
177                                         break;
178                                 }
179                                 break;
180                         case EH : /* equal height - now left heavy */
181                                 (*iroot)->avl_bf = LH;
182                                 *taller = 1;
183                                 break;
184                         case RH : /* right high - balance is restored */
185                                 (*iroot)->avl_bf = EH;
186                                 *taller = 0;
187                                 break;
188                         }
189                 else
190                         *taller = 0;
191         }
192
193         return( rc );
194 }
195
196 /*
197  * avl_insert -- insert a node containing data data into the avl tree
198  * with root root.  fcmp is a function to call to compare the data portion
199  * of two nodes.  it should take two arguments and return <, >, or == 0,
200  * depending on whether its first argument is <, >, or == its second
201  * argument (like strcmp, e.g.).  fdup is a function to call when a duplicate
202  * node is inserted.  it should return 0, or -1 and its return value
203  * will be the return value from avl_insert in the case of a duplicate node.
204  * the function will be called with the original node's data as its first
205  * argument and with the incoming duplicate node's data as its second
206  * argument.  this could be used, for example, to keep a count with each
207  * node.
208  *
209  * NOTE: this routine may malloc memory
210  */
211
212 int
213 avl_insert( Avlnode **root, void* data, AVL_CMP fcmp, AVL_DUP fdup )
214 {
215         int     taller;
216
217         return( ravl_insert( root, data, &taller, fcmp, fdup, 0 ) );
218 }
219
220 /* 
221  * right_balance() - called from delete when root's right subtree has
222  * been shortened because of a deletion.
223  */
224
225 static int
226 right_balance( Avlnode **root )
227 {
228         int     shorter = -1;
229         Avlnode *r, *l;
230
231         switch( (*root)->avl_bf ) {
232         case RH:        /* was right high - equal now */
233                 (*root)->avl_bf = EH;
234                 shorter = 1;
235                 break;
236         case EH:        /* was equal - left high now */
237                 (*root)->avl_bf = LH;
238                 shorter = 0;
239                 break;
240         case LH:        /* was right high - balance */
241                 l = (*root)->avl_left;
242                 switch ( l->avl_bf ) {
243                 case RH : /* double rotation left */
244                         r = l->avl_right;
245                         switch ( r->avl_bf ) {
246                         case RH :
247                                 (*root)->avl_bf = EH;
248                                 l->avl_bf = LH;
249                                 break;
250                         case EH :
251                                 (*root)->avl_bf = EH;
252                                 l->avl_bf = EH;
253                                 break;
254                         case LH :
255                                 (*root)->avl_bf = RH;
256                                 l->avl_bf = EH;
257                                 break;
258                         }
259                         r->avl_bf = EH;
260                         ROTATELEFT( (&l) )
261                         (*root)->avl_left = l;
262                         ROTATERIGHT( root )
263                         shorter = 1;
264                         break;
265                 case EH : /* right rotation */
266                         (*root)->avl_bf = LH;
267                         l->avl_bf = RH;
268                         ROTATERIGHT( root );
269                         shorter = 0;
270                         break;
271                 case LH : /* single rotation right */
272                         (*root)->avl_bf = EH;
273                         l->avl_bf = EH;
274                         ROTATERIGHT( root )
275                         shorter = 1;
276                         break;
277                 }
278                 break;
279         }
280
281         return( shorter );
282 }
283
284 /* 
285  * left_balance() - called from delete when root's left subtree has
286  * been shortened because of a deletion.
287  */
288
289 static int
290 left_balance( Avlnode **root )
291 {
292         int     shorter = -1;
293         Avlnode *r, *l;
294
295         switch( (*root)->avl_bf ) {
296         case LH:        /* was left high - equal now */
297                 (*root)->avl_bf = EH;
298                 shorter = 1;
299                 break;
300         case EH:        /* was equal - right high now */
301                 (*root)->avl_bf = RH;
302                 shorter = 0;
303                 break;
304         case RH:        /* was right high - balance */
305                 r = (*root)->avl_right;
306                 switch ( r->avl_bf ) {
307                 case LH : /* double rotation left */
308                         l = r->avl_left;
309                         switch ( l->avl_bf ) {
310                         case LH :
311                                 (*root)->avl_bf = EH;
312                                 r->avl_bf = RH;
313                                 break;
314                         case EH :
315                                 (*root)->avl_bf = EH;
316                                 r->avl_bf = EH;
317                                 break;
318                         case RH :
319                                 (*root)->avl_bf = LH;
320                                 r->avl_bf = EH;
321                                 break;
322                         }
323                         l->avl_bf = EH;
324                         ROTATERIGHT( (&r) )
325                         (*root)->avl_right = r;
326                         ROTATELEFT( root )
327                         shorter = 1;
328                         break;
329                 case EH : /* single rotation left */
330                         (*root)->avl_bf = RH;
331                         r->avl_bf = LH;
332                         ROTATELEFT( root );
333                         shorter = 0;
334                         break;
335                 case RH : /* single rotation left */
336                         (*root)->avl_bf = EH;
337                         r->avl_bf = EH;
338                         ROTATELEFT( root )
339                         shorter = 1;
340                         break;
341                 }
342                 break;
343         }
344
345         return( shorter );
346 }
347
348 /*
349  * ravl_delete() - called from avl_delete to do recursive deletion of a
350  * node from an avl tree.  It finds the node recursively, deletes it,
351  * and returns shorter if the tree is shorter after the deletion and
352  * rebalancing.
353  */
354
355 static void*
356 ravl_delete( Avlnode **root, void* data, AVL_CMP fcmp, int *shorter )
357 {
358         int     shortersubtree = 0;
359         int     cmp;
360         void*   savedata;
361         Avlnode *minnode, *savenode;
362
363         if ( *root == NULLAVL )
364                 return( 0 );
365
366         cmp = (*fcmp)( data, (*root)->avl_data );
367
368         /* found it! */
369         if ( cmp == 0 ) {
370                 savenode = *root;
371                 savedata = savenode->avl_data;
372
373                 /* simple cases: no left child */
374                 if ( (*root)->avl_left == 0 ) {
375                         *root = (*root)->avl_right;
376                         *shorter = 1;
377                         free( (char *) savenode );
378                         return( savedata );
379                 /* no right child */
380                 } else if ( (*root)->avl_right == 0 ) {
381                         *root = (*root)->avl_left;
382                         *shorter = 1;
383                         free( (char *) savenode );
384                         return( savedata );
385                 }
386
387                 /* 
388                  * avl_getmin will return to us the smallest node greater
389                  * than the one we are trying to delete.  deleting this node
390                  * from the right subtree is guaranteed to end in one of the
391                  * simple cases above.
392                  */
393
394                 minnode = (*root)->avl_right;
395                 while ( minnode->avl_left != NULLAVL )
396                         minnode = minnode->avl_left;
397
398                 /* swap the data */
399                 (*root)->avl_data = minnode->avl_data;
400                 minnode->avl_data = savedata;
401
402                 savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
403                     &shortersubtree );
404
405                 if ( shortersubtree )
406                         *shorter = right_balance( root );
407                 else
408                         *shorter = 0;
409         /* go left */
410         } else if ( cmp < 0 ) {
411                 if ( (savedata = ravl_delete( &(*root)->avl_left, data, fcmp,
412                     &shortersubtree )) == 0 ) {
413                         *shorter = 0;
414                         return( 0 );
415                 }
416
417                 /* left subtree shorter? */
418                 if ( shortersubtree )
419                         *shorter = left_balance( root );
420                 else
421                         *shorter = 0;
422         /* go right */
423         } else {
424                 if ( (savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
425                     &shortersubtree )) == 0 ) {
426                         *shorter = 0;
427                         return( 0 );
428                 }
429
430                 if ( shortersubtree ) 
431                         *shorter = right_balance( root );
432                 else
433                         *shorter = 0;
434         }
435
436         return( savedata );
437 }
438
439 /*
440  * avl_delete() - deletes the node containing data (according to fcmp) from
441  * the avl tree rooted at root.
442  */
443
444 void*
445 avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
446 {
447         int     shorter;
448
449         return( ravl_delete( root, data, fcmp, &shorter ) );
450 }
451
452 static int
453 avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
454 {
455         if ( root == 0 )
456                 return( AVL_NOMORE );
457
458         if ( root->avl_left != 0 )
459                 if ( avl_inapply( root->avl_left, fn, arg, stopflag ) 
460                     == stopflag )
461                         return( stopflag );
462
463         if ( (*fn)( root->avl_data, arg ) == stopflag )
464                 return( stopflag );
465
466         if ( root->avl_right == 0 )
467                 return( AVL_NOMORE );
468         else
469                 return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
470 }
471
472 static int
473 avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
474 {
475         if ( root == 0 )
476                 return( AVL_NOMORE );
477
478         if ( root->avl_left != 0 )
479                 if ( avl_postapply( root->avl_left, fn, arg, stopflag ) 
480                     == stopflag )
481                         return( stopflag );
482
483         if ( root->avl_right != 0 )
484                 if ( avl_postapply( root->avl_right, fn, arg, stopflag ) 
485                     == stopflag )
486                         return( stopflag );
487
488         return( (*fn)( root->avl_data, arg ) );
489 }
490
491 static int
492 avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
493 {
494         if ( root == 0 )
495                 return( AVL_NOMORE );
496
497         if ( (*fn)( root->avl_data, arg ) == stopflag )
498                 return( stopflag );
499
500         if ( root->avl_left != 0 )
501                 if ( avl_preapply( root->avl_left, fn, arg, stopflag ) 
502                     == stopflag )
503                         return( stopflag );
504
505         if ( root->avl_right == 0 )
506                 return( AVL_NOMORE );
507         else
508                 return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
509 }
510
511 /*
512  * avl_apply -- avl tree root is traversed, function fn is called with
513  * arguments arg and the data portion of each node.  if fn returns stopflag,
514  * the traversal is cut short, otherwise it continues.  Do not use -6 as
515  * a stopflag, as this is what is used to indicate the traversal ran out
516  * of nodes.
517  */
518
519 int
520 avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
521 {
522         switch ( type ) {
523         case AVL_INORDER:
524                 return( avl_inapply( root, fn, arg, stopflag ) );
525         case AVL_PREORDER:
526                 return( avl_preapply( root, fn, arg, stopflag ) );
527         case AVL_POSTORDER:
528                 return( avl_postapply( root, fn, arg, stopflag ) );
529         default:
530                 fprintf( stderr, "Invalid traversal type %d\n", type );
531                 return( -1 );
532         }
533
534         /* NOTREACHED */
535 }
536
537 /*
538  * avl_prefixapply - traverse avl tree root, applying function fprefix
539  * to any nodes that match.  fcmp is called with data as its first arg
540  * and the current node's data as its second arg.  it should return
541  * 0 if they match, < 0 if data is less, and > 0 if data is greater.
542  * the idea is to efficiently find all nodes that are prefixes of
543  * some key...  Like avl_apply, this routine also takes a stopflag
544  * and will return prematurely if fmatch returns this value.  Otherwise,
545  * AVL_NOMORE is returned.
546  */
547
548 int
549 avl_prefixapply(
550     Avlnode     *root,
551     void*       data,
552     AVL_CMP             fmatch,
553     void*       marg,
554     AVL_CMP             fcmp,
555     void*       carg,
556     int         stopflag
557 )
558 {
559         int     cmp;
560
561         if ( root == 0 )
562                 return( AVL_NOMORE );
563
564         cmp = (*fcmp)( data, root->avl_data /* , carg */);
565         if ( cmp == 0 ) {
566                 if ( (*fmatch)( root->avl_data, marg ) == stopflag )
567                         return( stopflag );
568
569                 if ( root->avl_left != 0 )
570                         if ( avl_prefixapply( root->avl_left, data, fmatch,
571                             marg, fcmp, carg, stopflag ) == stopflag )
572                                 return( stopflag );
573
574                 if ( root->avl_right != 0 )
575                         return( avl_prefixapply( root->avl_right, data, fmatch,
576                             marg, fcmp, carg, stopflag ) );
577                 else
578                         return( AVL_NOMORE );
579
580         } else if ( cmp < 0 ) {
581                 if ( root->avl_left != 0 )
582                         return( avl_prefixapply( root->avl_left, data, fmatch,
583                             marg, fcmp, carg, stopflag ) );
584         } else {
585                 if ( root->avl_right != 0 )
586                         return( avl_prefixapply( root->avl_right, data, fmatch,
587                             marg, fcmp, carg, stopflag ) );
588         }
589
590         return( AVL_NOMORE );
591 }
592
593 /*
594  * avl_free -- traverse avltree root, freeing the memory it is using.
595  * the dfree() is called to free the data portion of each node.  The
596  * number of items actually freed is returned.
597  */
598
599 int
600 avl_free( Avlnode *root, AVL_FREE dfree )
601 {
602         int     nleft, nright;
603
604         if ( root == 0 )
605                 return( 0 );
606
607         nleft = nright = 0;
608         if ( root->avl_left != 0 )
609                 nleft = avl_free( root->avl_left, dfree );
610
611         if ( root->avl_right != 0 )
612                 nright = avl_free( root->avl_right, dfree );
613
614         if ( dfree )
615                 (*dfree)( root->avl_data );
616         free( root );
617
618         return( nleft + nright + 1 );
619 }
620
621 /*
622  * avl_find -- search avltree root for a node with data data.  the function
623  * cmp is used to compare things.  it is called with data as its first arg 
624  * and the current node data as its second.  it should return 0 if they match,
625  * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
626  */
627
628 void*
629 avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
630 {
631         int     cmp;
632
633         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
634                 if ( cmp < 0 )
635                         root = root->avl_left;
636                 else
637                         root = root->avl_right;
638         }
639
640         return( root ? root->avl_data : 0 );
641 }
642
643 /*
644  * avl_find_lin -- search avltree root linearly for a node with data data. 
645  * the function cmp is used to compare things.  it is called with data as its
646  * first arg and the current node data as its second.  it should return 0 if
647  * they match, non-zero otherwise.
648  */
649
650 void*
651 avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
652 {
653         void*   res;
654
655         if ( root == 0 )
656                 return( NULL );
657
658         if ( (*fcmp)( data, root->avl_data ) == 0 )
659                 return( root->avl_data );
660
661         if ( root->avl_left != 0 )
662                 if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
663                     != NULL )
664                         return( res );
665
666         if ( root->avl_right == 0 )
667                 return( NULL );
668         else
669                 return( avl_find_lin( root->avl_right, data, fcmp ) );
670 }
671
672 /* NON-REENTRANT INTERFACE */
673
674 static void*    *avl_list;
675 static int      avl_maxlist;
676 static int      avl_nextlist;
677
678 #define AVL_GRABSIZE    100
679
680 /* ARGSUSED */
681 static int
682 avl_buildlist( void* data, void* arg )
683 {
684         static int      slots;
685
686         if ( avl_list == (void* *) 0 ) {
687                 avl_list = (void* *) malloc(AVL_GRABSIZE * sizeof(void*));
688                 slots = AVL_GRABSIZE;
689                 avl_maxlist = 0;
690         } else if ( avl_maxlist == slots ) {
691                 slots += AVL_GRABSIZE;
692                 avl_list = (void* *) realloc( (char *) avl_list,
693                     (unsigned) slots * sizeof(void*));
694         }
695
696         avl_list[ avl_maxlist++ ] = data;
697
698         return( 0 );
699 }
700
701 /*
702  * avl_getfirst() and avl_getnext() are provided as alternate tree
703  * traversal methods, to be used when a single function cannot be
704  * provided to be called with every node in the tree.  avl_getfirst()
705  * traverses the tree and builds a linear list of all the nodes,
706  * returning the first node.  avl_getnext() returns the next thing
707  * on the list built by avl_getfirst().  This means that avl_getfirst()
708  * can take a while, and that the tree should not be messed with while
709  * being traversed in this way, and that multiple traversals (even of
710  * different trees) cannot be active at once.
711  */
712
713 void*
714 avl_getfirst( Avlnode *root )
715 {
716         if ( avl_list ) {
717                 free( (char *) avl_list);
718                 avl_list = (void* *) 0;
719         }
720         avl_maxlist = 0;
721         avl_nextlist = 0;
722
723         if ( root == 0 )
724                 return( 0 );
725
726         (void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
727
728         return( avl_list[ avl_nextlist++ ] );
729 }
730
731 void*
732 avl_getnext( void )
733 {
734         if ( avl_list == 0 )
735                 return( 0 );
736
737         if ( avl_nextlist == avl_maxlist ) {
738                 free( (void*) avl_list);
739                 avl_list = (void* *) 0;
740                 return( 0 );
741         }
742
743         return( avl_list[ avl_nextlist++ ] );
744 }
745
746 /* end non-reentrant code */
747
748
749 int
750 avl_dup_error( void* left, void* right )
751 {
752         return( -1 );
753 }
754
755 int
756 avl_dup_ok( void* left, void* right )
757 {
758         return( 0 );
759 }