]> git.sur5r.net Git - openldap/blob - libraries/liblutil/tavl.c
fix test when slapo-memberof(5) built as module (ITS#5132)
[openldap] / libraries / liblutil / tavl.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 2005-2007 The OpenLDAP Foundation.
6  * Portions Copyright (c) 2005 by Howard Chu, Symas Corp.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Howard Chu for inclusion
19  * in OpenLDAP software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/stdlib.h>
26
27 #ifdef CSRIMALLOC
28 #define ber_memalloc malloc
29 #define ber_memrealloc realloc
30 #define ber_memfree free
31 #else
32 #include "lber.h"
33 #endif
34
35 #define AVL_INTERNAL
36 #include "avl.h"
37
38 static const int avl_bfs[] = {LH, RH};
39
40 /*
41  * Threaded AVL trees - for fast in-order traversal of nodes.
42  */
43 /*
44  * tavl_insert -- insert a node containing data data into the avl tree
45  * with root root.  fcmp is a function to call to compare the data portion
46  * of two nodes.  it should take two arguments and return <, >, or == 0,
47  * depending on whether its first argument is <, >, or == its second
48  * argument (like strcmp, e.g.).  fdup is a function to call when a duplicate
49  * node is inserted.  it should return 0, or -1 and its return value
50  * will be the return value from avl_insert in the case of a duplicate node.
51  * the function will be called with the original node's data as its first
52  * argument and with the incoming duplicate node's data as its second
53  * argument.  this could be used, for example, to keep a count with each
54  * node.
55  *
56  * NOTE: this routine may malloc memory
57  */
58 int
59 tavl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
60 {
61     Avlnode *t, *p, *s, *q, *r;
62     int a, cmp, ncmp;
63
64         if ( *root == NULL ) {
65                 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
66                         return( -1 );
67                 }
68                 r->avl_link[0] = r->avl_link[1] = NULL;
69                 r->avl_data = data;
70                 r->avl_bf = EH;
71                 r->avl_bits[0] = r->avl_bits[1] = AVL_THREAD;
72                 *root = r;
73
74                 return( 0 );
75         }
76
77     t = NULL;
78     s = p = *root;
79
80         /* find insertion point */
81     while (1) {
82                 cmp = fcmp( data, p->avl_data );
83                 if ( cmp == 0 )
84                         return (*fdup)( p->avl_data, data );
85
86                 cmp = (cmp > 0);
87                 q = avl_child( p, cmp );
88                 if (q == NULL) {
89                         /* insert */
90                         if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
91                                 return( -1 );
92                         }
93                         q->avl_link[cmp] = p->avl_link[cmp];
94                         q->avl_link[!cmp] = p;
95                         q->avl_data = data;
96                         q->avl_bf = EH;
97                         q->avl_bits[0] = q->avl_bits[1] = AVL_THREAD;
98
99                         p->avl_link[cmp] = q;
100                         p->avl_bits[cmp] = AVL_CHILD;
101                         break;
102                 } else if ( q->avl_bf ) {
103                         t = p;
104                         s = q;
105                 }
106                 p = q;
107     }
108
109     /* adjust balance factors */
110     cmp = fcmp( data, s->avl_data ) > 0;
111         r = p = s->avl_link[cmp];
112         a = avl_bfs[cmp];
113
114         while ( p != q ) {
115                 cmp = fcmp( data, p->avl_data ) > 0;
116                 p->avl_bf = avl_bfs[cmp];
117                 p = p->avl_link[cmp];
118         }
119
120         /* checks and balances */
121
122         if ( s->avl_bf == EH ) {
123                 s->avl_bf = a;
124                 return 0;
125         } else if ( s->avl_bf == -a ) {
126                 s->avl_bf = EH;
127                 return 0;
128     } else if ( s->avl_bf == a ) {
129                 cmp = (a > 0);
130                 ncmp = !cmp;
131                 if ( r->avl_bf == a ) {
132                         /* single rotation */
133                         p = r;
134                         if ( r->avl_bits[ncmp] == AVL_THREAD ) {
135                                 r->avl_bits[ncmp] = AVL_CHILD;
136                                 s->avl_bits[cmp] = AVL_THREAD;
137                         } else {
138                                 s->avl_link[cmp] = r->avl_link[ncmp];
139                                 r->avl_link[ncmp] = s;
140                         }
141                         s->avl_bf = 0;
142                         r->avl_bf = 0;
143                 } else if ( r->avl_bf == -a ) {
144                         /* double rotation */
145                         p = r->avl_link[ncmp];
146                         if ( p->avl_bits[cmp] == AVL_THREAD ) {
147                                 p->avl_bits[cmp] = AVL_CHILD;
148                                 r->avl_bits[ncmp] = AVL_THREAD;
149                         } else {
150                                 r->avl_link[ncmp] = p->avl_link[cmp];
151                                 p->avl_link[cmp] = r;
152                         }
153                         if ( p->avl_bits[ncmp] == AVL_THREAD ) {
154                                 p->avl_bits[ncmp] = AVL_CHILD;
155                                 s->avl_link[cmp] = p;
156                                 s->avl_bits[cmp] = AVL_THREAD;
157                         } else {
158                                 s->avl_link[cmp] = p->avl_link[ncmp];
159                                 p->avl_link[ncmp] = s;
160                         }
161                         if ( p->avl_bf == a ) {
162                                 s->avl_bf = -a;
163                                 r->avl_bf = 0;
164                         } else if ( p->avl_bf == -a ) {
165                                 s->avl_bf = 0;
166                                 r->avl_bf = a;
167                         } else {
168                                 s->avl_bf = 0;
169                                 r->avl_bf = 0;
170                         }
171                         p->avl_bf = 0;
172                 }
173                 /* Update parent */
174                 if ( t == NULL )
175                         *root = p;
176                 else if ( s == t->avl_right )
177                         t->avl_right = p;
178                 else
179                         t->avl_left = p;
180     }
181
182   return 0;
183 }
184
185 void*
186 tavl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
187 {
188         Avlnode *p, *q, *r, *top;
189         int side, side_bf, shorter, nside = -1;
190
191         /* parent stack */
192         Avlnode *pptr[sizeof(void *)*8];
193         unsigned char pdir[sizeof(void *)*8];
194         int depth = 0;
195
196         if ( *root == NULL )
197                 return NULL;
198
199         p = *root;
200
201         while (1) {
202                 side = fcmp( data, p->avl_data );
203                 if ( !side )
204                         break;
205                 side = ( side > 0 );
206                 pdir[depth] = side;
207                 pptr[depth++] = p;
208
209                 if ( p->avl_bits[side] == AVL_THREAD )
210                         return NULL;
211                 p = p->avl_link[side];
212         }
213         data = p->avl_data;
214
215         /* If this node has two children, swap so we are deleting a node with
216          * at most one child.
217          */
218         if ( p->avl_bits[0] == AVL_CHILD && p->avl_bits[1] == AVL_CHILD &&
219                 p->avl_link[0] && p->avl_link[1] ) {
220
221                 /* find the immediate predecessor <q> */
222                 q = p->avl_link[0];
223                 side = depth;
224                 pdir[depth++] = 0;
225                 while (q->avl_bits[1] == AVL_CHILD && q->avl_link[1]) {
226                         pdir[depth] = 1;
227                         pptr[depth++] = q;
228                         q = q->avl_link[1];
229                 }
230                 /* swap links */
231                 r = p->avl_link[0];
232                 p->avl_link[0] = q->avl_link[0];
233                 q->avl_link[0] = r;
234
235                 q->avl_link[1] = p->avl_link[1];
236                 p->avl_link[1] = q;
237
238                 p->avl_bits[0] = q->avl_bits[0];
239                 p->avl_bits[1] = q->avl_bits[1];
240                 q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD;
241
242                 q->avl_bf = p->avl_bf;
243
244                 /* fix stack positions: old parent of p points to q */
245                 pptr[side] = q;
246                 if ( side ) {
247                         r = pptr[side-1];
248                         r->avl_link[pdir[side-1]] = q;
249                 } else {
250                         *root = q;
251                 }
252                 /* new parent of p points to p */
253                 if ( depth-side > 1 ) {
254                         r = pptr[depth-1];
255                         r->avl_link[1] = p;
256                 } else {
257                         q->avl_link[0] = p;
258                 }
259
260                 /* fix right subtree: successor of p points to q */
261                 r = q->avl_link[1];
262                 while ( r->avl_bits[0] == AVL_CHILD && r->avl_link[0] )
263                         r = r->avl_link[0];
264                 r->avl_link[0] = q;
265         }
266
267         /* now <p> has at most one child, get it */
268         if ( p->avl_link[0] && p->avl_bits[0] == AVL_CHILD ) {
269                 q = p->avl_link[0];
270                 /* Preserve thread continuity */
271                 r = p->avl_link[1];
272                 nside = 1;
273         } else if ( p->avl_link[1] && p->avl_bits[1] == AVL_CHILD ) {
274                 q = p->avl_link[1];
275                 r = p->avl_link[0];
276                 nside = 0;
277         } else {
278                 q = NULL;
279                 if ( depth > 0 )
280                         r = p->avl_link[pdir[depth-1]];
281                 else
282                         r = NULL;
283         }
284
285         ber_memfree( p );
286
287         /* Update child thread */
288         if ( q ) {
289                 for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
290                         q = q->avl_link[nside] ) ;
291                 q->avl_link[nside] = r;
292         }
293         
294         if ( !depth ) {
295                 *root = q;
296                 return data;
297         }
298
299         /* set the child into p's parent */
300         depth--;
301         p = pptr[depth];
302         side = pdir[depth];
303         p->avl_link[side] = q;
304
305         if ( !q ) {
306                 p->avl_bits[side] = AVL_THREAD;
307                 p->avl_link[side] = r;
308         }
309
310         top = NULL;
311         shorter = 1;
312   
313         while ( shorter ) {
314                 p = pptr[depth];
315                 side = pdir[depth];
316                 nside = !side;
317                 side_bf = avl_bfs[side];
318
319                 /* case 1: height unchanged */
320                 if ( p->avl_bf == EH ) {
321                         /* Tree is now heavier on opposite side */
322                         p->avl_bf = avl_bfs[nside];
323                         shorter = 0;
324                   
325                 } else if ( p->avl_bf == side_bf ) {
326                 /* case 2: taller subtree shortened, height reduced */
327                         p->avl_bf = EH;
328                 } else {
329                 /* case 3: shorter subtree shortened */
330                         if ( depth )
331                                 top = pptr[depth-1]; /* p->parent; */
332                         else
333                                 top = NULL;
334                         /* set <q> to the taller of the two subtrees of <p> */
335                         q = p->avl_link[nside];
336                         if ( q->avl_bf == EH ) {
337                                 /* case 3a: height unchanged, single rotate */
338                                 if ( q->avl_bits[side] == AVL_THREAD ) {
339                                         q->avl_bits[side] = AVL_CHILD;
340                                         p->avl_bits[nside] = AVL_THREAD;
341                                 } else {
342                                         p->avl_link[nside] = q->avl_link[side];
343                                         q->avl_link[side] = p;
344                                 }
345                                 shorter = 0;
346                                 q->avl_bf = side_bf;
347                                 p->avl_bf = (- side_bf);
348
349                         } else if ( q->avl_bf == p->avl_bf ) {
350                                 /* case 3b: height reduced, single rotate */
351                                 if ( q->avl_bits[side] == AVL_THREAD ) {
352                                         q->avl_bits[side] = AVL_CHILD;
353                                         p->avl_bits[nside] = AVL_THREAD;
354                                 } else {
355                                         p->avl_link[nside] = q->avl_link[side];
356                                         q->avl_link[side] = p;
357                                 }
358                                 shorter = 1;
359                                 q->avl_bf = EH;
360                                 p->avl_bf = EH;
361
362                         } else {
363                                 /* case 3c: height reduced, balance factors opposite */
364                                 r = q->avl_link[side];
365                                 if ( r->avl_bits[nside] == AVL_THREAD ) {
366                                         r->avl_bits[nside] = AVL_CHILD;
367                                         q->avl_bits[side] = AVL_THREAD;
368                                 } else {
369                                         q->avl_link[side] = r->avl_link[nside];
370                                         r->avl_link[nside] = q;
371                                 }
372
373                                 if ( r->avl_bits[side] == AVL_THREAD ) {
374                                         r->avl_bits[side] = AVL_CHILD;
375                                         p->avl_bits[nside] = AVL_THREAD;
376                                         p->avl_link[nside] = r;
377                                 } else {
378                                         p->avl_link[nside] = r->avl_link[side];
379                                         r->avl_link[side] = p;
380                                 }
381
382                                 if ( r->avl_bf == side_bf ) {
383                                         q->avl_bf = (- side_bf);
384                                         p->avl_bf = EH;
385                                 } else if ( r->avl_bf == (- side_bf)) {
386                                         q->avl_bf = EH;
387                                         p->avl_bf = side_bf;
388                                 } else {
389                                         q->avl_bf = EH;
390                                         p->avl_bf = EH;
391                                 }
392                                 r->avl_bf = EH;
393                                 q = r;
394                         }
395                         /* a rotation has caused <q> (or <r> in case 3c) to become
396                          * the root.  let <p>'s former parent know this.
397                          */
398                         if ( top == NULL ) {
399                                 *root = q;
400                         } else if (top->avl_link[0] == p) {
401                                 top->avl_link[0] = q;
402                         } else {
403                                 top->avl_link[1] = q;
404                         }
405                         /* end case 3 */
406                         p = q;
407                 }
408                 if ( !depth )
409                         break;
410                 depth--;
411         } /* end while(shorter) */
412
413         return data;
414 }
415
416 /*
417  * tavl_free -- traverse avltree root, freeing the memory it is using.
418  * the dfree() is called to free the data portion of each node.  The
419  * number of items actually freed is returned.
420  */
421
422 int
423 tavl_free( Avlnode *root, AVL_FREE dfree )
424 {
425         int     nleft, nright;
426
427         if ( root == 0 )
428                 return( 0 );
429
430         nleft = tavl_free( avl_lchild( root ), dfree );
431
432         nright = tavl_free( avl_rchild( root ), dfree );
433
434         if ( dfree )
435                 (*dfree)( root->avl_data );
436         ber_memfree( root );
437
438         return( nleft + nright + 1 );
439 }
440
441 /*
442  * tavl_find -- search avltree root for a node with data data.  the function
443  * cmp is used to compare things.  it is called with data as its first arg 
444  * and the current node data as its second.  it should return 0 if they match,
445  * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
446  */
447
448 /*
449  * tavl_find2 - returns Avlnode instead of data pointer.
450  * tavl_find3 - as above, but returns Avlnode even if no match is found.
451  *                              also return the last comparison result in ret.
452  */
453 Avlnode *
454 tavl_find3( Avlnode *root, const void *data, AVL_CMP fcmp, int *ret )
455 {
456         int     cmp, dir;
457         Avlnode *prev;
458
459         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
460                 prev = root;
461                 dir = cmp > 0;
462                 root = avl_child( root, dir );
463         }
464         *ret = cmp;
465         return root ? root : prev;
466 }
467
468 Avlnode *
469 tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
470 {
471         int     cmp;
472
473         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
474                 cmp = cmp > 0;
475                 root = avl_child( root, cmp );
476         }
477         return root;
478 }
479
480 void*
481 tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
482 {
483         int     cmp;
484
485         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
486                 cmp = cmp > 0;
487                 root = avl_child( root, cmp );
488         }
489
490         return( root ? root->avl_data : 0 );
491 }
492
493 /* Return the leftmost or rightmost node in the tree */
494 Avlnode *
495 tavl_end( Avlnode *root, int dir )
496 {
497         if ( root ) {
498                 while ( root->avl_bits[dir] == AVL_CHILD )
499                         root = root->avl_link[dir];
500         }
501         return root;
502 }
503
504 /* Return the next node in the given direction */
505 Avlnode *
506 tavl_next( Avlnode *root, int dir )
507 {
508         if ( root ) {
509                 int c = root->avl_bits[dir];
510
511                 root = root->avl_link[dir];
512                 if ( c == AVL_CHILD ) {
513                         dir ^= 1;
514                         while ( root->avl_bits[dir] == AVL_CHILD )
515                                 root = root->avl_link[dir];
516                 }
517         }
518         return root;
519 }