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