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