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