18404SAndrew.W.Wilson@sun.com /* 28404SAndrew.W.Wilson@sun.com * CDDL HEADER START 38404SAndrew.W.Wilson@sun.com * 48404SAndrew.W.Wilson@sun.com * The contents of this file are subject to the terms of the 58404SAndrew.W.Wilson@sun.com * Common Development and Distribution License (the "License"). 68404SAndrew.W.Wilson@sun.com * You may not use this file except in compliance with the License. 78404SAndrew.W.Wilson@sun.com * 88404SAndrew.W.Wilson@sun.com * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98404SAndrew.W.Wilson@sun.com * or http://www.opensolaris.org/os/licensing. 108404SAndrew.W.Wilson@sun.com * See the License for the specific language governing permissions 118404SAndrew.W.Wilson@sun.com * and limitations under the License. 128404SAndrew.W.Wilson@sun.com * 138404SAndrew.W.Wilson@sun.com * When distributing Covered Code, include this CDDL HEADER in each 148404SAndrew.W.Wilson@sun.com * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158404SAndrew.W.Wilson@sun.com * If applicable, add the following below this CDDL HEADER, with the 168404SAndrew.W.Wilson@sun.com * fields enclosed by brackets "[]" replaced with your own identifying 178404SAndrew.W.Wilson@sun.com * information: Portions Copyright [yyyy] [name of copyright owner] 188404SAndrew.W.Wilson@sun.com * 198404SAndrew.W.Wilson@sun.com * CDDL HEADER END 208404SAndrew.W.Wilson@sun.com */ 218404SAndrew.W.Wilson@sun.com /* 22*9513SAndrew.W.Wilson@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 238404SAndrew.W.Wilson@sun.com * Use is subject to license terms. 248404SAndrew.W.Wilson@sun.com */ 258404SAndrew.W.Wilson@sun.com 268404SAndrew.W.Wilson@sun.com #ifndef FB_AVL_H 278404SAndrew.W.Wilson@sun.com #define FB_AVL_H 288404SAndrew.W.Wilson@sun.com 298404SAndrew.W.Wilson@sun.com /* 308404SAndrew.W.Wilson@sun.com * derived from Solaris' sys/avl.h and sys/avl_impl.h 318404SAndrew.W.Wilson@sun.com */ 328404SAndrew.W.Wilson@sun.com 338404SAndrew.W.Wilson@sun.com #ifdef __cplusplus 348404SAndrew.W.Wilson@sun.com extern "C" { 358404SAndrew.W.Wilson@sun.com #endif 368404SAndrew.W.Wilson@sun.com 378404SAndrew.W.Wilson@sun.com #include <sys/types.h> 388404SAndrew.W.Wilson@sun.com 398404SAndrew.W.Wilson@sun.com /* 408404SAndrew.W.Wilson@sun.com * generic AVL tree implementation for FileBench use 418404SAndrew.W.Wilson@sun.com * 428404SAndrew.W.Wilson@sun.com * The interfaces provide an efficient way of implementing an ordered set of 438404SAndrew.W.Wilson@sun.com * data structures. 448404SAndrew.W.Wilson@sun.com * 458404SAndrew.W.Wilson@sun.com * AVL trees provide an alternative to using an ordered linked list. Using AVL 468404SAndrew.W.Wilson@sun.com * trees will usually be faster, however they requires more storage. An ordered 478404SAndrew.W.Wilson@sun.com * linked list in general requires 2 pointers in each data structure. The 488404SAndrew.W.Wilson@sun.com * AVL tree implementation uses 3 pointers. The following chart gives the 498404SAndrew.W.Wilson@sun.com * approximate performance of operations with the different approaches: 508404SAndrew.W.Wilson@sun.com * 518404SAndrew.W.Wilson@sun.com * Operation Link List AVL tree 528404SAndrew.W.Wilson@sun.com * --------- -------- -------- 538404SAndrew.W.Wilson@sun.com * lookup O(n) O(log(n)) 548404SAndrew.W.Wilson@sun.com * 558404SAndrew.W.Wilson@sun.com * insert 1 node constant constant 568404SAndrew.W.Wilson@sun.com * 578404SAndrew.W.Wilson@sun.com * delete 1 node constant between constant and O(log(n)) 588404SAndrew.W.Wilson@sun.com * 598404SAndrew.W.Wilson@sun.com * delete all nodes O(n) O(n) 608404SAndrew.W.Wilson@sun.com * 618404SAndrew.W.Wilson@sun.com * visit the next 628404SAndrew.W.Wilson@sun.com * or prev node constant between constant and O(log(n)) 638404SAndrew.W.Wilson@sun.com * 648404SAndrew.W.Wilson@sun.com * 658404SAndrew.W.Wilson@sun.com * There are 5 pieces of information stored for each node in an AVL tree 668404SAndrew.W.Wilson@sun.com * 678404SAndrew.W.Wilson@sun.com * pointer to less than child 688404SAndrew.W.Wilson@sun.com * pointer to greater than child 698404SAndrew.W.Wilson@sun.com * a pointer to the parent of this node 708404SAndrew.W.Wilson@sun.com * an indication [0/1] of which child I am of my parent 718404SAndrew.W.Wilson@sun.com * a "balance" (-1, 0, +1) indicating which child tree is taller 728404SAndrew.W.Wilson@sun.com * 738404SAndrew.W.Wilson@sun.com * Since they only need 3 bits, the last two fields are packed into the 748404SAndrew.W.Wilson@sun.com * bottom bits of the parent pointer on 64 bit machines to save on space. 758404SAndrew.W.Wilson@sun.com */ 768404SAndrew.W.Wilson@sun.com 778404SAndrew.W.Wilson@sun.com #ifndef _LP64 788404SAndrew.W.Wilson@sun.com 798404SAndrew.W.Wilson@sun.com struct avl_node { 808404SAndrew.W.Wilson@sun.com struct avl_node *avl_child[2]; /* left/right children */ 818404SAndrew.W.Wilson@sun.com struct avl_node *avl_parent; /* this node's parent */ 828404SAndrew.W.Wilson@sun.com unsigned short avl_child_index; /* my index in parent's avl_child[] */ 838404SAndrew.W.Wilson@sun.com short avl_balance; /* balance value: -1, 0, +1 */ 848404SAndrew.W.Wilson@sun.com }; 858404SAndrew.W.Wilson@sun.com 868404SAndrew.W.Wilson@sun.com #define AVL_XPARENT(n) ((n)->avl_parent) 878404SAndrew.W.Wilson@sun.com #define AVL_SETPARENT(n, p) ((n)->avl_parent = (p)) 888404SAndrew.W.Wilson@sun.com 898404SAndrew.W.Wilson@sun.com #define AVL_XCHILD(n) ((n)->avl_child_index) 908404SAndrew.W.Wilson@sun.com #define AVL_SETCHILD(n, c) ((n)->avl_child_index = (unsigned short)(c)) 918404SAndrew.W.Wilson@sun.com 928404SAndrew.W.Wilson@sun.com #define AVL_XBALANCE(n) ((n)->avl_balance) 938404SAndrew.W.Wilson@sun.com #define AVL_SETBALANCE(n, b) ((n)->avl_balance = (short)(b)) 948404SAndrew.W.Wilson@sun.com 958404SAndrew.W.Wilson@sun.com #else /* _LP64 */ 968404SAndrew.W.Wilson@sun.com 978404SAndrew.W.Wilson@sun.com /* 988404SAndrew.W.Wilson@sun.com * for 64 bit machines, avl_pcb contains parent pointer, balance and child_index 998404SAndrew.W.Wilson@sun.com * values packed in the following manner: 1008404SAndrew.W.Wilson@sun.com * 1018404SAndrew.W.Wilson@sun.com * |63 3| 2 |1 0 | 1028404SAndrew.W.Wilson@sun.com * |-------------------------------------|-----------------|-------------| 1038404SAndrew.W.Wilson@sun.com * | avl_parent hi order bits | avl_child_index | avl_balance | 1048404SAndrew.W.Wilson@sun.com * | | | + 1 | 1058404SAndrew.W.Wilson@sun.com * |-------------------------------------|-----------------|-------------| 1068404SAndrew.W.Wilson@sun.com * 1078404SAndrew.W.Wilson@sun.com */ 1088404SAndrew.W.Wilson@sun.com struct avl_node { 1098404SAndrew.W.Wilson@sun.com struct avl_node *avl_child[2]; /* left/right children nodes */ 1108404SAndrew.W.Wilson@sun.com uintptr_t avl_pcb; /* parent, child_index, balance */ 1118404SAndrew.W.Wilson@sun.com }; 1128404SAndrew.W.Wilson@sun.com 1138404SAndrew.W.Wilson@sun.com /* 1148404SAndrew.W.Wilson@sun.com * macros to extract/set fields in avl_pcb 1158404SAndrew.W.Wilson@sun.com * 1168404SAndrew.W.Wilson@sun.com * pointer to the parent of the current node is the high order bits 1178404SAndrew.W.Wilson@sun.com */ 1188404SAndrew.W.Wilson@sun.com #define AVL_XPARENT(n) ((struct avl_node *)((n)->avl_pcb & ~7)) 1198404SAndrew.W.Wilson@sun.com #define AVL_SETPARENT(n, p) \ 1208404SAndrew.W.Wilson@sun.com ((n)->avl_pcb = (((n)->avl_pcb & 7) | (uintptr_t)(p))) 1218404SAndrew.W.Wilson@sun.com 1228404SAndrew.W.Wilson@sun.com /* 1238404SAndrew.W.Wilson@sun.com * index of this node in its parent's avl_child[]: bit #2 1248404SAndrew.W.Wilson@sun.com */ 1258404SAndrew.W.Wilson@sun.com #define AVL_XCHILD(n) (((n)->avl_pcb >> 2) & 1) 1268404SAndrew.W.Wilson@sun.com #define AVL_SETCHILD(n, c) \ 1278404SAndrew.W.Wilson@sun.com ((n)->avl_pcb = (uintptr_t)(((n)->avl_pcb & ~4) | ((c) << 2))) 1288404SAndrew.W.Wilson@sun.com 1298404SAndrew.W.Wilson@sun.com /* 1308404SAndrew.W.Wilson@sun.com * balance indication for a node, lowest 2 bits. A valid balance is 1318404SAndrew.W.Wilson@sun.com * -1, 0, or +1, and is encoded by adding 1 to the value to get the 1328404SAndrew.W.Wilson@sun.com * unsigned values of 0, 1, 2. 1338404SAndrew.W.Wilson@sun.com */ 1348404SAndrew.W.Wilson@sun.com #define AVL_XBALANCE(n) ((int)(((n)->avl_pcb & 3) - 1)) 1358404SAndrew.W.Wilson@sun.com #define AVL_SETBALANCE(n, b) \ 1368404SAndrew.W.Wilson@sun.com ((n)->avl_pcb = (uintptr_t)((((n)->avl_pcb & ~3) | ((b) + 1)))) 1378404SAndrew.W.Wilson@sun.com 1388404SAndrew.W.Wilson@sun.com #endif /* _LP64 */ 1398404SAndrew.W.Wilson@sun.com 1408404SAndrew.W.Wilson@sun.com 1418404SAndrew.W.Wilson@sun.com 1428404SAndrew.W.Wilson@sun.com /* 1438404SAndrew.W.Wilson@sun.com * switch between a node and data pointer for a given tree 1448404SAndrew.W.Wilson@sun.com * the value of "o" is tree->avl_offset 1458404SAndrew.W.Wilson@sun.com */ 1468404SAndrew.W.Wilson@sun.com #define AVL_NODE2DATA(n, o) ((void *)((uintptr_t)(n) - (o))) 1478404SAndrew.W.Wilson@sun.com #define AVL_DATA2NODE(d, o) ((struct avl_node *)((uintptr_t)(d) + (o))) 1488404SAndrew.W.Wilson@sun.com 1498404SAndrew.W.Wilson@sun.com 1508404SAndrew.W.Wilson@sun.com 1518404SAndrew.W.Wilson@sun.com /* 1528404SAndrew.W.Wilson@sun.com * macros used to create/access an avl_index_t 1538404SAndrew.W.Wilson@sun.com */ 1548404SAndrew.W.Wilson@sun.com #define AVL_INDEX2NODE(x) ((avl_node_t *)((x) & ~1)) 1558404SAndrew.W.Wilson@sun.com #define AVL_INDEX2CHILD(x) ((x) & 1) 1568404SAndrew.W.Wilson@sun.com #define AVL_MKINDEX(n, c) ((avl_index_t)(n) | (c)) 1578404SAndrew.W.Wilson@sun.com 1588404SAndrew.W.Wilson@sun.com 1598404SAndrew.W.Wilson@sun.com /* 1608404SAndrew.W.Wilson@sun.com * The tree structure. The fields avl_root, avl_compar, and avl_offset come 1618404SAndrew.W.Wilson@sun.com * first since they are needed for avl_find(). We want them to fit into 1628404SAndrew.W.Wilson@sun.com * a single 64 byte cache line to make avl_find() as fast as possible. 1638404SAndrew.W.Wilson@sun.com */ 1648404SAndrew.W.Wilson@sun.com struct avl_tree { 1658404SAndrew.W.Wilson@sun.com struct avl_node *avl_root; /* root node in tree */ 1668404SAndrew.W.Wilson@sun.com int (*avl_compar)(const void *, const void *); 1678404SAndrew.W.Wilson@sun.com size_t avl_offset; /* offsetof(type, avl_link_t field) */ 168*9513SAndrew.W.Wilson@sun.com unsigned long avl_numnodes; /* number of nodes in the tree */ 1698404SAndrew.W.Wilson@sun.com size_t avl_size; /* sizeof user type struct */ 1708404SAndrew.W.Wilson@sun.com }; 1718404SAndrew.W.Wilson@sun.com 1728404SAndrew.W.Wilson@sun.com 1738404SAndrew.W.Wilson@sun.com /* 1748404SAndrew.W.Wilson@sun.com * This will only by used via AVL_NEXT() or AVL_PREV() 1758404SAndrew.W.Wilson@sun.com */ 1768404SAndrew.W.Wilson@sun.com extern void *avl_walk(struct avl_tree *, void *, int); 1778404SAndrew.W.Wilson@sun.com 1788404SAndrew.W.Wilson@sun.com 1798404SAndrew.W.Wilson@sun.com /* 1808404SAndrew.W.Wilson@sun.com * The data structure nodes are anchored at an "avl_tree_t" (the equivalent 1818404SAndrew.W.Wilson@sun.com * of a list header) and the individual nodes will have a field of 1828404SAndrew.W.Wilson@sun.com * type "avl_node_t" (corresponding to list pointers). 1838404SAndrew.W.Wilson@sun.com * 1848404SAndrew.W.Wilson@sun.com * The type "avl_index_t" is used to indicate a position in the list for 1858404SAndrew.W.Wilson@sun.com * certain calls. 1868404SAndrew.W.Wilson@sun.com * 1878404SAndrew.W.Wilson@sun.com * The usage scenario is generally: 1888404SAndrew.W.Wilson@sun.com * 1898404SAndrew.W.Wilson@sun.com * 1. Create the list/tree with: avl_create() 1908404SAndrew.W.Wilson@sun.com * 1918404SAndrew.W.Wilson@sun.com * followed by any mixture of: 1928404SAndrew.W.Wilson@sun.com * 1938404SAndrew.W.Wilson@sun.com * 2a. Insert nodes with: avl_add(), or avl_find() and avl_insert() 1948404SAndrew.W.Wilson@sun.com * 1958404SAndrew.W.Wilson@sun.com * 2b. Visited elements with: 1968404SAndrew.W.Wilson@sun.com * avl_first() - returns the lowest valued node 1978404SAndrew.W.Wilson@sun.com * avl_last() - returns the highest valued node 1988404SAndrew.W.Wilson@sun.com * AVL_NEXT() - given a node go to next higher one 1998404SAndrew.W.Wilson@sun.com * AVL_PREV() - given a node go to previous lower one 2008404SAndrew.W.Wilson@sun.com * 2018404SAndrew.W.Wilson@sun.com * 2c. Find the node with the closest value either less than or greater 2028404SAndrew.W.Wilson@sun.com * than a given value with avl_nearest(). 2038404SAndrew.W.Wilson@sun.com * 2048404SAndrew.W.Wilson@sun.com * 2d. Remove individual nodes from the list/tree with avl_remove(). 2058404SAndrew.W.Wilson@sun.com * 2068404SAndrew.W.Wilson@sun.com * and finally when the list is being destroyed 2078404SAndrew.W.Wilson@sun.com * 2088404SAndrew.W.Wilson@sun.com * 3. Use avl_destroy_nodes() to quickly process/free up any remaining nodes. 2098404SAndrew.W.Wilson@sun.com * Note that once you use avl_destroy_nodes(), you can no longer 2108404SAndrew.W.Wilson@sun.com * use any routine except avl_destroy_nodes() and avl_destoy(). 2118404SAndrew.W.Wilson@sun.com * 2128404SAndrew.W.Wilson@sun.com * 4. Use avl_destroy() to destroy the AVL tree itself. 2138404SAndrew.W.Wilson@sun.com * 2148404SAndrew.W.Wilson@sun.com * Any locking for multiple thread access is up to the user to provide, just 2158404SAndrew.W.Wilson@sun.com * as is needed for any linked list implementation. 2168404SAndrew.W.Wilson@sun.com */ 2178404SAndrew.W.Wilson@sun.com 2188404SAndrew.W.Wilson@sun.com 2198404SAndrew.W.Wilson@sun.com /* 2208404SAndrew.W.Wilson@sun.com * Type used for the root of the AVL tree. 2218404SAndrew.W.Wilson@sun.com */ 2228404SAndrew.W.Wilson@sun.com typedef struct avl_tree avl_tree_t; 2238404SAndrew.W.Wilson@sun.com 2248404SAndrew.W.Wilson@sun.com /* 2258404SAndrew.W.Wilson@sun.com * The data nodes in the AVL tree must have a field of this type. 2268404SAndrew.W.Wilson@sun.com */ 2278404SAndrew.W.Wilson@sun.com typedef struct avl_node avl_node_t; 2288404SAndrew.W.Wilson@sun.com 2298404SAndrew.W.Wilson@sun.com /* 2308404SAndrew.W.Wilson@sun.com * An opaque type used to locate a position in the tree where a node 2318404SAndrew.W.Wilson@sun.com * would be inserted. 2328404SAndrew.W.Wilson@sun.com */ 2338404SAndrew.W.Wilson@sun.com typedef uintptr_t avl_index_t; 2348404SAndrew.W.Wilson@sun.com 2358404SAndrew.W.Wilson@sun.com 2368404SAndrew.W.Wilson@sun.com /* 2378404SAndrew.W.Wilson@sun.com * Direction constants used for avl_nearest(). 2388404SAndrew.W.Wilson@sun.com */ 2398404SAndrew.W.Wilson@sun.com #define AVL_BEFORE (0) 2408404SAndrew.W.Wilson@sun.com #define AVL_AFTER (1) 2418404SAndrew.W.Wilson@sun.com 2428404SAndrew.W.Wilson@sun.com 2438404SAndrew.W.Wilson@sun.com /* 2448404SAndrew.W.Wilson@sun.com * Prototypes 2458404SAndrew.W.Wilson@sun.com * 2468404SAndrew.W.Wilson@sun.com * Where not otherwise mentioned, "void *" arguments are a pointer to the 2478404SAndrew.W.Wilson@sun.com * user data structure which must contain a field of type avl_node_t. 2488404SAndrew.W.Wilson@sun.com * 2498404SAndrew.W.Wilson@sun.com * Also assume the user data structures looks like: 2508404SAndrew.W.Wilson@sun.com * stuct my_type { 2518404SAndrew.W.Wilson@sun.com * ... 2528404SAndrew.W.Wilson@sun.com * avl_node_t my_link; 2538404SAndrew.W.Wilson@sun.com * ... 2548404SAndrew.W.Wilson@sun.com * }; 2558404SAndrew.W.Wilson@sun.com */ 2568404SAndrew.W.Wilson@sun.com 2578404SAndrew.W.Wilson@sun.com /* 2588404SAndrew.W.Wilson@sun.com * Initialize an AVL tree. Arguments are: 2598404SAndrew.W.Wilson@sun.com * 2608404SAndrew.W.Wilson@sun.com * tree - the tree to be initialized 2618404SAndrew.W.Wilson@sun.com * compar - function to compare two nodes, it must return exactly: -1, 0, or +1 2628404SAndrew.W.Wilson@sun.com * -1 for <, 0 for ==, and +1 for > 2638404SAndrew.W.Wilson@sun.com * size - the value of sizeof(struct my_type) 2648404SAndrew.W.Wilson@sun.com * offset - the value of OFFSETOF(struct my_type, my_link) 2658404SAndrew.W.Wilson@sun.com */ 2668404SAndrew.W.Wilson@sun.com extern void avl_create(avl_tree_t *tree, 2678404SAndrew.W.Wilson@sun.com int (*compar) (const void *, const void *), size_t size, size_t offset); 2688404SAndrew.W.Wilson@sun.com 2698404SAndrew.W.Wilson@sun.com 2708404SAndrew.W.Wilson@sun.com /* 2718404SAndrew.W.Wilson@sun.com * Find a node with a matching value in the tree. Returns the matching node 2728404SAndrew.W.Wilson@sun.com * found. If not found, it returns NULL and then if "where" is not NULL it sets 2738404SAndrew.W.Wilson@sun.com * "where" for use with avl_insert() or avl_nearest(). 2748404SAndrew.W.Wilson@sun.com * 2758404SAndrew.W.Wilson@sun.com * node - node that has the value being looked for 2768404SAndrew.W.Wilson@sun.com * where - position for use with avl_nearest() or avl_insert(), may be NULL 2778404SAndrew.W.Wilson@sun.com */ 2788404SAndrew.W.Wilson@sun.com extern void *avl_find(avl_tree_t *tree, void *node, avl_index_t *where); 2798404SAndrew.W.Wilson@sun.com 2808404SAndrew.W.Wilson@sun.com /* 2818404SAndrew.W.Wilson@sun.com * Insert a node into the tree. 2828404SAndrew.W.Wilson@sun.com * 2838404SAndrew.W.Wilson@sun.com * node - the node to insert 2848404SAndrew.W.Wilson@sun.com * where - position as returned from avl_find() 2858404SAndrew.W.Wilson@sun.com */ 2868404SAndrew.W.Wilson@sun.com extern void avl_insert(avl_tree_t *tree, void *node, avl_index_t where); 2878404SAndrew.W.Wilson@sun.com 2888404SAndrew.W.Wilson@sun.com /* 2898404SAndrew.W.Wilson@sun.com * Insert "new_data" in "tree" in the given "direction" either after 2908404SAndrew.W.Wilson@sun.com * or before the data "here". 2918404SAndrew.W.Wilson@sun.com * 2928404SAndrew.W.Wilson@sun.com * This might be usefull for avl clients caching recently accessed 2938404SAndrew.W.Wilson@sun.com * data to avoid doing avl_find() again for insertion. 2948404SAndrew.W.Wilson@sun.com * 2958404SAndrew.W.Wilson@sun.com * new_data - new data to insert 2968404SAndrew.W.Wilson@sun.com * here - existing node in "tree" 2978404SAndrew.W.Wilson@sun.com * direction - either AVL_AFTER or AVL_BEFORE the data "here". 2988404SAndrew.W.Wilson@sun.com */ 2998404SAndrew.W.Wilson@sun.com extern void avl_insert_here(avl_tree_t *tree, void *new_data, void *here, 3008404SAndrew.W.Wilson@sun.com int direction); 3018404SAndrew.W.Wilson@sun.com 3028404SAndrew.W.Wilson@sun.com 3038404SAndrew.W.Wilson@sun.com /* 3048404SAndrew.W.Wilson@sun.com * Return the first or last valued node in the tree. Will return NULL 3058404SAndrew.W.Wilson@sun.com * if the tree is empty. 3068404SAndrew.W.Wilson@sun.com * 3078404SAndrew.W.Wilson@sun.com */ 3088404SAndrew.W.Wilson@sun.com extern void *avl_first(avl_tree_t *tree); 3098404SAndrew.W.Wilson@sun.com extern void *avl_last(avl_tree_t *tree); 3108404SAndrew.W.Wilson@sun.com 3118404SAndrew.W.Wilson@sun.com 3128404SAndrew.W.Wilson@sun.com /* 3138404SAndrew.W.Wilson@sun.com * Return the next or previous valued node in the tree. 3148404SAndrew.W.Wilson@sun.com * AVL_NEXT() will return NULL if at the last node. 3158404SAndrew.W.Wilson@sun.com * AVL_PREV() will return NULL if at the first node. 3168404SAndrew.W.Wilson@sun.com * 3178404SAndrew.W.Wilson@sun.com * node - the node from which the next or previous node is found 3188404SAndrew.W.Wilson@sun.com */ 3198404SAndrew.W.Wilson@sun.com #define AVL_NEXT(tree, node) avl_walk(tree, node, AVL_AFTER) 3208404SAndrew.W.Wilson@sun.com #define AVL_PREV(tree, node) avl_walk(tree, node, AVL_BEFORE) 3218404SAndrew.W.Wilson@sun.com 3228404SAndrew.W.Wilson@sun.com 3238404SAndrew.W.Wilson@sun.com /* 3248404SAndrew.W.Wilson@sun.com * Find the node with the nearest value either greater or less than 3258404SAndrew.W.Wilson@sun.com * the value from a previous avl_find(). Returns the node or NULL if 3268404SAndrew.W.Wilson@sun.com * there isn't a matching one. 3278404SAndrew.W.Wilson@sun.com * 3288404SAndrew.W.Wilson@sun.com * where - position as returned from avl_find() 3298404SAndrew.W.Wilson@sun.com * direction - either AVL_BEFORE or AVL_AFTER 3308404SAndrew.W.Wilson@sun.com * 3318404SAndrew.W.Wilson@sun.com * EXAMPLE get the greatest node that is less than a given value: 3328404SAndrew.W.Wilson@sun.com * 3338404SAndrew.W.Wilson@sun.com * avl_tree_t *tree; 3348404SAndrew.W.Wilson@sun.com * struct my_data look_for_value = {....}; 3358404SAndrew.W.Wilson@sun.com * struct my_data *node; 3368404SAndrew.W.Wilson@sun.com * struct my_data *less; 3378404SAndrew.W.Wilson@sun.com * avl_index_t where; 3388404SAndrew.W.Wilson@sun.com * 3398404SAndrew.W.Wilson@sun.com * node = avl_find(tree, &look_for_value, &where); 3408404SAndrew.W.Wilson@sun.com * if (node != NULL) 3418404SAndrew.W.Wilson@sun.com * less = AVL_PREV(tree, node); 3428404SAndrew.W.Wilson@sun.com * else 3438404SAndrew.W.Wilson@sun.com * less = avl_nearest(tree, where, AVL_BEFORE); 3448404SAndrew.W.Wilson@sun.com */ 3458404SAndrew.W.Wilson@sun.com extern void *avl_nearest(avl_tree_t *tree, avl_index_t where, int direction); 3468404SAndrew.W.Wilson@sun.com 3478404SAndrew.W.Wilson@sun.com 3488404SAndrew.W.Wilson@sun.com /* 3498404SAndrew.W.Wilson@sun.com * Add a single node to the tree. 3508404SAndrew.W.Wilson@sun.com * The node must not be in the tree, and it must not 3518404SAndrew.W.Wilson@sun.com * compare equal to any other node already in the tree. 3528404SAndrew.W.Wilson@sun.com * 3538404SAndrew.W.Wilson@sun.com * node - the node to add 3548404SAndrew.W.Wilson@sun.com */ 3558404SAndrew.W.Wilson@sun.com extern void avl_add(avl_tree_t *tree, void *node); 3568404SAndrew.W.Wilson@sun.com 3578404SAndrew.W.Wilson@sun.com 3588404SAndrew.W.Wilson@sun.com /* 3598404SAndrew.W.Wilson@sun.com * Remove a single node from the tree. The node must be in the tree. 3608404SAndrew.W.Wilson@sun.com * 3618404SAndrew.W.Wilson@sun.com * node - the node to remove 3628404SAndrew.W.Wilson@sun.com */ 3638404SAndrew.W.Wilson@sun.com extern void avl_remove(avl_tree_t *tree, void *node); 3648404SAndrew.W.Wilson@sun.com 3658404SAndrew.W.Wilson@sun.com /* 3668404SAndrew.W.Wilson@sun.com * Reinsert a node only if its order has changed relative to its nearest 3678404SAndrew.W.Wilson@sun.com * neighbors. To optimize performance avl_update_lt() checks only the previous 3688404SAndrew.W.Wilson@sun.com * node and avl_update_gt() checks only the next node. Use avl_update_lt() and 3698404SAndrew.W.Wilson@sun.com * avl_update_gt() only if you know the direction in which the order of the 3708404SAndrew.W.Wilson@sun.com * node may change. 3718404SAndrew.W.Wilson@sun.com */ 3728404SAndrew.W.Wilson@sun.com extern boolean_t avl_update(avl_tree_t *, void *); 3738404SAndrew.W.Wilson@sun.com extern boolean_t avl_update_lt(avl_tree_t *, void *); 3748404SAndrew.W.Wilson@sun.com extern boolean_t avl_update_gt(avl_tree_t *, void *); 3758404SAndrew.W.Wilson@sun.com 3768404SAndrew.W.Wilson@sun.com /* 3778404SAndrew.W.Wilson@sun.com * Return the number of nodes in the tree 3788404SAndrew.W.Wilson@sun.com */ 379*9513SAndrew.W.Wilson@sun.com extern unsigned long avl_numnodes(avl_tree_t *tree); 3808404SAndrew.W.Wilson@sun.com 3818404SAndrew.W.Wilson@sun.com /* 3828404SAndrew.W.Wilson@sun.com * Return B_TRUE if there are zero nodes in the tree, B_FALSE otherwise. 3838404SAndrew.W.Wilson@sun.com */ 3848404SAndrew.W.Wilson@sun.com extern boolean_t avl_is_empty(avl_tree_t *tree); 3858404SAndrew.W.Wilson@sun.com 3868404SAndrew.W.Wilson@sun.com /* 3878404SAndrew.W.Wilson@sun.com * Used to destroy any remaining nodes in a tree. The cookie argument should 3888404SAndrew.W.Wilson@sun.com * be initialized to NULL before the first call. Returns a node that has been 3898404SAndrew.W.Wilson@sun.com * removed from the tree and may be free()'d. Returns NULL when the tree is 3908404SAndrew.W.Wilson@sun.com * empty. 3918404SAndrew.W.Wilson@sun.com * 3928404SAndrew.W.Wilson@sun.com * Once you call avl_destroy_nodes(), you can only continuing calling it and 3938404SAndrew.W.Wilson@sun.com * finally avl_destroy(). No other AVL routines will be valid. 3948404SAndrew.W.Wilson@sun.com * 3958404SAndrew.W.Wilson@sun.com * cookie - a "void *" used to save state between calls to avl_destroy_nodes() 3968404SAndrew.W.Wilson@sun.com * 3978404SAndrew.W.Wilson@sun.com * EXAMPLE: 3988404SAndrew.W.Wilson@sun.com * avl_tree_t *tree; 3998404SAndrew.W.Wilson@sun.com * struct my_data *node; 4008404SAndrew.W.Wilson@sun.com * void *cookie; 4018404SAndrew.W.Wilson@sun.com * 4028404SAndrew.W.Wilson@sun.com * cookie = NULL; 4038404SAndrew.W.Wilson@sun.com * while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) 4048404SAndrew.W.Wilson@sun.com * free(node); 4058404SAndrew.W.Wilson@sun.com * avl_destroy(tree); 4068404SAndrew.W.Wilson@sun.com */ 4078404SAndrew.W.Wilson@sun.com extern void *avl_destroy_nodes(avl_tree_t *tree, void **cookie); 4088404SAndrew.W.Wilson@sun.com 4098404SAndrew.W.Wilson@sun.com 4108404SAndrew.W.Wilson@sun.com /* 4118404SAndrew.W.Wilson@sun.com * Final destroy of an AVL tree. Arguments are: 4128404SAndrew.W.Wilson@sun.com * 4138404SAndrew.W.Wilson@sun.com * tree - the empty tree to destroy 4148404SAndrew.W.Wilson@sun.com */ 4158404SAndrew.W.Wilson@sun.com extern void avl_destroy(avl_tree_t *tree); 4168404SAndrew.W.Wilson@sun.com 4178404SAndrew.W.Wilson@sun.com 4188404SAndrew.W.Wilson@sun.com 4198404SAndrew.W.Wilson@sun.com #ifdef __cplusplus 4208404SAndrew.W.Wilson@sun.com } 4218404SAndrew.W.Wilson@sun.com #endif 4228404SAndrew.W.Wilson@sun.com 4238404SAndrew.W.Wilson@sun.com #endif /* FB_AVL_H */ 424