1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * AVL - generic AVL tree implementation for kernel use 32*0Sstevel@tonic-gate * 33*0Sstevel@tonic-gate * A complete description of AVL trees can be found in many CS textbooks. 34*0Sstevel@tonic-gate * 35*0Sstevel@tonic-gate * Here is a very brief overview. An AVL tree is a binary search tree that is 36*0Sstevel@tonic-gate * almost perfectly balanced. By "almost" perfectly balanced, we mean that at 37*0Sstevel@tonic-gate * any given node, the left and right subtrees are allowed to differ in height 38*0Sstevel@tonic-gate * by at most 1 level. 39*0Sstevel@tonic-gate * 40*0Sstevel@tonic-gate * This relaxation from a perfectly balanced binary tree allows doing 41*0Sstevel@tonic-gate * insertion and deletion relatively efficiently. Searching the tree is 42*0Sstevel@tonic-gate * still a fast operation, roughly O(log(N)). 43*0Sstevel@tonic-gate * 44*0Sstevel@tonic-gate * The key to insertion and deletion is a set of tree maniuplations called 45*0Sstevel@tonic-gate * rotations, which bring unbalanced subtrees back into the semi-balanced state. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * This implementation of AVL trees has the following peculiarities: 48*0Sstevel@tonic-gate * 49*0Sstevel@tonic-gate * - The AVL specific data structures are physically embedded as fields 50*0Sstevel@tonic-gate * in the "using" data structures. To maintain generality the code 51*0Sstevel@tonic-gate * must constantly translate between "avl_node_t *" and containing 52*0Sstevel@tonic-gate * data structure "void *"s by adding/subracting the avl_offset. 53*0Sstevel@tonic-gate * 54*0Sstevel@tonic-gate * - Since the AVL data is always embedded in other structures, there is 55*0Sstevel@tonic-gate * no locking or memory allocation in the AVL routines. This must be 56*0Sstevel@tonic-gate * provided for by the enclosing data structure's semantics. Typically, 57*0Sstevel@tonic-gate * avl_insert()/_remove()/avl_insert_here() require some kind of 58*0Sstevel@tonic-gate * exclusive write lock. Other operations require a read lock. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * - The implementation uses iteration instead of explicit recursion, 61*0Sstevel@tonic-gate * since it is intended to run on limited size kernel stacks. Since 62*0Sstevel@tonic-gate * there is no recursion stack present to move "up" in the tree, 63*0Sstevel@tonic-gate * there is an explicit "parent" link in the avl_node_t. 64*0Sstevel@tonic-gate * 65*0Sstevel@tonic-gate * - The left/right children pointers of a node are in an array. 66*0Sstevel@tonic-gate * In the code, variables (instead of constants) are used to represent 67*0Sstevel@tonic-gate * left and right indices. The implementation is written as if it only 68*0Sstevel@tonic-gate * dealt with left handed manipulations. By changing the value assigned 69*0Sstevel@tonic-gate * to "left", the code also works for right handed trees. The 70*0Sstevel@tonic-gate * following variables/terms are frequently used: 71*0Sstevel@tonic-gate * 72*0Sstevel@tonic-gate * int left; // 0 when dealing with left children, 73*0Sstevel@tonic-gate * // 1 for dealing with right children 74*0Sstevel@tonic-gate * 75*0Sstevel@tonic-gate * int left_heavy; // -1 when left subtree is taller at some node, 76*0Sstevel@tonic-gate * // +1 when right subtree is taller 77*0Sstevel@tonic-gate * 78*0Sstevel@tonic-gate * int right; // will be the opposite of left (0 or 1) 79*0Sstevel@tonic-gate * int right_heavy;// will be the opposite of left_heavy (-1 or 1) 80*0Sstevel@tonic-gate * 81*0Sstevel@tonic-gate * int direction; // 0 for "<" (ie. left child); 1 for ">" (right) 82*0Sstevel@tonic-gate * 83*0Sstevel@tonic-gate * Though it is a little more confusing to read the code, the approach 84*0Sstevel@tonic-gate * allows using half as much code (and hence cache footprint) for tree 85*0Sstevel@tonic-gate * manipulations and eliminates many conditional branches. 86*0Sstevel@tonic-gate * 87*0Sstevel@tonic-gate * - The avl_index_t is an opaque "cookie" used to find nodes at or 88*0Sstevel@tonic-gate * adjacent to where a new value would be inserted in the tree. The value 89*0Sstevel@tonic-gate * is a modified "avl_node_t *". The bottom bit (normally 0 for a 90*0Sstevel@tonic-gate * pointer) is set to indicate if that the new node has a value greater 91*0Sstevel@tonic-gate * than the value of the indicated "avl_node_t *". 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate #include <sys/types.h> 95*0Sstevel@tonic-gate #include <sys/param.h> 96*0Sstevel@tonic-gate #include <sys/debug.h> 97*0Sstevel@tonic-gate #include <sys/avl.h> 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* 100*0Sstevel@tonic-gate * Small arrays to translate between balance (or diff) values and child indeces. 101*0Sstevel@tonic-gate * 102*0Sstevel@tonic-gate * Code that deals with binary tree data structures will randomly use 103*0Sstevel@tonic-gate * left and right children when examining a tree. C "if()" statements 104*0Sstevel@tonic-gate * which evaluate randomly suffer from very poor hardware branch prediction. 105*0Sstevel@tonic-gate * In this code we avoid some of the branch mispredictions by using the 106*0Sstevel@tonic-gate * following translation arrays. They replace random branches with an 107*0Sstevel@tonic-gate * additional memory reference. Since the translation arrays are both very 108*0Sstevel@tonic-gate * small the data should remain efficiently in cache. 109*0Sstevel@tonic-gate */ 110*0Sstevel@tonic-gate static const int avl_child2balance[2] = {-1, 1}; 111*0Sstevel@tonic-gate static const int avl_balance2child[] = {0, 0, 1}; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Walk from one node to the previous valued node (ie. an infix walk 116*0Sstevel@tonic-gate * towards the left). At any given node we do one of 2 things: 117*0Sstevel@tonic-gate * 118*0Sstevel@tonic-gate * - If there is a left child, go to it, then to it's rightmost descendant. 119*0Sstevel@tonic-gate * 120*0Sstevel@tonic-gate * - otherwise we return thru parent nodes until we've come from a right child. 121*0Sstevel@tonic-gate * 122*0Sstevel@tonic-gate * Return Value: 123*0Sstevel@tonic-gate * NULL - if at the end of the nodes 124*0Sstevel@tonic-gate * otherwise next node 125*0Sstevel@tonic-gate */ 126*0Sstevel@tonic-gate void * 127*0Sstevel@tonic-gate avl_walk(avl_tree_t *tree, void *oldnode, int left) 128*0Sstevel@tonic-gate { 129*0Sstevel@tonic-gate size_t off = tree->avl_offset; 130*0Sstevel@tonic-gate avl_node_t *node = AVL_DATA2NODE(oldnode, off); 131*0Sstevel@tonic-gate int right = 1 - left; 132*0Sstevel@tonic-gate int was_child; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * nowhere to walk to if tree is empty 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate if (node == NULL) 139*0Sstevel@tonic-gate return (NULL); 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * Visit the previous valued node. There are two possibilities: 143*0Sstevel@tonic-gate * 144*0Sstevel@tonic-gate * If this node has a left child, go down one left, then all 145*0Sstevel@tonic-gate * the way right. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate if (node->avl_child[left] != NULL) { 148*0Sstevel@tonic-gate for (node = node->avl_child[left]; 149*0Sstevel@tonic-gate node->avl_child[right] != NULL; 150*0Sstevel@tonic-gate node = node->avl_child[right]) 151*0Sstevel@tonic-gate ; 152*0Sstevel@tonic-gate /* 153*0Sstevel@tonic-gate * Otherwise, return thru left children as far as we can. 154*0Sstevel@tonic-gate */ 155*0Sstevel@tonic-gate } else { 156*0Sstevel@tonic-gate for (;;) { 157*0Sstevel@tonic-gate was_child = AVL_XCHILD(node); 158*0Sstevel@tonic-gate node = AVL_XPARENT(node); 159*0Sstevel@tonic-gate if (node == NULL) 160*0Sstevel@tonic-gate return (NULL); 161*0Sstevel@tonic-gate if (was_child == right) 162*0Sstevel@tonic-gate break; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate return (AVL_NODE2DATA(node, off)); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate /* 170*0Sstevel@tonic-gate * Return the lowest valued node in a tree or NULL. 171*0Sstevel@tonic-gate * (leftmost child from root of tree) 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate void * 174*0Sstevel@tonic-gate avl_first(avl_tree_t *tree) 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate avl_node_t *node; 177*0Sstevel@tonic-gate avl_node_t *prev = NULL; 178*0Sstevel@tonic-gate size_t off = tree->avl_offset; 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate for (node = tree->avl_root; node != NULL; node = node->avl_child[0]) 181*0Sstevel@tonic-gate prev = node; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (prev != NULL) 184*0Sstevel@tonic-gate return (AVL_NODE2DATA(prev, off)); 185*0Sstevel@tonic-gate return (NULL); 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate /* 189*0Sstevel@tonic-gate * Return the highest valued node in a tree or NULL. 190*0Sstevel@tonic-gate * (rightmost child from root of tree) 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate void * 193*0Sstevel@tonic-gate avl_last(avl_tree_t *tree) 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate avl_node_t *node; 196*0Sstevel@tonic-gate avl_node_t *prev = NULL; 197*0Sstevel@tonic-gate size_t off = tree->avl_offset; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate for (node = tree->avl_root; node != NULL; node = node->avl_child[1]) 200*0Sstevel@tonic-gate prev = node; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (prev != NULL) 203*0Sstevel@tonic-gate return (AVL_NODE2DATA(prev, off)); 204*0Sstevel@tonic-gate return (NULL); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate /* 208*0Sstevel@tonic-gate * Access the node immediately before or after an insertion point. 209*0Sstevel@tonic-gate * 210*0Sstevel@tonic-gate * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child 211*0Sstevel@tonic-gate * 212*0Sstevel@tonic-gate * Return value: 213*0Sstevel@tonic-gate * NULL: no node in the given direction 214*0Sstevel@tonic-gate * "void *" of the found tree node 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate void * 217*0Sstevel@tonic-gate avl_nearest(avl_tree_t *tree, avl_index_t where, int direction) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate int child = AVL_INDEX2CHILD(where); 220*0Sstevel@tonic-gate avl_node_t *node = AVL_INDEX2NODE(where); 221*0Sstevel@tonic-gate void *data; 222*0Sstevel@tonic-gate size_t off = tree->avl_offset; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate if (node == NULL) { 225*0Sstevel@tonic-gate ASSERT(tree->avl_root == NULL); 226*0Sstevel@tonic-gate return (NULL); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate data = AVL_NODE2DATA(node, off); 229*0Sstevel@tonic-gate if (child != direction) 230*0Sstevel@tonic-gate return (data); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate return (avl_walk(tree, data, direction)); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * Search for the node which contains "value". The algorithm is a 238*0Sstevel@tonic-gate * simple binary tree search. 239*0Sstevel@tonic-gate * 240*0Sstevel@tonic-gate * return value: 241*0Sstevel@tonic-gate * NULL: the value is not in the AVL tree 242*0Sstevel@tonic-gate * *where (if not NULL) is set to indicate the insertion point 243*0Sstevel@tonic-gate * "void *" of the found tree node 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate void * 246*0Sstevel@tonic-gate avl_find(avl_tree_t *tree, void *value, avl_index_t *where) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate avl_node_t *node; 249*0Sstevel@tonic-gate avl_node_t *prev = NULL; 250*0Sstevel@tonic-gate int child = 0; 251*0Sstevel@tonic-gate int diff; 252*0Sstevel@tonic-gate size_t off = tree->avl_offset; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate for (node = tree->avl_root; node != NULL; 255*0Sstevel@tonic-gate node = node->avl_child[child]) { 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate prev = node; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate diff = tree->avl_compar(value, AVL_NODE2DATA(node, off)); 260*0Sstevel@tonic-gate ASSERT(-1 <= diff && diff <= 1); 261*0Sstevel@tonic-gate if (diff == 0) { 262*0Sstevel@tonic-gate #ifdef DEBUG 263*0Sstevel@tonic-gate if (where != NULL) 264*0Sstevel@tonic-gate *where = NULL; 265*0Sstevel@tonic-gate #endif 266*0Sstevel@tonic-gate return (AVL_NODE2DATA(node, off)); 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate child = avl_balance2child[1 + diff]; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate if (where != NULL) 273*0Sstevel@tonic-gate *where = AVL_MKINDEX(prev, child); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate return (NULL); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate /* 280*0Sstevel@tonic-gate * Perform a rotation to restore balance at the subtree given by depth. 281*0Sstevel@tonic-gate * 282*0Sstevel@tonic-gate * This routine is used by both insertion and deletion. The return value 283*0Sstevel@tonic-gate * indicates: 284*0Sstevel@tonic-gate * 0 : subtree did not change height 285*0Sstevel@tonic-gate * !0 : subtree was reduced in height 286*0Sstevel@tonic-gate * 287*0Sstevel@tonic-gate * The code is written as if handling left rotations, right rotations are 288*0Sstevel@tonic-gate * symmetric and handled by swapping values of variables right/left[_heavy] 289*0Sstevel@tonic-gate * 290*0Sstevel@tonic-gate * On input balance is the "new" balance at "node". This value is either 291*0Sstevel@tonic-gate * -2 or +2. 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate static int 294*0Sstevel@tonic-gate avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance) 295*0Sstevel@tonic-gate { 296*0Sstevel@tonic-gate int left = !(balance < 0); /* when balance = -2, left will be 0 */ 297*0Sstevel@tonic-gate int right = 1 - left; 298*0Sstevel@tonic-gate int left_heavy = balance >> 1; 299*0Sstevel@tonic-gate int right_heavy = -left_heavy; 300*0Sstevel@tonic-gate avl_node_t *parent = AVL_XPARENT(node); 301*0Sstevel@tonic-gate avl_node_t *child = node->avl_child[left]; 302*0Sstevel@tonic-gate avl_node_t *cright; 303*0Sstevel@tonic-gate avl_node_t *gchild; 304*0Sstevel@tonic-gate avl_node_t *gright; 305*0Sstevel@tonic-gate avl_node_t *gleft; 306*0Sstevel@tonic-gate int which_child = AVL_XCHILD(node); 307*0Sstevel@tonic-gate int child_bal = AVL_XBALANCE(child); 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* BEGIN CSTYLED */ 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * case 1 : node is overly left heavy, the left child is balanced or 312*0Sstevel@tonic-gate * also left heavy. This requires the following rotation. 313*0Sstevel@tonic-gate * 314*0Sstevel@tonic-gate * (node bal:-2) 315*0Sstevel@tonic-gate * / \ 316*0Sstevel@tonic-gate * / \ 317*0Sstevel@tonic-gate * (child bal:0 or -1) 318*0Sstevel@tonic-gate * / \ 319*0Sstevel@tonic-gate * / \ 320*0Sstevel@tonic-gate * cright 321*0Sstevel@tonic-gate * 322*0Sstevel@tonic-gate * becomes: 323*0Sstevel@tonic-gate * 324*0Sstevel@tonic-gate * (child bal:1 or 0) 325*0Sstevel@tonic-gate * / \ 326*0Sstevel@tonic-gate * / \ 327*0Sstevel@tonic-gate * (node bal:-1 or 0) 328*0Sstevel@tonic-gate * / \ 329*0Sstevel@tonic-gate * / \ 330*0Sstevel@tonic-gate * cright 331*0Sstevel@tonic-gate * 332*0Sstevel@tonic-gate * we detect this situation by noting that child's balance is not 333*0Sstevel@tonic-gate * right_heavy. 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate /* END CSTYLED */ 336*0Sstevel@tonic-gate if (child_bal != right_heavy) { 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * compute new balance of nodes 340*0Sstevel@tonic-gate * 341*0Sstevel@tonic-gate * If child used to be left heavy (now balanced) we reduced 342*0Sstevel@tonic-gate * the height of this sub-tree -- used in "return...;" below 343*0Sstevel@tonic-gate */ 344*0Sstevel@tonic-gate child_bal += right_heavy; /* adjust towards right */ 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * move "cright" to be node's left child 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate cright = child->avl_child[right]; 350*0Sstevel@tonic-gate node->avl_child[left] = cright; 351*0Sstevel@tonic-gate if (cright != NULL) { 352*0Sstevel@tonic-gate AVL_SETPARENT(cright, node); 353*0Sstevel@tonic-gate AVL_SETCHILD(cright, left); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * move node to be child's right child 358*0Sstevel@tonic-gate */ 359*0Sstevel@tonic-gate child->avl_child[right] = node; 360*0Sstevel@tonic-gate AVL_SETBALANCE(node, -child_bal); 361*0Sstevel@tonic-gate AVL_SETCHILD(node, right); 362*0Sstevel@tonic-gate AVL_SETPARENT(node, child); 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate /* 365*0Sstevel@tonic-gate * update the pointer into this subtree 366*0Sstevel@tonic-gate */ 367*0Sstevel@tonic-gate AVL_SETBALANCE(child, child_bal); 368*0Sstevel@tonic-gate AVL_SETCHILD(child, which_child); 369*0Sstevel@tonic-gate AVL_SETPARENT(child, parent); 370*0Sstevel@tonic-gate if (parent != NULL) 371*0Sstevel@tonic-gate parent->avl_child[which_child] = child; 372*0Sstevel@tonic-gate else 373*0Sstevel@tonic-gate tree->avl_root = child; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate return (child_bal == 0); 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* BEGIN CSTYLED */ 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * case 2 : When node is left heavy, but child is right heavy we use 381*0Sstevel@tonic-gate * a different rotation. 382*0Sstevel@tonic-gate * 383*0Sstevel@tonic-gate * (node b:-2) 384*0Sstevel@tonic-gate * / \ 385*0Sstevel@tonic-gate * / \ 386*0Sstevel@tonic-gate * / \ 387*0Sstevel@tonic-gate * (child b:+1) 388*0Sstevel@tonic-gate * / \ 389*0Sstevel@tonic-gate * / \ 390*0Sstevel@tonic-gate * (gchild b: != 0) 391*0Sstevel@tonic-gate * / \ 392*0Sstevel@tonic-gate * / \ 393*0Sstevel@tonic-gate * gleft gright 394*0Sstevel@tonic-gate * 395*0Sstevel@tonic-gate * becomes: 396*0Sstevel@tonic-gate * 397*0Sstevel@tonic-gate * (gchild b:0) 398*0Sstevel@tonic-gate * / \ 399*0Sstevel@tonic-gate * / \ 400*0Sstevel@tonic-gate * / \ 401*0Sstevel@tonic-gate * (child b:?) (node b:?) 402*0Sstevel@tonic-gate * / \ / \ 403*0Sstevel@tonic-gate * / \ / \ 404*0Sstevel@tonic-gate * gleft gright 405*0Sstevel@tonic-gate * 406*0Sstevel@tonic-gate * computing the new balances is more complicated. As an example: 407*0Sstevel@tonic-gate * if gchild was right_heavy, then child is now left heavy 408*0Sstevel@tonic-gate * else it is balanced 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate /* END CSTYLED */ 411*0Sstevel@tonic-gate gchild = child->avl_child[right]; 412*0Sstevel@tonic-gate gleft = gchild->avl_child[left]; 413*0Sstevel@tonic-gate gright = gchild->avl_child[right]; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * move gright to left child of node and 417*0Sstevel@tonic-gate * 418*0Sstevel@tonic-gate * move gleft to right child of node 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate node->avl_child[left] = gright; 421*0Sstevel@tonic-gate if (gright != NULL) { 422*0Sstevel@tonic-gate AVL_SETPARENT(gright, node); 423*0Sstevel@tonic-gate AVL_SETCHILD(gright, left); 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate child->avl_child[right] = gleft; 427*0Sstevel@tonic-gate if (gleft != NULL) { 428*0Sstevel@tonic-gate AVL_SETPARENT(gleft, child); 429*0Sstevel@tonic-gate AVL_SETCHILD(gleft, right); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* 433*0Sstevel@tonic-gate * move child to left child of gchild and 434*0Sstevel@tonic-gate * 435*0Sstevel@tonic-gate * move node to right child of gchild and 436*0Sstevel@tonic-gate * 437*0Sstevel@tonic-gate * fixup parent of all this to point to gchild 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate balance = AVL_XBALANCE(gchild); 440*0Sstevel@tonic-gate gchild->avl_child[left] = child; 441*0Sstevel@tonic-gate AVL_SETBALANCE(child, (balance == right_heavy ? left_heavy : 0)); 442*0Sstevel@tonic-gate AVL_SETPARENT(child, gchild); 443*0Sstevel@tonic-gate AVL_SETCHILD(child, left); 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate gchild->avl_child[right] = node; 446*0Sstevel@tonic-gate AVL_SETBALANCE(node, (balance == left_heavy ? right_heavy : 0)); 447*0Sstevel@tonic-gate AVL_SETPARENT(node, gchild); 448*0Sstevel@tonic-gate AVL_SETCHILD(node, right); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate AVL_SETBALANCE(gchild, 0); 451*0Sstevel@tonic-gate AVL_SETPARENT(gchild, parent); 452*0Sstevel@tonic-gate AVL_SETCHILD(gchild, which_child); 453*0Sstevel@tonic-gate if (parent != NULL) 454*0Sstevel@tonic-gate parent->avl_child[which_child] = gchild; 455*0Sstevel@tonic-gate else 456*0Sstevel@tonic-gate tree->avl_root = gchild; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate return (1); /* the new tree is always shorter */ 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * Insert a new node into an AVL tree at the specified (from avl_find()) place. 464*0Sstevel@tonic-gate * 465*0Sstevel@tonic-gate * Newly inserted nodes are always leaf nodes in the tree, since avl_find() 466*0Sstevel@tonic-gate * searches out to the leaf positions. The avl_index_t indicates the node 467*0Sstevel@tonic-gate * which will be the parent of the new node. 468*0Sstevel@tonic-gate * 469*0Sstevel@tonic-gate * After the node is inserted, a single rotation further up the tree may 470*0Sstevel@tonic-gate * be necessary to maintain an acceptable AVL balance. 471*0Sstevel@tonic-gate */ 472*0Sstevel@tonic-gate void 473*0Sstevel@tonic-gate avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where) 474*0Sstevel@tonic-gate { 475*0Sstevel@tonic-gate avl_node_t *node; 476*0Sstevel@tonic-gate avl_node_t *parent = AVL_INDEX2NODE(where); 477*0Sstevel@tonic-gate int old_balance; 478*0Sstevel@tonic-gate int new_balance; 479*0Sstevel@tonic-gate int which_child = AVL_INDEX2CHILD(where); 480*0Sstevel@tonic-gate size_t off = tree->avl_offset; 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate ASSERT(tree); 483*0Sstevel@tonic-gate #ifdef _LP64 484*0Sstevel@tonic-gate ASSERT(((uintptr_t)new_data & 0x7) == 0); 485*0Sstevel@tonic-gate #endif 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate node = AVL_DATA2NODE(new_data, off); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate /* 490*0Sstevel@tonic-gate * First, add the node to the tree at the indicated position. 491*0Sstevel@tonic-gate */ 492*0Sstevel@tonic-gate ++tree->avl_numnodes; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate node->avl_child[0] = NULL; 495*0Sstevel@tonic-gate node->avl_child[1] = NULL; 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate AVL_SETCHILD(node, which_child); 498*0Sstevel@tonic-gate AVL_SETBALANCE(node, 0); 499*0Sstevel@tonic-gate AVL_SETPARENT(node, parent); 500*0Sstevel@tonic-gate if (parent != NULL) { 501*0Sstevel@tonic-gate ASSERT(parent->avl_child[which_child] == NULL); 502*0Sstevel@tonic-gate parent->avl_child[which_child] = node; 503*0Sstevel@tonic-gate } else { 504*0Sstevel@tonic-gate ASSERT(tree->avl_root == NULL); 505*0Sstevel@tonic-gate tree->avl_root = node; 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * Now, back up the tree modifying the balance of all nodes above the 509*0Sstevel@tonic-gate * insertion point. If we get to a highly unbalanced ancestor, we 510*0Sstevel@tonic-gate * need to do a rotation. If we back out of the tree we are done. 511*0Sstevel@tonic-gate * If we brought any subtree into perfect balance (0), we are also done. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate for (;;) { 514*0Sstevel@tonic-gate node = parent; 515*0Sstevel@tonic-gate if (node == NULL) 516*0Sstevel@tonic-gate return; 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* 519*0Sstevel@tonic-gate * Compute the new balance 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate old_balance = AVL_XBALANCE(node); 522*0Sstevel@tonic-gate new_balance = old_balance + avl_child2balance[which_child]; 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * If we introduced equal balance, then we are done immediately 526*0Sstevel@tonic-gate */ 527*0Sstevel@tonic-gate if (new_balance == 0) { 528*0Sstevel@tonic-gate AVL_SETBALANCE(node, 0); 529*0Sstevel@tonic-gate return; 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate /* 533*0Sstevel@tonic-gate * If both old and new are not zero we went 534*0Sstevel@tonic-gate * from -1 to -2 balance, do a rotation. 535*0Sstevel@tonic-gate */ 536*0Sstevel@tonic-gate if (old_balance != 0) 537*0Sstevel@tonic-gate break; 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate AVL_SETBALANCE(node, new_balance); 540*0Sstevel@tonic-gate parent = AVL_XPARENT(node); 541*0Sstevel@tonic-gate which_child = AVL_XCHILD(node); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* 545*0Sstevel@tonic-gate * perform a rotation to fix the tree and return 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate (void) avl_rotation(tree, node, new_balance); 548*0Sstevel@tonic-gate } 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate /* 551*0Sstevel@tonic-gate * Insert "new_data" in "tree" in the given "direction" either after or 552*0Sstevel@tonic-gate * before (AVL_AFTER, AVL_BEFORE) the data "here". 553*0Sstevel@tonic-gate * 554*0Sstevel@tonic-gate * Insertions can only be done at empty leaf points in the tree, therefore 555*0Sstevel@tonic-gate * if the given child of the node is already present we move to either 556*0Sstevel@tonic-gate * the AVL_PREV or AVL_NEXT and reverse the insertion direction. Since 557*0Sstevel@tonic-gate * every other node in the tree is a leaf, this always works. 558*0Sstevel@tonic-gate * 559*0Sstevel@tonic-gate * To help developers using this interface, we assert that the new node 560*0Sstevel@tonic-gate * is correctly ordered at every step of the way in DEBUG kernels. 561*0Sstevel@tonic-gate */ 562*0Sstevel@tonic-gate void 563*0Sstevel@tonic-gate avl_insert_here( 564*0Sstevel@tonic-gate avl_tree_t *tree, 565*0Sstevel@tonic-gate void *new_data, 566*0Sstevel@tonic-gate void *here, 567*0Sstevel@tonic-gate int direction) 568*0Sstevel@tonic-gate { 569*0Sstevel@tonic-gate avl_node_t *node; 570*0Sstevel@tonic-gate int child = direction; /* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */ 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate ASSERT(tree != NULL); 573*0Sstevel@tonic-gate ASSERT(new_data != NULL); 574*0Sstevel@tonic-gate ASSERT(here != NULL); 575*0Sstevel@tonic-gate ASSERT(direction == AVL_BEFORE || direction == AVL_AFTER); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* 578*0Sstevel@tonic-gate * If corresponding child of node is not NULL, go to the neighboring 579*0Sstevel@tonic-gate * node and reverse the insertion direction. 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate node = AVL_DATA2NODE(here, tree->avl_offset); 582*0Sstevel@tonic-gate ASSERT(tree->avl_compar(new_data, here) > 0 ? child == 1 : child == 0); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate if (node->avl_child[child] != NULL) { 585*0Sstevel@tonic-gate node = node->avl_child[child]; 586*0Sstevel@tonic-gate child = 1 - child; 587*0Sstevel@tonic-gate while (node->avl_child[child] != NULL) { 588*0Sstevel@tonic-gate ASSERT(tree->avl_compar(new_data, 589*0Sstevel@tonic-gate AVL_NODE2DATA(node, tree->avl_offset)) > 0 ? 590*0Sstevel@tonic-gate child == 1 : child == 0); 591*0Sstevel@tonic-gate node = node->avl_child[child]; 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate ASSERT(tree->avl_compar(new_data, 594*0Sstevel@tonic-gate AVL_NODE2DATA(node, tree->avl_offset)) > 0 ? 595*0Sstevel@tonic-gate child == 1 : child == 0); 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate ASSERT(node->avl_child[child] == NULL); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate avl_insert(tree, new_data, AVL_MKINDEX(node, child)); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate /* 603*0Sstevel@tonic-gate * Delete a node from the AVL tree. Deletion is similar to insertion, but 604*0Sstevel@tonic-gate * with 2 complications. 605*0Sstevel@tonic-gate * 606*0Sstevel@tonic-gate * First, we may be deleting an interior node. Consider the following subtree: 607*0Sstevel@tonic-gate * 608*0Sstevel@tonic-gate * d c c 609*0Sstevel@tonic-gate * / \ / \ / \ 610*0Sstevel@tonic-gate * b e b e b e 611*0Sstevel@tonic-gate * / \ / \ / 612*0Sstevel@tonic-gate * a c a a 613*0Sstevel@tonic-gate * 614*0Sstevel@tonic-gate * When we are deleting node (d), we find and bring up an adjacent valued leaf 615*0Sstevel@tonic-gate * node, say (c), to take the interior node's place. In the code this is 616*0Sstevel@tonic-gate * handled by temporarily swapping (d) and (c) in the tree and then using 617*0Sstevel@tonic-gate * common code to delete (d) from the leaf position. 618*0Sstevel@tonic-gate * 619*0Sstevel@tonic-gate * Secondly, an interior deletion from a deep tree may require more than one 620*0Sstevel@tonic-gate * rotation to fix the balance. This is handled by moving up the tree through 621*0Sstevel@tonic-gate * parents and applying rotations as needed. The return value from 622*0Sstevel@tonic-gate * avl_rotation() is used to detect when a subtree did not change overall 623*0Sstevel@tonic-gate * height due to a rotation. 624*0Sstevel@tonic-gate */ 625*0Sstevel@tonic-gate void 626*0Sstevel@tonic-gate avl_remove(avl_tree_t *tree, void *data) 627*0Sstevel@tonic-gate { 628*0Sstevel@tonic-gate avl_node_t *delete; 629*0Sstevel@tonic-gate avl_node_t *parent; 630*0Sstevel@tonic-gate avl_node_t *node; 631*0Sstevel@tonic-gate avl_node_t tmp; 632*0Sstevel@tonic-gate int old_balance; 633*0Sstevel@tonic-gate int new_balance; 634*0Sstevel@tonic-gate int left; 635*0Sstevel@tonic-gate int right; 636*0Sstevel@tonic-gate int which_child; 637*0Sstevel@tonic-gate size_t off = tree->avl_offset; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate ASSERT(tree); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate delete = AVL_DATA2NODE(data, off); 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate /* 644*0Sstevel@tonic-gate * Deletion is easiest with a node that has at most 1 child. 645*0Sstevel@tonic-gate * We swap a node with 2 children with a sequentially valued 646*0Sstevel@tonic-gate * neighbor node. That node will have at most 1 child. Note this 647*0Sstevel@tonic-gate * has no effect on the ordering of the remaining nodes. 648*0Sstevel@tonic-gate * 649*0Sstevel@tonic-gate * As an optimization, we choose the greater neighbor if the tree 650*0Sstevel@tonic-gate * is right heavy, otherwise the left neighbor. This reduces the 651*0Sstevel@tonic-gate * number of rotations needed. 652*0Sstevel@tonic-gate */ 653*0Sstevel@tonic-gate if (delete->avl_child[0] != NULL && delete->avl_child[1] != NULL) { 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate /* 656*0Sstevel@tonic-gate * choose node to swap from whichever side is taller 657*0Sstevel@tonic-gate */ 658*0Sstevel@tonic-gate old_balance = AVL_XBALANCE(delete); 659*0Sstevel@tonic-gate left = avl_balance2child[old_balance + 1]; 660*0Sstevel@tonic-gate right = 1 - left; 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate /* 663*0Sstevel@tonic-gate * get to the previous value'd node 664*0Sstevel@tonic-gate * (down 1 left, as far as possible right) 665*0Sstevel@tonic-gate */ 666*0Sstevel@tonic-gate for (node = delete->avl_child[left]; 667*0Sstevel@tonic-gate node->avl_child[right] != NULL; 668*0Sstevel@tonic-gate node = node->avl_child[right]) 669*0Sstevel@tonic-gate ; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate /* 672*0Sstevel@tonic-gate * create a temp placeholder for 'node' 673*0Sstevel@tonic-gate * move 'node' to delete's spot in the tree 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate tmp = *node; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate *node = *delete; 678*0Sstevel@tonic-gate if (node->avl_child[left] == node) 679*0Sstevel@tonic-gate node->avl_child[left] = &tmp; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate parent = AVL_XPARENT(node); 682*0Sstevel@tonic-gate if (parent != NULL) 683*0Sstevel@tonic-gate parent->avl_child[AVL_XCHILD(node)] = node; 684*0Sstevel@tonic-gate else 685*0Sstevel@tonic-gate tree->avl_root = node; 686*0Sstevel@tonic-gate AVL_SETPARENT(node->avl_child[left], node); 687*0Sstevel@tonic-gate AVL_SETPARENT(node->avl_child[right], node); 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate /* 690*0Sstevel@tonic-gate * Put tmp where node used to be (just temporary). 691*0Sstevel@tonic-gate * It always has a parent and at most 1 child. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate delete = &tmp; 694*0Sstevel@tonic-gate parent = AVL_XPARENT(delete); 695*0Sstevel@tonic-gate parent->avl_child[AVL_XCHILD(delete)] = delete; 696*0Sstevel@tonic-gate which_child = (delete->avl_child[1] != 0); 697*0Sstevel@tonic-gate if (delete->avl_child[which_child] != NULL) 698*0Sstevel@tonic-gate AVL_SETPARENT(delete->avl_child[which_child], delete); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate /* 703*0Sstevel@tonic-gate * Here we know "delete" is at least partially a leaf node. It can 704*0Sstevel@tonic-gate * be easily removed from the tree. 705*0Sstevel@tonic-gate */ 706*0Sstevel@tonic-gate --tree->avl_numnodes; 707*0Sstevel@tonic-gate parent = AVL_XPARENT(delete); 708*0Sstevel@tonic-gate which_child = AVL_XCHILD(delete); 709*0Sstevel@tonic-gate if (delete->avl_child[0] != NULL) 710*0Sstevel@tonic-gate node = delete->avl_child[0]; 711*0Sstevel@tonic-gate else 712*0Sstevel@tonic-gate node = delete->avl_child[1]; 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /* 715*0Sstevel@tonic-gate * Connect parent directly to node (leaving out delete). 716*0Sstevel@tonic-gate */ 717*0Sstevel@tonic-gate if (node != NULL) { 718*0Sstevel@tonic-gate AVL_SETPARENT(node, parent); 719*0Sstevel@tonic-gate AVL_SETCHILD(node, which_child); 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate if (parent == NULL) { 722*0Sstevel@tonic-gate tree->avl_root = node; 723*0Sstevel@tonic-gate return; 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate parent->avl_child[which_child] = node; 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate /* 729*0Sstevel@tonic-gate * Since the subtree is now shorter, begin adjusting parent balances 730*0Sstevel@tonic-gate * and performing any needed rotations. 731*0Sstevel@tonic-gate */ 732*0Sstevel@tonic-gate do { 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate /* 735*0Sstevel@tonic-gate * Move up the tree and adjust the balance 736*0Sstevel@tonic-gate * 737*0Sstevel@tonic-gate * Capture the parent and which_child values for the next 738*0Sstevel@tonic-gate * iteration before any rotations occur. 739*0Sstevel@tonic-gate */ 740*0Sstevel@tonic-gate node = parent; 741*0Sstevel@tonic-gate old_balance = AVL_XBALANCE(node); 742*0Sstevel@tonic-gate new_balance = old_balance - avl_child2balance[which_child]; 743*0Sstevel@tonic-gate parent = AVL_XPARENT(node); 744*0Sstevel@tonic-gate which_child = AVL_XCHILD(node); 745*0Sstevel@tonic-gate 746*0Sstevel@tonic-gate /* 747*0Sstevel@tonic-gate * If a node was in perfect balance but isn't anymore then 748*0Sstevel@tonic-gate * we can stop, since the height didn't change above this point 749*0Sstevel@tonic-gate * due to a deletion. 750*0Sstevel@tonic-gate */ 751*0Sstevel@tonic-gate if (old_balance == 0) { 752*0Sstevel@tonic-gate AVL_SETBALANCE(node, new_balance); 753*0Sstevel@tonic-gate break; 754*0Sstevel@tonic-gate } 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate /* 757*0Sstevel@tonic-gate * If the new balance is zero, we don't need to rotate 758*0Sstevel@tonic-gate * else 759*0Sstevel@tonic-gate * need a rotation to fix the balance. 760*0Sstevel@tonic-gate * If the rotation doesn't change the height 761*0Sstevel@tonic-gate * of the sub-tree we have finished adjusting. 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate if (new_balance == 0) 764*0Sstevel@tonic-gate AVL_SETBALANCE(node, new_balance); 765*0Sstevel@tonic-gate else if (!avl_rotation(tree, node, new_balance)) 766*0Sstevel@tonic-gate break; 767*0Sstevel@tonic-gate } while (parent != NULL); 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate /* 771*0Sstevel@tonic-gate * initialize a new AVL tree 772*0Sstevel@tonic-gate */ 773*0Sstevel@tonic-gate void 774*0Sstevel@tonic-gate avl_create(avl_tree_t *tree, int (*compar) (const void *, const void *), 775*0Sstevel@tonic-gate size_t size, size_t offset) 776*0Sstevel@tonic-gate { 777*0Sstevel@tonic-gate ASSERT(tree); 778*0Sstevel@tonic-gate ASSERT(compar); 779*0Sstevel@tonic-gate ASSERT(size > 0); 780*0Sstevel@tonic-gate ASSERT(size >= offset + sizeof (avl_node_t)); 781*0Sstevel@tonic-gate #ifdef _LP64 782*0Sstevel@tonic-gate ASSERT((offset & 0x7) == 0); 783*0Sstevel@tonic-gate #endif 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate tree->avl_compar = compar; 786*0Sstevel@tonic-gate tree->avl_root = NULL; 787*0Sstevel@tonic-gate tree->avl_numnodes = 0; 788*0Sstevel@tonic-gate tree->avl_size = size; 789*0Sstevel@tonic-gate tree->avl_offset = offset; 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * Delete a tree. 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate /* ARGSUSED */ 796*0Sstevel@tonic-gate void 797*0Sstevel@tonic-gate avl_destroy(avl_tree_t *tree) 798*0Sstevel@tonic-gate { 799*0Sstevel@tonic-gate ASSERT(tree); 800*0Sstevel@tonic-gate ASSERT(tree->avl_numnodes == 0); 801*0Sstevel@tonic-gate ASSERT(tree->avl_root == NULL); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* 806*0Sstevel@tonic-gate * Return the number of nodes in an AVL tree. 807*0Sstevel@tonic-gate */ 808*0Sstevel@tonic-gate ulong_t 809*0Sstevel@tonic-gate avl_numnodes(avl_tree_t *tree) 810*0Sstevel@tonic-gate { 811*0Sstevel@tonic-gate ASSERT(tree); 812*0Sstevel@tonic-gate return (tree->avl_numnodes); 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate #define CHILDBIT (1L) 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate /* 819*0Sstevel@tonic-gate * Post-order tree walk used to visit all tree nodes and destroy the tree 820*0Sstevel@tonic-gate * in post order. This is used for destroying a tree w/o paying any cost 821*0Sstevel@tonic-gate * for rebalancing it. 822*0Sstevel@tonic-gate * 823*0Sstevel@tonic-gate * example: 824*0Sstevel@tonic-gate * 825*0Sstevel@tonic-gate * void *cookie = NULL; 826*0Sstevel@tonic-gate * my_data_t *node; 827*0Sstevel@tonic-gate * 828*0Sstevel@tonic-gate * while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) 829*0Sstevel@tonic-gate * free(node); 830*0Sstevel@tonic-gate * avl_destroy(tree); 831*0Sstevel@tonic-gate * 832*0Sstevel@tonic-gate * The cookie is really an avl_node_t to the current node's parent and 833*0Sstevel@tonic-gate * an indication of which child you looked at last. 834*0Sstevel@tonic-gate * 835*0Sstevel@tonic-gate * On input, a cookie value of CHILDBIT indicates the tree is done. 836*0Sstevel@tonic-gate */ 837*0Sstevel@tonic-gate void * 838*0Sstevel@tonic-gate avl_destroy_nodes(avl_tree_t *tree, void **cookie) 839*0Sstevel@tonic-gate { 840*0Sstevel@tonic-gate avl_node_t *node; 841*0Sstevel@tonic-gate avl_node_t *parent; 842*0Sstevel@tonic-gate int child; 843*0Sstevel@tonic-gate void *first; 844*0Sstevel@tonic-gate size_t off = tree->avl_offset; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate /* 847*0Sstevel@tonic-gate * Initial calls go to the first node or it's right descendant. 848*0Sstevel@tonic-gate */ 849*0Sstevel@tonic-gate if (*cookie == NULL) { 850*0Sstevel@tonic-gate first = avl_first(tree); 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate /* 853*0Sstevel@tonic-gate * deal with an empty tree 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate if (first == NULL) { 856*0Sstevel@tonic-gate *cookie = (void *)CHILDBIT; 857*0Sstevel@tonic-gate return (NULL); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate node = AVL_DATA2NODE(first, off); 861*0Sstevel@tonic-gate parent = AVL_XPARENT(node); 862*0Sstevel@tonic-gate goto check_right_side; 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate /* 866*0Sstevel@tonic-gate * If there is no parent to return to we are done. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate parent = (avl_node_t *)((uintptr_t)(*cookie) & ~CHILDBIT); 869*0Sstevel@tonic-gate if (parent == NULL) { 870*0Sstevel@tonic-gate if (tree->avl_root != NULL) { 871*0Sstevel@tonic-gate ASSERT(tree->avl_numnodes == 1); 872*0Sstevel@tonic-gate tree->avl_root = NULL; 873*0Sstevel@tonic-gate tree->avl_numnodes = 0; 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate return (NULL); 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* 879*0Sstevel@tonic-gate * Remove the child pointer we just visited from the parent and tree. 880*0Sstevel@tonic-gate */ 881*0Sstevel@tonic-gate child = (uintptr_t)(*cookie) & CHILDBIT; 882*0Sstevel@tonic-gate parent->avl_child[child] = NULL; 883*0Sstevel@tonic-gate ASSERT(tree->avl_numnodes > 1); 884*0Sstevel@tonic-gate --tree->avl_numnodes; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate /* 887*0Sstevel@tonic-gate * If we just did a right child or there isn't one, go up to parent. 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate if (child == 1 || parent->avl_child[1] == NULL) { 890*0Sstevel@tonic-gate node = parent; 891*0Sstevel@tonic-gate parent = AVL_XPARENT(parent); 892*0Sstevel@tonic-gate goto done; 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate /* 896*0Sstevel@tonic-gate * Do parent's right child, then leftmost descendent. 897*0Sstevel@tonic-gate */ 898*0Sstevel@tonic-gate node = parent->avl_child[1]; 899*0Sstevel@tonic-gate while (node->avl_child[0] != NULL) { 900*0Sstevel@tonic-gate parent = node; 901*0Sstevel@tonic-gate node = node->avl_child[0]; 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate /* 905*0Sstevel@tonic-gate * If here, we moved to a left child. It may have one 906*0Sstevel@tonic-gate * child on the right (when balance == +1). 907*0Sstevel@tonic-gate */ 908*0Sstevel@tonic-gate check_right_side: 909*0Sstevel@tonic-gate if (node->avl_child[1] != NULL) { 910*0Sstevel@tonic-gate ASSERT(AVL_XBALANCE(node) == 1); 911*0Sstevel@tonic-gate parent = node; 912*0Sstevel@tonic-gate node = node->avl_child[1]; 913*0Sstevel@tonic-gate ASSERT(node->avl_child[0] == NULL && 914*0Sstevel@tonic-gate node->avl_child[1] == NULL); 915*0Sstevel@tonic-gate } else { 916*0Sstevel@tonic-gate ASSERT(AVL_XBALANCE(node) <= 0); 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate done: 920*0Sstevel@tonic-gate if (parent == NULL) { 921*0Sstevel@tonic-gate *cookie = (void *)CHILDBIT; 922*0Sstevel@tonic-gate ASSERT(node == tree->avl_root); 923*0Sstevel@tonic-gate } else { 924*0Sstevel@tonic-gate *cookie = (void *)((uintptr_t)parent | AVL_XCHILD(node)); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate return (AVL_NODE2DATA(node, off)); 928*0Sstevel@tonic-gate } 929