Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/ldap/libldap/avl.c
4394 views
1
/* avl.c - routines to implement an avl tree */
2
/* $OpenLDAP$ */
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
*
5
* Copyright 1998-2024 The OpenLDAP Foundation.
6
* All rights reserved.
7
*
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.
11
*
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>.
15
*/
16
/* Portions Copyright (c) 1993 Regents of the University of Michigan.
17
* All rights reserved.
18
*
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.
25
*/
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
33
*/
34
35
#include "portable.h"
36
37
#include <limits.h>
38
#include <stdio.h>
39
#include <ac/stdlib.h>
40
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
48
49
#define AVL_INTERNAL
50
#include "ldap_avl.h"
51
52
/* Maximum tree depth this host's address space could support */
53
#define MAX_TREE_DEPTH (sizeof(void *) * CHAR_BIT)
54
55
static const int avl_bfs[] = {LH, RH};
56
57
/*
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.
69
*
70
* NOTE: this routine may malloc memory
71
*/
72
int
73
ldap_avl_insert( Avlnode ** root, void *data, AVL_CMP fcmp, AVL_DUP fdup )
74
{
75
Avlnode *t, *p, *s, *q, *r;
76
int a, cmp, ncmp;
77
78
if ( *root == NULL ) {
79
if (( r = (Avlnode *) ber_memalloc( sizeof( Avlnode ))) == NULL ) {
80
return( -1 );
81
}
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;
87
88
return( 0 );
89
}
90
91
t = NULL;
92
s = p = *root;
93
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 );
99
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 );
106
}
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;
111
112
p->avl_link[cmp] = q;
113
break;
114
} else if ( q->avl_bf ) {
115
t = p;
116
s = q;
117
}
118
p = q;
119
}
120
121
/* adjust balance factors */
122
cmp = fcmp( data, s->avl_data ) > 0;
123
r = p = s->avl_link[cmp];
124
a = avl_bfs[cmp];
125
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];
130
}
131
132
/* checks and balances */
133
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;
157
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;
167
}
168
p->avl_bf = 0;
169
}
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;
177
}
178
179
return 0;
180
}
181
182
void*
183
ldap_avl_delete( Avlnode **root, void* data, AVL_CMP fcmp )
184
{
185
Avlnode *p, *q, *r, *top;
186
int side, side_bf, shorter, nside;
187
188
/* parent stack */
189
Avlnode *pptr[MAX_TREE_DEPTH];
190
unsigned char pdir[MAX_TREE_DEPTH];
191
int depth = 0;
192
193
if ( *root == NULL )
194
return NULL;
195
196
p = *root;
197
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;
205
206
p = p->avl_link[side];
207
if ( p == NULL )
208
return p;
209
}
210
data = p->avl_data;
211
212
/* If this node has two children, swap so we are deleting a node with
213
* at most one child.
214
*/
215
if ( p->avl_link[0] && p->avl_link[1] ) {
216
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];
225
}
226
/* swap links */
227
r = p->avl_link[0];
228
p->avl_link[0] = q->avl_link[0];
229
q->avl_link[0] = r;
230
231
q->avl_link[1] = p->avl_link[1];
232
p->avl_link[1] = NULL;
233
234
q->avl_bf = p->avl_bf;
235
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;
243
}
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;
250
}
251
}
252
253
/* now <p> has at most one child, get it */
254
q = p->avl_link[0] ? p->avl_link[0] : p->avl_link[1];
255
256
ber_memfree( p );
257
258
if ( !depth ) {
259
*root = q;
260
return data;
261
}
262
263
/* set the child into p's parent */
264
depth--;
265
p = pptr[depth];
266
side = pdir[depth];
267
p->avl_link[side] = q;
268
269
top = NULL;
270
shorter = 1;
271
272
while ( shorter ) {
273
p = pptr[depth];
274
side = pdir[depth];
275
nside = !side;
276
side_bf = avl_bfs[side];
277
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;
283
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);
302
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;
310
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;
316
317
p->avl_link[nside] = r->avl_link[side];
318
r->avl_link[side] = p;
319
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;
329
}
330
r->avl_bf = EH;
331
q = r;
332
}
333
/* a rotation has caused <q> (or <r> in case 3c) to become
334
* the root. let <p>'s former parent know this.
335
*/
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;
342
}
343
/* end case 3 */
344
p = q;
345
}
346
if ( !depth )
347
break;
348
depth--;
349
} /* end while(shorter) */
350
351
return data;
352
}
353
354
static int
355
avl_inapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
356
{
357
if ( root == 0 )
358
return( AVL_NOMORE );
359
360
if ( root->avl_left != 0 )
361
if ( avl_inapply( root->avl_left, fn, arg, stopflag )
362
== stopflag )
363
return( stopflag );
364
365
if ( (*fn)( root->avl_data, arg ) == stopflag )
366
return( stopflag );
367
368
if ( root->avl_right == 0 )
369
return( AVL_NOMORE );
370
else
371
return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
372
}
373
374
static int
375
avl_postapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
376
{
377
if ( root == 0 )
378
return( AVL_NOMORE );
379
380
if ( root->avl_left != 0 )
381
if ( avl_postapply( root->avl_left, fn, arg, stopflag )
382
== stopflag )
383
return( stopflag );
384
385
if ( root->avl_right != 0 )
386
if ( avl_postapply( root->avl_right, fn, arg, stopflag )
387
== stopflag )
388
return( stopflag );
389
390
return( (*fn)( root->avl_data, arg ) );
391
}
392
393
static int
394
avl_preapply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag )
395
{
396
if ( root == 0 )
397
return( AVL_NOMORE );
398
399
if ( (*fn)( root->avl_data, arg ) == stopflag )
400
return( stopflag );
401
402
if ( root->avl_left != 0 )
403
if ( avl_preapply( root->avl_left, fn, arg, stopflag )
404
== stopflag )
405
return( stopflag );
406
407
if ( root->avl_right == 0 )
408
return( AVL_NOMORE );
409
else
410
return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
411
}
412
413
/*
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.
419
*/
420
421
int
422
ldap_avl_apply( Avlnode *root, AVL_APPLY fn, void* arg, int stopflag, int type )
423
{
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 );
434
}
435
436
/* NOTREACHED */
437
}
438
439
/*
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.
448
*/
449
450
int
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
459
)
460
{
461
int cmp;
462
463
if ( root == 0 )
464
return( AVL_NOMORE );
465
466
cmp = (*fcmp)( data, root->avl_data /* , carg */);
467
if ( cmp == 0 ) {
468
if ( (*fmatch)( root->avl_data, marg ) == stopflag )
469
return( stopflag );
470
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 );
475
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 );
481
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 ) );
490
}
491
492
return( AVL_NOMORE );
493
}
494
495
/*
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.
499
*/
500
501
int
502
ldap_avl_free( Avlnode *root, AVL_FREE dfree )
503
{
504
int nleft, nright;
505
506
if ( root == 0 )
507
return( 0 );
508
509
nleft = nright = 0;
510
if ( root->avl_left != 0 )
511
nleft = ldap_avl_free( root->avl_left, dfree );
512
513
if ( root->avl_right != 0 )
514
nright = ldap_avl_free( root->avl_right, dfree );
515
516
if ( dfree )
517
(*dfree)( root->avl_data );
518
ber_memfree( root );
519
520
return( nleft + nright + 1 );
521
}
522
523
/*
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.
528
*/
529
530
Avlnode *
531
ldap_avl_find2( Avlnode *root, const void *data, AVL_CMP fcmp )
532
{
533
int cmp;
534
535
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
536
cmp = cmp > 0;
537
root = root->avl_link[cmp];
538
}
539
return root;
540
}
541
542
void*
543
ldap_avl_find( Avlnode *root, const void* data, AVL_CMP fcmp )
544
{
545
int cmp;
546
547
while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
548
cmp = cmp > 0;
549
root = root->avl_link[cmp];
550
}
551
552
return( root ? root->avl_data : 0 );
553
}
554
555
/*
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.
560
*/
561
562
void*
563
ldap_avl_find_lin( Avlnode *root, const void* data, AVL_CMP fcmp )
564
{
565
void* res;
566
567
if ( root == 0 )
568
return( NULL );
569
570
if ( (*fcmp)( data, root->avl_data ) == 0 )
571
return( root->avl_data );
572
573
if ( root->avl_left != 0 )
574
if ( (res = ldap_avl_find_lin( root->avl_left, data, fcmp ))
575
!= NULL )
576
return( res );
577
578
if ( root->avl_right == 0 )
579
return( NULL );
580
else
581
return( ldap_avl_find_lin( root->avl_right, data, fcmp ) );
582
}
583
584
/* NON-REENTRANT INTERFACE */
585
586
static void* *avl_list;
587
static int avl_maxlist;
588
static int ldap_avl_nextlist;
589
590
#define AVL_GRABSIZE 100
591
592
/* ARGSUSED */
593
static int
594
avl_buildlist( void* data, void* arg )
595
{
596
static int slots;
597
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*));
606
}
607
608
avl_list[ avl_maxlist++ ] = data;
609
610
return( 0 );
611
}
612
613
/*
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.
623
*/
624
625
void*
626
ldap_avl_getfirst( Avlnode *root )
627
{
628
if ( avl_list ) {
629
ber_memfree( (char *) avl_list);
630
avl_list = (void* *) 0;
631
}
632
avl_maxlist = 0;
633
ldap_avl_nextlist = 0;
634
635
if ( root == 0 )
636
return( 0 );
637
638
(void) ldap_avl_apply( root, avl_buildlist, (void*) 0, -1, AVL_INORDER );
639
640
return( avl_list[ ldap_avl_nextlist++ ] );
641
}
642
643
void*
644
ldap_avl_getnext( void )
645
{
646
if ( avl_list == 0 )
647
return( 0 );
648
649
if ( ldap_avl_nextlist == avl_maxlist ) {
650
ber_memfree( (void*) avl_list);
651
avl_list = (void* *) 0;
652
return( 0 );
653
}
654
655
return( avl_list[ ldap_avl_nextlist++ ] );
656
}
657
658
/* end non-reentrant code */
659
660
661
int
662
ldap_avl_dup_error( void* left, void* right )
663
{
664
return( -1 );
665
}
666
667
int
668
ldap_avl_dup_ok( void* left, void* right )
669
{
670
return( 0 );
671
}
672
673