]> git.sur5r.net Git - openldap/blob - libraries/liblutil/avl.c
ITS#5615 return success on Solaris 10
[openldap] / libraries / liblutil / avl.c
1 /* avl.c - routines to implement an avl tree */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1993 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26 /* ACKNOWLEDGEMENTS:
27  * This work was originally developed by the University of Michigan
28  * (as part of U-MICH LDAP).  Additional significant contributors
29  * include:
30  *   Howard Y. Chu
31  *   Hallvard B. Furuseth
32  *   Kurt D. Zeilenga
33  */
34
35 #include "portable.h"
36
37 #include <stdio.h>
38 #include <ac/stdlib.h>
39
40 #ifdef CSRIMALLOC
41 #define ber_memalloc malloc
42 #define ber_memrealloc realloc
43 #define ber_memfree free
44 #else
45 #include "lber.h"
46 #endif
47
48 #define AVL_INTERNAL
49 #include "avl.h"
50
51 static const int avl_bfs[] = {LH, RH};
52
53 /*
54  * avl_insert -- insert a node containing data data into the avl tree
55  * with root root.  fcmp is a function to call to compare the data portion
56  * of two nodes.  it should take two arguments and return <, >, or == 0,
57  * depending on whether its first argument is <, >, or == its second
58  * argument (like strcmp, e.g.).  fdup is a function to call when a duplicate
59  * node is inserted.  it should return 0, or -1 and its return value
60  * will be the return value from avl_insert in the case of a duplicate node.
61  * the function will be called with the original node's data as its first
62  * argument and with the incoming duplicate node's data as its second
63  * argument.  this could be used, for example, to keep a count with each
64  * node.
65  *
66  * NOTE: this routine may malloc memory
67  */
68 int
69 avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
70 {
71     Avlnode *t, *p, *s, *q, *r;
72     int a, cmp, ncmp;
73
74         if ( *root == NULL ) {
75                 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
76                         return( -1 );
77                 }
78                 r->avl_link[0] = r->avl_link[1] = NULL;
79                 r->avl_data = data;
80                 r->avl_bf = EH;
81                 *root = r;
82
83                 return( 0 );
84         }
85
86     t = NULL;
87     s = p = *root;
88
89         /* find insertion point */
90     while (1) {
91                 cmp = fcmp( data, p->avl_data );
92                 if ( cmp == 0 )
93                         return (*fdup)( p->avl_data, data );
94
95                 cmp = (cmp > 0);
96                 q = p->avl_link[cmp];
97                 if (q == NULL) {
98                         /* insert */
99                         if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
100                                 return( -1 );
101                         }
102                         q->avl_link[0] = q->avl_link[1] = NULL;
103                         q->avl_data = data;
104                         q->avl_bf = EH;
105
106                         p->avl_link[cmp] = q;
107                         break;
108                 } else if ( q->avl_bf ) {
109                         t = p;
110                         s = q;
111                 }
112                 p = q;
113     }
114
115     /* adjust balance factors */
116     cmp = fcmp( data, s->avl_data ) > 0;
117         r = p = s->avl_link[cmp];
118         a = avl_bfs[cmp];
119
120         while ( p != q ) {
121                 cmp = fcmp( data, p->avl_data ) > 0;
122                 p->avl_bf = avl_bfs[cmp];
123                 p = p->avl_link[cmp];
124         }
125
126         /* checks and balances */
127
128         if ( s->avl_bf == EH ) {
129                 s->avl_bf = a;
130                 return 0;
131         } else if ( s->avl_bf == -a ) {
132                 s->avl_bf = EH;
133                 return 0;
134     } else if ( s->avl_bf == a ) {
135                 cmp = (a > 0);
136                 ncmp = !cmp;
137                 if ( r->avl_bf == a ) {
138                         /* single rotation */
139                         p = r;
140                         s->avl_link[cmp] = r->avl_link[ncmp];
141                         r->avl_link[ncmp] = s;
142                         s->avl_bf = 0;
143                         r->avl_bf = 0;
144                 } else if ( r->avl_bf == -a ) {
145                         /* double rotation */
146                         p = r->avl_link[ncmp];
147                         r->avl_link[ncmp] = p->avl_link[cmp];
148                         p->avl_link[cmp] = r;
149                         s->avl_link[cmp] = p->avl_link[ncmp];
150                         p->avl_link[ncmp] = s;
151
152                         if ( p->avl_bf == a ) {
153                                 s->avl_bf = -a;
154                                 r->avl_bf = 0;
155                         } else if ( p->avl_bf == -a ) {
156                                 s->avl_bf = 0;
157                                 r->avl_bf = a;
158                         } else {
159                                 s->avl_bf = 0;
160                                 r->avl_bf = 0;
161                         }
162                         p->avl_bf = 0;
163                 }
164                 /* Update parent */
165                 if ( t == NULL )
166                         *root = p;
167                 else if ( s == t->avl_right )
168                         t->avl_right = p;
169                 else
170                         t->avl_left = p;
171     }
172
173   return 0;
174 }
175
176 void*
177 avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
178 {
179         Avlnode *p, *q, *r, *top;
180         int side, side_bf, shorter, nside;
181
182         /* parent stack */
183         Avlnode *pptr[sizeof(void *)*8];
184         unsigned char pdir[sizeof(void *)*8];
185         int depth = 0;
186
187         if ( *root == NULL )
188                 return NULL;
189
190         p = *root;
191
192         while (1) {
193                 side = fcmp( data, p->avl_data );
194                 if ( !side )
195                         break;
196                 side = ( side > 0 );
197                 pdir[depth] = side;
198                 pptr[depth++] = p;
199
200                 p = p->avl_link[side];
201                 if ( p == NULL )
202                         return p;
203         }
204         data = p->avl_data;
205
206         /* If this node has two children, swap so we are deleting a node with
207          * at most one child.
208          */
209         if ( p->avl_link[0] && p->avl_link[1] ) {
210
211                 /* find the immediate predecessor <q> */
212                 q = p->avl_link[0];
213                 side = depth;
214                 pdir[depth++] = 0;
215                 while (q->avl_link[1]) {
216                         pdir[depth] = 1;
217                         pptr[depth++] = q;
218                         q = q->avl_link[1];
219                 }
220                 /* swap links */
221                 r = p->avl_link[0];
222                 p->avl_link[0] = q->avl_link[0];
223                 q->avl_link[0] = r;
224
225                 q->avl_link[1] = p->avl_link[1];
226                 p->avl_link[1] = NULL;
227
228                 q->avl_bf = p->avl_bf;
229
230                 /* fix stack positions: old parent of p points to q */
231                 pptr[side] = q;
232                 if ( side ) {
233                         r = pptr[side-1];
234                         r->avl_link[pdir[side-1]] = q;
235                 } else {
236                         *root = q;
237                 }
238                 /* new parent of p points to p */
239                 if ( depth-side > 1 ) {
240                         r = pptr[depth-1];
241                         r->avl_link[1] = p;
242                 } else {
243                         q->avl_link[0] = p;
244                 }
245         }
246
247         /* now <p> has at most one child, get it */
248         q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
249
250         ber_memfree( p );
251
252         if ( !depth ) {
253                 *root = q;
254                 return data;
255         }
256
257         /* set the child into p's parent */
258         depth--;
259         p = pptr[depth];
260         side = pdir[depth];
261         p->avl_link[side] = q;
262
263         top = NULL;
264         shorter = 1;
265   
266         while ( shorter ) {
267                 p = pptr[depth];
268                 side = pdir[depth];
269                 nside = !side;
270                 side_bf = avl_bfs[side];
271
272                 /* case 1: height unchanged */
273                 if ( p->avl_bf == EH ) {
274                         /* Tree is now heavier on opposite side */
275                         p->avl_bf = avl_bfs[nside];
276                         shorter = 0;
277                   
278                 } else if ( p->avl_bf == side_bf ) {
279                 /* case 2: taller subtree shortened, height reduced */
280                         p->avl_bf = EH;
281                 } else {
282                 /* case 3: shorter subtree shortened */
283                         if ( depth )
284                                 top = pptr[depth-1]; /* p->parent; */
285                         else
286                                 top = NULL;
287                         /* set <q> to the taller of the two subtrees of <p> */
288                         q = p->avl_link[nside];
289                         if ( q->avl_bf == EH ) {
290                                 /* case 3a: height unchanged, single rotate */
291                                 p->avl_link[nside] = q->avl_link[side];
292                                 q->avl_link[side] = p;
293                                 shorter = 0;
294                                 q->avl_bf = side_bf;
295                                 p->avl_bf = (- side_bf);
296
297                         } else if ( q->avl_bf == p->avl_bf ) {
298                                 /* case 3b: height reduced, single rotate */
299                                 p->avl_link[nside] = q->avl_link[side];
300                                 q->avl_link[side] = p;
301                                 shorter = 1;
302                                 q->avl_bf = EH;
303                                 p->avl_bf = EH;
304
305                         } else {
306                                 /* case 3c: height reduced, balance factors opposite */
307                                 r = q->avl_link[side];
308                                 q->avl_link[side] = r->avl_link[nside];
309                                 r->avl_link[nside] = q;
310
311                                 p->avl_link[nside] = r->avl_link[side];
312                                 r->avl_link[side] = p;
313
314                                 if ( r->avl_bf == side_bf ) {
315                                         q->avl_bf = (- side_bf);
316                                         p->avl_bf = EH;
317                                 } else if ( r->avl_bf == (- side_bf)) {
318                                         q->avl_bf = EH;
319                                         p->avl_bf = side_bf;
320                                 } else {
321                                         q->avl_bf = EH;
322                                         p->avl_bf = EH;
323                                 }
324                                 r->avl_bf = EH;
325                                 q = r;
326                         }
327                         /* a rotation has caused <q> (or <r> in case 3c) to become
328                          * the root.  let <p>'s former parent know this.
329                          */
330                         if ( top == NULL ) {
331                                 *root = q;
332                         } else if (top->avl_link[0] == p) {
333                                 top->avl_link[0] = q;
334                         } else {
335                                 top->avl_link[1] = q;
336                         }
337                         /* end case 3 */
338                         p = q;
339                 }
340                 if ( !depth )
341                         break;
342                 depth--;
343         } /* end while(shorter) */
344
345         return data;
346 }
347
348 static int
349 avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
350 {
351         if ( root == 0 )
352                 return( AVL_NOMORE );
353
354         if ( root->avl_left != 0 )
355                 if ( avl_inapply( root->avl_left, fn, arg, stopflag ) 
356                     == stopflag )
357                         return( stopflag );
358
359         if ( (*fn)( root->avl_data, arg ) == stopflag )
360                 return( stopflag );
361
362         if ( root->avl_right == 0 )
363                 return( AVL_NOMORE );
364         else
365                 return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
366 }
367
368 static int
369 avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
370 {
371         if ( root == 0 )
372                 return( AVL_NOMORE );
373
374         if ( root->avl_left != 0 )
375                 if ( avl_postapply( root->avl_left, fn, arg, stopflag ) 
376                     == stopflag )
377                         return( stopflag );
378
379         if ( root->avl_right != 0 )
380                 if ( avl_postapply( root->avl_right, fn, arg, stopflag ) 
381                     == stopflag )
382                         return( stopflag );
383
384         return( (*fn)( root->avl_data, arg ) );
385 }
386
387 static int
388 avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
389 {
390         if ( root == 0 )
391                 return( AVL_NOMORE );
392
393         if ( (*fn)( root->avl_data, arg ) == stopflag )
394                 return( stopflag );
395
396         if ( root->avl_left != 0 )
397                 if ( avl_preapply( root->avl_left, fn, arg, stopflag ) 
398                     == stopflag )
399                         return( stopflag );
400
401         if ( root->avl_right == 0 )
402                 return( AVL_NOMORE );
403         else
404                 return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
405 }
406
407 /*
408  * avl_apply -- avl tree root is traversed, function fn is called with
409  * arguments arg and the data portion of each node.  if fn returns stopflag,
410  * the traversal is cut short, otherwise it continues.  Do not use -6 as
411  * a stopflag, as this is what is used to indicate the traversal ran out
412  * of nodes.
413  */
414
415 int
416 avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
417 {
418         switch ( type ) {
419         case AVL_INORDER:
420                 return( avl_inapply( root, fn, arg, stopflag ) );
421         case AVL_PREORDER:
422                 return( avl_preapply( root, fn, arg, stopflag ) );
423         case AVL_POSTORDER:
424                 return( avl_postapply( root, fn, arg, stopflag ) );
425         default:
426                 fprintf( stderr, "Invalid traversal type %d\n", type );
427                 return( -1 );
428         }
429
430         /* NOTREACHED */
431 }
432
433 /*
434  * avl_prefixapply - traverse avl tree root, applying function fprefix
435  * to any nodes that match.  fcmp is called with data as its first arg
436  * and the current node's data as its second arg.  it should return
437  * 0 if they match, < 0 if data is less, and > 0 if data is greater.
438  * the idea is to efficiently find all nodes that are prefixes of
439  * some key...  Like avl_apply, this routine also takes a stopflag
440  * and will return prematurely if fmatch returns this value.  Otherwise,
441  * AVL_NOMORE is returned.
442  */
443
444 int
445 avl_prefixapply(
446     Avlnode     *root,
447     void*       data,
448     AVL_CMP             fmatch,
449     void*       marg,
450     AVL_CMP             fcmp,
451     void*       carg,
452     int         stopflag
453 )
454 {
455         int     cmp;
456
457         if ( root == 0 )
458                 return( AVL_NOMORE );
459
460         cmp = (*fcmp)( data, root->avl_data /* , carg */);
461         if ( cmp == 0 ) {
462                 if ( (*fmatch)( root->avl_data, marg ) == stopflag )
463                         return( stopflag );
464
465                 if ( root->avl_left != 0 )
466                         if ( avl_prefixapply( root->avl_left, data, fmatch,
467                             marg, fcmp, carg, stopflag ) == stopflag )
468                                 return( stopflag );
469
470                 if ( root->avl_right != 0 )
471                         return( avl_prefixapply( root->avl_right, data, fmatch,
472                             marg, fcmp, carg, stopflag ) );
473                 else
474                         return( AVL_NOMORE );
475
476         } else if ( cmp < 0 ) {
477                 if ( root->avl_left != 0 )
478                         return( avl_prefixapply( root->avl_left, data, fmatch,
479                             marg, fcmp, carg, stopflag ) );
480         } else {
481                 if ( root->avl_right != 0 )
482                         return( avl_prefixapply( root->avl_right, data, fmatch,
483                             marg, fcmp, carg, stopflag ) );
484         }
485
486         return( AVL_NOMORE );
487 }
488
489 /*
490  * avl_free -- traverse avltree root, freeing the memory it is using.
491  * the dfree() is called to free the data portion of each node.  The
492  * number of items actually freed is returned.
493  */
494
495 int
496 avl_free( Avlnode *root, AVL_FREE dfree )
497 {
498         int     nleft, nright;
499
500         if ( root == 0 )
501                 return( 0 );
502
503         nleft = nright = 0;
504         if ( root->avl_left != 0 )
505                 nleft = avl_free( root->avl_left, dfree );
506
507         if ( root->avl_right != 0 )
508                 nright = avl_free( root->avl_right, dfree );
509
510         if ( dfree )
511                 (*dfree)( root->avl_data );
512         ber_memfree( root );
513
514         return( nleft + nright + 1 );
515 }
516
517 /*
518  * avl_find -- search avltree root for a node with data data.  the function
519  * cmp is used to compare things.  it is called with data as its first arg 
520  * and the current node data as its second.  it should return 0 if they match,
521  * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
522  */
523
524 Avlnode *
525 avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
526 {
527         int     cmp;
528
529         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
530                 cmp = cmp > 0;
531                 root = root->avl_link[cmp];
532         }
533         return root;
534 }
535
536 void*
537 avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
538 {
539         int     cmp;
540
541         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
542                 cmp = cmp > 0;
543                 root = root->avl_link[cmp];
544         }
545
546         return( root ? root->avl_data : 0 );
547 }
548
549 /*
550  * avl_find_lin -- search avltree root linearly for a node with data data. 
551  * the function cmp is used to compare things.  it is called with data as its
552  * first arg and the current node data as its second.  it should return 0 if
553  * they match, non-zero otherwise.
554  */
555
556 void*
557 avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
558 {
559         void*   res;
560
561         if ( root == 0 )
562                 return( NULL );
563
564         if ( (*fcmp)( data, root->avl_data ) == 0 )
565                 return( root->avl_data );
566
567         if ( root->avl_left != 0 )
568                 if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
569                     != NULL )
570                         return( res );
571
572         if ( root->avl_right == 0 )
573                 return( NULL );
574         else
575                 return( avl_find_lin( root->avl_right, data, fcmp ) );
576 }
577
578 /* NON-REENTRANT INTERFACE */
579
580 static void*    *avl_list;
581 static int      avl_maxlist;
582 static int      avl_nextlist;
583
584 #define AVL_GRABSIZE    100
585
586 /* ARGSUSED */
587 static int
588 avl_buildlist( void* data, void* arg )
589 {
590         static int      slots;
591
592         if ( avl_list == (void* *) 0 ) {
593                 avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
594                 slots = AVL_GRABSIZE;
595                 avl_maxlist = 0;
596         } else if ( avl_maxlist == slots ) {
597                 slots += AVL_GRABSIZE;
598                 avl_list = (void* *) ber_memrealloc( (char *) avl_list,
599                     (unsigned) slots * sizeof(void*));
600         }
601
602         avl_list[ avl_maxlist++ ] = data;
603
604         return( 0 );
605 }
606
607 /*
608  * avl_getfirst() and avl_getnext() are provided as alternate tree
609  * traversal methods, to be used when a single function cannot be
610  * provided to be called with every node in the tree.  avl_getfirst()
611  * traverses the tree and builds a linear list of all the nodes,
612  * returning the first node.  avl_getnext() returns the next thing
613  * on the list built by avl_getfirst().  This means that avl_getfirst()
614  * can take a while, and that the tree should not be messed with while
615  * being traversed in this way, and that multiple traversals (even of
616  * different trees) cannot be active at once.
617  */
618
619 void*
620 avl_getfirst( Avlnode *root )
621 {
622         if ( avl_list ) {
623                 ber_memfree( (char *) avl_list);
624                 avl_list = (void* *) 0;
625         }
626         avl_maxlist = 0;
627         avl_nextlist = 0;
628
629         if ( root == 0 )
630                 return( 0 );
631
632         (void) avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
633
634         return( avl_list[ avl_nextlist++ ] );
635 }
636
637 void*
638 avl_getnext( void )
639 {
640         if ( avl_list == 0 )
641                 return( 0 );
642
643         if ( avl_nextlist == avl_maxlist ) {
644                 ber_memfree( (void*) avl_list);
645                 avl_list = (void* *) 0;
646                 return( 0 );
647         }
648
649         return( avl_list[ avl_nextlist++ ] );
650 }
651
652 /* end non-reentrant code */
653
654
655 int
656 avl_dup_error( void* left, void* right )
657 {
658         return( -1 );
659 }
660
661 int
662 avl_dup_ok( void* left, void* right )
663 {
664         return( 0 );
665 }