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