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