wineps: Clip visible rectangle to bitmap size in get_vis_rectangles.
[wine.git] / libs / ldap / libldap / avl.c
blobfd22c7f0de6529c82a12de773c31c3987fa18dab
1 /* avl.c - routines to implement an avl tree */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2022 The OpenLDAP Foundation.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
16 /* Portions Copyright (c) 1993 Regents of the University of Michigan.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms are permitted
20 * provided that this notice is preserved and that due credit is given
21 * to the University of Michigan at Ann Arbor. The name of the University
22 * may not be used to endorse or promote products derived from this
23 * software without specific prior written permission. This software
24 * is provided ``as is'' without express or implied warranty.
26 /* ACKNOWLEDGEMENTS:
27 * This work was originally developed by the University of Michigan
28 * (as part of U-MICH LDAP). Additional significant contributors
29 * include:
30 * Howard Y. Chu
31 * Hallvard B. Furuseth
32 * Kurt D. Zeilenga
35 #include "portable.h"
37 #include <limits.h>
38 #include <stdio.h>
39 #include <ac/stdlib.h>
41 #ifdef CSRIMALLOC
42 #define ber_memalloc malloc
43 #define ber_memrealloc realloc
44 #define ber_memfree free
45 #else
46 #include "lber.h"
47 #endif
49 #define AVL_INTERNAL
50 #include "ldap_avl.h"
52 /* Maximum tree depth this host's address space could support */
53 #define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
55 static const int avl_bfs[] = {LH, RH};
58 * ldap_avl_insert -- insert a node containing data data into the avl tree
59 * with root root. fcmp is a function to call to compare the data portion
60 * of two nodes. it should take two arguments and return <, >, or == 0,
61 * depending on whether its first argument is <, >, or == its second
62 * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
63 * node is inserted. it should return 0, or -1 and its return value
64 * will be the return value from ldap_avl_insert in the case of a duplicate node.
65 * the function will be called with the original node's data as its first
66 * argument and with the incoming duplicate node's data as its second
67 * argument. this could be used, for example, to keep a count with each
68 * node.
70 * NOTE: this routine may malloc memory
72 int
73 ldap_avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
75 Avlnode *t, *p, *s, *q, *r;
76 int a, cmp, ncmp;
78 if ( *root == NULL ) {
79 if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
80 return( -1 );
82 r->avl_link[0] = r->avl_link[1] = NULL;
83 r->avl_data = data;
84 r->avl_bits[0] = r->avl_bits[1] = AVL_CHILD;
85 r->avl_bf = EH;
86 *root = r;
88 return( 0 );
91 t = NULL;
92 s = p = *root;
94 /* find insertion point */
95 while (1) {
96 cmp = fcmp( data, p->avl_data );
97 if ( cmp == 0 )
98 return (*fdup)( p->avl_data, data );
100 cmp = (cmp > 0);
101 q = p->avl_link[cmp];
102 if (q == NULL) {
103 /* insert */
104 if (( q = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
105 return( -1 );
107 q->avl_link[0] = q->avl_link[1] = NULL;
108 q->avl_data = data;
109 q->avl_bits[0] = q->avl_bits[1] = AVL_CHILD;
110 q->avl_bf = EH;
112 p->avl_link[cmp] = q;
113 break;
114 } else if ( q->avl_bf ) {
115 t = p;
116 s = q;
118 p = q;
121 /* adjust balance factors */
122 cmp = fcmp( data, s->avl_data ) > 0;
123 r = p = s->avl_link[cmp];
124 a = avl_bfs[cmp];
126 while ( p != q ) {
127 cmp = fcmp( data, p->avl_data ) > 0;
128 p->avl_bf = avl_bfs[cmp];
129 p = p->avl_link[cmp];
132 /* checks and balances */
134 if ( s->avl_bf == EH ) {
135 s->avl_bf = a;
136 return 0;
137 } else if ( s->avl_bf == -a ) {
138 s->avl_bf = EH;
139 return 0;
140 } else if ( s->avl_bf == a ) {
141 cmp = (a > 0);
142 ncmp = !cmp;
143 if ( r->avl_bf == a ) {
144 /* single rotation */
145 p = r;
146 s->avl_link[cmp] = r->avl_link[ncmp];
147 r->avl_link[ncmp] = s;
148 s->avl_bf = 0;
149 r->avl_bf = 0;
150 } else if ( r->avl_bf == -a ) {
151 /* double rotation */
152 p = r->avl_link[ncmp];
153 r->avl_link[ncmp] = p->avl_link[cmp];
154 p->avl_link[cmp] = r;
155 s->avl_link[cmp] = p->avl_link[ncmp];
156 p->avl_link[ncmp] = s;
158 if ( p->avl_bf == a ) {
159 s->avl_bf = -a;
160 r->avl_bf = 0;
161 } else if ( p->avl_bf == -a ) {
162 s->avl_bf = 0;
163 r->avl_bf = a;
164 } else {
165 s->avl_bf = 0;
166 r->avl_bf = 0;
168 p->avl_bf = 0;
170 /* Update parent */
171 if ( t == NULL )
172 *root = p;
173 else if ( s == t->avl_right )
174 t->avl_right = p;
175 else
176 t->avl_left = p;
179 return 0;
182 void*
183 ldap_avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
185 Avlnode *p, *q, *r, *top;
186 int side, side_bf, shorter, nside;
188 /* parent stack */
189 Avlnode *pptr[MAX_TREE_DEPTH];
190 unsigned char pdir[MAX_TREE_DEPTH];
191 int depth = 0;
193 if ( *root == NULL )
194 return NULL;
196 p = *root;
198 while (1) {
199 side = fcmp( data, p->avl_data );
200 if ( !side )
201 break;
202 side = ( side > 0 );
203 pdir[depth] = side;
204 pptr[depth++] = p;
206 p = p->avl_link[side];
207 if ( p == NULL )
208 return p;
210 data = p->avl_data;
212 /* If this node has two children, swap so we are deleting a node with
213 * at most one child.
215 if ( p->avl_link[0] && p->avl_link[1] ) {
217 /* find the immediate predecessor <q> */
218 q = p->avl_link[0];
219 side = depth;
220 pdir[depth++] = 0;
221 while (q->avl_link[1]) {
222 pdir[depth] = 1;
223 pptr[depth++] = q;
224 q = q->avl_link[1];
226 /* swap links */
227 r = p->avl_link[0];
228 p->avl_link[0] = q->avl_link[0];
229 q->avl_link[0] = r;
231 q->avl_link[1] = p->avl_link[1];
232 p->avl_link[1] = NULL;
234 q->avl_bf = p->avl_bf;
236 /* fix stack positions: old parent of p points to q */
237 pptr[side] = q;
238 if ( side ) {
239 r = pptr[side-1];
240 r->avl_link[pdir[side-1]] = q;
241 } else {
242 *root = q;
244 /* new parent of p points to p */
245 if ( depth-side > 1 ) {
246 r = pptr[depth-1];
247 r->avl_link[1] = p;
248 } else {
249 q->avl_link[0] = p;
253 /* now <p> has at most one child, get it */
254 q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
256 ber_memfree( p );
258 if ( !depth ) {
259 *root = q;
260 return data;
263 /* set the child into p's parent */
264 depth--;
265 p = pptr[depth];
266 side = pdir[depth];
267 p->avl_link[side] = q;
269 top = NULL;
270 shorter = 1;
272 while ( shorter ) {
273 p = pptr[depth];
274 side = pdir[depth];
275 nside = !side;
276 side_bf = avl_bfs[side];
278 /* case 1: height unchanged */
279 if ( p->avl_bf == EH ) {
280 /* Tree is now heavier on opposite side */
281 p->avl_bf = avl_bfs[nside];
282 shorter = 0;
284 } else if ( p->avl_bf == side_bf ) {
285 /* case 2: taller subtree shortened, height reduced */
286 p->avl_bf = EH;
287 } else {
288 /* case 3: shorter subtree shortened */
289 if ( depth )
290 top = pptr[depth-1]; /* p->parent; */
291 else
292 top = NULL;
293 /* set <q> to the taller of the two subtrees of <p> */
294 q = p->avl_link[nside];
295 if ( q->avl_bf == EH ) {
296 /* case 3a: height unchanged, single rotate */
297 p->avl_link[nside] = q->avl_link[side];
298 q->avl_link[side] = p;
299 shorter = 0;
300 q->avl_bf = side_bf;
301 p->avl_bf = (- side_bf);
303 } else if ( q->avl_bf == p->avl_bf ) {
304 /* case 3b: height reduced, single rotate */
305 p->avl_link[nside] = q->avl_link[side];
306 q->avl_link[side] = p;
307 shorter = 1;
308 q->avl_bf = EH;
309 p->avl_bf = EH;
311 } else {
312 /* case 3c: height reduced, balance factors opposite */
313 r = q->avl_link[side];
314 q->avl_link[side] = r->avl_link[nside];
315 r->avl_link[nside] = q;
317 p->avl_link[nside] = r->avl_link[side];
318 r->avl_link[side] = p;
320 if ( r->avl_bf == side_bf ) {
321 q->avl_bf = (- side_bf);
322 p->avl_bf = EH;
323 } else if ( r->avl_bf == (- side_bf)) {
324 q->avl_bf = EH;
325 p->avl_bf = side_bf;
326 } else {
327 q->avl_bf = EH;
328 p->avl_bf = EH;
330 r->avl_bf = EH;
331 q = r;
333 /* a rotation has caused <q> (or <r> in case 3c) to become
334 * the root. let <p>'s former parent know this.
336 if ( top == NULL ) {
337 *root = q;
338 } else if (top->avl_link[0] == p) {
339 top->avl_link[0] = q;
340 } else {
341 top->avl_link[1] = q;
343 /* end case 3 */
344 p = q;
346 if ( !depth )
347 break;
348 depth--;
349 } /* end while(shorter) */
351 return data;
354 static int
355 avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
357 if ( root == 0 )
358 return( AVL_NOMORE );
360 if ( root->avl_left != 0 )
361 if ( avl_inapply( root->avl_left, fn, arg, stopflag )
362 == stopflag )
363 return( stopflag );
365 if ( (*fn)( root->avl_data, arg ) == stopflag )
366 return( stopflag );
368 if ( root->avl_right == 0 )
369 return( AVL_NOMORE );
370 else
371 return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
374 static int
375 avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
377 if ( root == 0 )
378 return( AVL_NOMORE );
380 if ( root->avl_left != 0 )
381 if ( avl_postapply( root->avl_left, fn, arg, stopflag )
382 == stopflag )
383 return( stopflag );
385 if ( root->avl_right != 0 )
386 if ( avl_postapply( root->avl_right, fn, arg, stopflag )
387 == stopflag )
388 return( stopflag );
390 return( (*fn)( root->avl_data, arg ) );
393 static int
394 avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
396 if ( root == 0 )
397 return( AVL_NOMORE );
399 if ( (*fn)( root->avl_data, arg ) == stopflag )
400 return( stopflag );
402 if ( root->avl_left != 0 )
403 if ( avl_preapply( root->avl_left, fn, arg, stopflag )
404 == stopflag )
405 return( stopflag );
407 if ( root->avl_right == 0 )
408 return( AVL_NOMORE );
409 else
410 return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
414 * ldap_avl_apply -- avl tree root is traversed, function fn is called with
415 * arguments arg and the data portion of each node. if fn returns stopflag,
416 * the traversal is cut short, otherwise it continues. Do not use -6 as
417 * a stopflag, as this is what is used to indicate the traversal ran out
418 * of nodes.
422 ldap_avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
424 switch ( type ) {
425 case AVL_INORDER:
426 return( avl_inapply( root, fn, arg, stopflag ) );
427 case AVL_PREORDER:
428 return( avl_preapply( root, fn, arg, stopflag ) );
429 case AVL_POSTORDER:
430 return( avl_postapply( root, fn, arg, stopflag ) );
431 default:
432 fprintf( stderr, "Invalid traversal type %d\n", type );
433 return( -1 );
436 /* NOTREACHED */
440 * ldap_avl_prefixapply - traverse avl tree root, applying function fprefix
441 * to any nodes that match. fcmp is called with data as its first arg
442 * and the current node's data as its second arg. it should return
443 * 0 if they match, < 0 if data is less, and > 0 if data is greater.
444 * the idea is to efficiently find all nodes that are prefixes of
445 * some key... Like ldap_avl_apply, this routine also takes a stopflag
446 * and will return prematurely if fmatch returns this value. Otherwise,
447 * AVL_NOMORE is returned.
451 ldap_avl_prefixapply(
452 Avlnode *root,
453 void* data,
454 AVL_CMP fmatch,
455 void* marg,
456 AVL_CMP fcmp,
457 void* carg,
458 int stopflag
461 int cmp;
463 if ( root == 0 )
464 return( AVL_NOMORE );
466 cmp = (*fcmp)( data, root->avl_data /* , carg */);
467 if ( cmp == 0 ) {
468 if ( (*fmatch)( root->avl_data, marg ) == stopflag )
469 return( stopflag );
471 if ( root->avl_left != 0 )
472 if ( ldap_avl_prefixapply( root->avl_left, data, fmatch,
473 marg, fcmp, carg, stopflag ) == stopflag )
474 return( stopflag );
476 if ( root->avl_right != 0 )
477 return( ldap_avl_prefixapply( root->avl_right, data, fmatch,
478 marg, fcmp, carg, stopflag ) );
479 else
480 return( AVL_NOMORE );
482 } else if ( cmp < 0 ) {
483 if ( root->avl_left != 0 )
484 return( ldap_avl_prefixapply( root->avl_left, data, fmatch,
485 marg, fcmp, carg, stopflag ) );
486 } else {
487 if ( root->avl_right != 0 )
488 return( ldap_avl_prefixapply( root->avl_right, data, fmatch,
489 marg, fcmp, carg, stopflag ) );
492 return( AVL_NOMORE );
496 * ldap_avl_free -- traverse avltree root, freeing the memory it is using.
497 * the dfree() is called to free the data portion of each node. The
498 * number of items actually freed is returned.
502 ldap_avl_free( Avlnode *root, AVL_FREE dfree )
504 int nleft, nright;
506 if ( root == 0 )
507 return( 0 );
509 nleft = nright = 0;
510 if ( root->avl_left != 0 )
511 nleft = ldap_avl_free( root->avl_left, dfree );
513 if ( root->avl_right != 0 )
514 nright = ldap_avl_free( root->avl_right, dfree );
516 if ( dfree )
517 (*dfree)( root->avl_data );
518 ber_memfree( root );
520 return( nleft + nright + 1 );
524 * ldap_avl_find -- search avltree root for a node with data data. the function
525 * cmp is used to compare things. it is called with data as its first arg
526 * and the current node data as its second. it should return 0 if they match,
527 * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
530 Avlnode *
531 ldap_avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
533 int cmp;
535 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
536 cmp = cmp > 0;
537 root = root->avl_link[cmp];
539 return root;
542 void*
543 ldap_avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
545 int cmp;
547 while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
548 cmp = cmp > 0;
549 root = root->avl_link[cmp];
552 return( root ? root->avl_data : 0 );
556 * ldap_avl_find_lin -- search avltree root linearly for a node with data data.
557 * the function cmp is used to compare things. it is called with data as its
558 * first arg and the current node data as its second. it should return 0 if
559 * they match, non-zero otherwise.
562 void*
563 ldap_avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
565 void* res;
567 if ( root == 0 )
568 return( NULL );
570 if ( (*fcmp)( data, root->avl_data ) == 0 )
571 return( root->avl_data );
573 if ( root->avl_left != 0 )
574 if ( (res = ldap_avl_find_lin( root->avl_left, data, fcmp ))
575 != NULL )
576 return( res );
578 if ( root->avl_right == 0 )
579 return( NULL );
580 else
581 return( ldap_avl_find_lin( root->avl_right, data, fcmp ) );
584 /* NON-REENTRANT INTERFACE */
586 static void* *avl_list;
587 static int avl_maxlist;
588 static int ldap_avl_nextlist;
590 #define AVL_GRABSIZE 100
592 /* ARGSUSED */
593 static int
594 avl_buildlist( void* data, void* arg )
596 static int slots;
598 if ( avl_list == (void* *) 0 ) {
599 avl_list = (void* *) ber_memalloc(AVL_GRABSIZE * sizeof(void*));
600 slots = AVL_GRABSIZE;
601 avl_maxlist = 0;
602 } else if ( avl_maxlist == slots ) {
603 slots += AVL_GRABSIZE;
604 avl_list = (void* *) ber_memrealloc( (char *) avl_list,
605 (unsigned) slots * sizeof(void*));
608 avl_list[ avl_maxlist++ ] = data;
610 return( 0 );
614 * ldap_avl_getfirst() and ldap_avl_getnext() are provided as alternate tree
615 * traversal methods, to be used when a single function cannot be
616 * provided to be called with every node in the tree. ldap_avl_getfirst()
617 * traverses the tree and builds a linear list of all the nodes,
618 * returning the first node. ldap_avl_getnext() returns the next thing
619 * on the list built by ldap_avl_getfirst(). This means that ldap_avl_getfirst()
620 * can take a while, and that the tree should not be messed with while
621 * being traversed in this way, and that multiple traversals (even of
622 * different trees) cannot be active at once.
625 void*
626 ldap_avl_getfirst( Avlnode *root )
628 if ( avl_list ) {
629 ber_memfree( (char *) avl_list);
630 avl_list = (void* *) 0;
632 avl_maxlist = 0;
633 ldap_avl_nextlist = 0;
635 if ( root == 0 )
636 return( 0 );
638 (void) ldap_avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
640 return( avl_list[ ldap_avl_nextlist++ ] );
643 void*
644 ldap_avl_getnext( void )
646 if ( avl_list == 0 )
647 return( 0 );
649 if ( ldap_avl_nextlist == avl_maxlist ) {
650 ber_memfree( (void*) avl_list);
651 avl_list = (void* *) 0;
652 return( 0 );
655 return( avl_list[ ldap_avl_nextlist++ ] );
658 /* end non-reentrant code */
662 ldap_avl_dup_error( void* left, void* right )
664 return( -1 );
668 ldap_avl_dup_ok( void* left, void* right )
670 return( 0 );