]> git.sur5r.net Git - openldap/blob - libraries/liblutil/tavl.c
silence warnings
[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-2006 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         if ( !depth ) {
288                 *root = q;
289                 return data;
290         }
291
292         /* set the child into p's parent */
293         depth--;
294         p = pptr[depth];
295         side = pdir[depth];
296         p->avl_link[side] = q;
297
298         /* Update child thread */
299         if ( q ) {
300                 for ( ; q->avl_bits[nside] == AVL_CHILD && q->avl_link[nside];
301                         q = q->avl_link[nside] ) ;
302                 q->avl_link[nside] = r;
303         } else {
304                 p->avl_bits[side] = AVL_THREAD;
305                 p->avl_link[side] = r;
306         }
307
308         top = NULL;
309         shorter = 1;
310   
311         while ( shorter ) {
312                 p = pptr[depth];
313                 side = pdir[depth];
314                 nside = !side;
315                 side_bf = avl_bfs[side];
316
317                 /* case 1: height unchanged */
318                 if ( p->avl_bf == EH ) {
319                         /* Tree is now heavier on opposite side */
320                         p->avl_bf = avl_bfs[nside];
321                         shorter = 0;
322                   
323                 } else if ( p->avl_bf == side_bf ) {
324                 /* case 2: taller subtree shortened, height reduced */
325                         p->avl_bf = EH;
326                 } else {
327                 /* case 3: shorter subtree shortened */
328                         if ( depth )
329                                 top = pptr[depth-1]; /* p->parent; */
330                         else
331                                 top = NULL;
332                         /* set <q> to the taller of the two subtrees of <p> */
333                         q = p->avl_link[nside];
334                         if ( q->avl_bf == EH ) {
335                                 /* case 3a: height unchanged, single rotate */
336                                 if ( q->avl_bits[side] == AVL_THREAD ) {
337                                         q->avl_bits[side] = AVL_CHILD;
338                                         p->avl_bits[nside] = AVL_THREAD;
339                                 } else {
340                                         p->avl_link[nside] = q->avl_link[side];
341                                         q->avl_link[side] = p;
342                                 }
343                                 shorter = 0;
344                                 q->avl_bf = side_bf;
345                                 p->avl_bf = (- side_bf);
346
347                         } else if ( q->avl_bf == p->avl_bf ) {
348                                 /* case 3b: height reduced, single rotate */
349                                 if ( q->avl_bits[side] == AVL_THREAD ) {
350                                         q->avl_bits[side] = AVL_CHILD;
351                                         p->avl_bits[nside] = AVL_THREAD;
352                                 } else {
353                                         p->avl_link[nside] = q->avl_link[side];
354                                         q->avl_link[side] = p;
355                                 }
356                                 shorter = 1;
357                                 q->avl_bf = EH;
358                                 p->avl_bf = EH;
359
360                         } else {
361                                 /* case 3c: height reduced, balance factors opposite */
362                                 r = q->avl_link[side];
363                                 if ( r->avl_bits[nside] == AVL_THREAD ) {
364                                         r->avl_bits[nside] = AVL_CHILD;
365                                         q->avl_bits[side] = AVL_THREAD;
366                                 } else {
367                                         q->avl_link[side] = r->avl_link[nside];
368                                         r->avl_link[nside] = q;
369                                 }
370
371                                 if ( r->avl_bits[side] == AVL_THREAD ) {
372                                         r->avl_bits[side] = AVL_CHILD;
373                                         p->avl_bits[nside] = AVL_THREAD;
374                                         p->avl_link[nside] = r;
375                                 } else {
376                                         p->avl_link[nside] = r->avl_link[side];
377                                         r->avl_link[side] = p;
378                                 }
379
380                                 if ( r->avl_bf == side_bf ) {
381                                         q->avl_bf = (- side_bf);
382                                         p->avl_bf = EH;
383                                 } else if ( r->avl_bf == (- side_bf)) {
384                                         q->avl_bf = EH;
385                                         p->avl_bf = side_bf;
386                                 } else {
387                                         q->avl_bf = EH;
388                                         p->avl_bf = EH;
389                                 }
390                                 r->avl_bf = EH;
391                                 q = r;
392                         }
393                         /* a rotation has caused <q> (or <r> in case 3c) to become
394                          * the root.  let <p>'s former parent know this.
395                          */
396                         if ( top == NULL ) {
397                                 *root = q;
398                         } else if (top->avl_link[0] == p) {
399                                 top->avl_link[0] = q;
400                         } else {
401                                 top->avl_link[1] = q;
402                         }
403                         /* end case 3 */
404                         p = q;
405                 }
406                 if ( !depth )
407                         break;
408                 depth--;
409         } /* end while(shorter) */
410
411         return data;
412 }
413
414 /*
415  * tavl_free -- traverse avltree root, freeing the memory it is using.
416  * the dfree() is called to free the data portion of each node.  The
417  * number of items actually freed is returned.
418  */
419
420 int
421 tavl_free( Avlnode *root, AVL_FREE dfree )
422 {
423         int     nleft, nright;
424
425         if ( root == 0 )
426                 return( 0 );
427
428         nleft = tavl_free( avl_lchild( root ), dfree );
429
430         nright = tavl_free( avl_rchild( root ), dfree );
431
432         if ( dfree )
433                 (*dfree)( root->avl_data );
434         ber_memfree( root );
435
436         return( nleft + nright + 1 );
437 }
438
439 /*
440  * tavl_find -- search avltree root for a node with data data.  the function
441  * cmp is used to compare things.  it is called with data as its first arg 
442  * and the current node data as its second.  it should return 0 if they match,
443  * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
444  */
445
446 /*
447  * tavl_find2 - returns Avlnode instead of data pointer.
448  * tavl_find3 - as above, but returns Avlnode even if no match is found.
449  *                              also return the last comparison result in ret.
450  */
451 Avlnode *
452 tavl_find3( Avlnode *root, const void *data, AVL_CMP fcmp, int *ret )
453 {
454         int     cmp, dir;
455         Avlnode *prev;
456
457         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
458                 prev = root;
459                 dir = cmp > 0;
460                 root = avl_child( root, dir );
461         }
462         *ret = cmp;
463         return root ? root : prev;
464 }
465
466 Avlnode *
467 tavl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
468 {
469         int     cmp;
470
471         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
472                 cmp = cmp > 0;
473                 root = avl_child( root, cmp );
474         }
475         return root;
476 }
477
478 void*
479 tavl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
480 {
481         int     cmp;
482
483         while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
484                 cmp = cmp > 0;
485                 root = avl_child( root, cmp );
486         }
487
488         return( root ? root->avl_data : 0 );
489 }
490
491 /* Return the leftmost or rightmost node in the tree */
492 Avlnode *
493 tavl_end( Avlnode *root, int dir )
494 {
495         if ( root ) {
496                 while ( root->avl_bits[dir] == AVL_CHILD )
497                         root = root->avl_link[dir];
498         }
499         return root;
500 }
501
502 /* Return the next node in the given direction */
503 Avlnode *
504 tavl_next( Avlnode *root, int dir )
505 {
506         if ( root ) {
507                 int c = root->avl_bits[dir];
508
509                 root = root->avl_link[dir];
510                 if ( c == AVL_CHILD ) {
511                         dir ^= 1;
512                         while ( root->avl_bits[dir] == AVL_CHILD )
513                                 root = root->avl_link[dir];
514                 }
515         }
516         return root;
517 }