1 /*******************************************************************
2 uLan Communication - C interface library
4 ul_gavl.c - generic AVL tree
6 (C) Copyright 2003 by Pavel Pisa - Originator
8 The uLan driver is distributed under the Gnu General Public License.
9 See file COPYING for details.
11 Originator reserve the right to use and publish sources
12 under different conditions too. If third party contributors
13 do not accept this condition, they can delete this statement
14 and only GNU license will apply.
15 *******************************************************************/
23 gavl_hdiff_check(gavl_node_t *node, int mode);
26 #define GAVL_HDIFF_DEBUG(tree, mode) gavl_hdiff_check(tree, mode)
28 #define GAVL_HDIFF_DEBUG(tree, mode)
33 * gavl_first_node - Returns First Node of GAVL Tree
34 * @root: GAVL tree root
36 * Return Value: pointer to the first node of tree according to ordering
39 gavl_first_node(const gavl_root_t *root)
41 gavl_node_t *n=root->root_node;
49 * gavl_last_node - Returns Last Node of GAVL Tree
50 * @root: GAVL tree root
52 * Return Value: pointer to the last node of tree according to ordering
55 gavl_last_node(const gavl_root_t *root)
57 gavl_node_t *n=root->root_node;
65 * gavl_is_empty - Check for Empty GAVL Tree
66 * @root: GAVL tree root
68 * Return Value: returns non-zero value if there is no node in the tree
71 gavl_is_empty(const gavl_root_t *root)
73 return !root->root_node;
77 * gavl_search_node - Search for Node or Place for Node by Key
78 * @root: GAVL tree root
79 * @key: key value searched for
80 * @mode: mode of the search operation
81 * @nodep: pointer to place for storing of pointer to found node
82 * or pointer to node which should be parent of inserted node
84 * Core search routine for GAVL trees
85 * searches in tree starting at @root for node of item
86 * with value of item field at offset @key_off
87 * equal to provided *@key value. Values are compared by function
88 * pointed by *@cmp_fnc field in the tree @root.
89 * Integer @mode modifies search algorithm:
90 * %GAVL_FANY .. finds node of any item with field value *@key,
91 * %GAVL_FFIRST .. finds node of first item with *@key,
92 * %GAVL_FAFTER .. node points after last item with *@key value,
93 * reworded - index points at first item with higher
94 * value of field or after last item
95 * Return Value: Return of nonzero value indicates match found.
96 * If the @mode is ored with %GAVL_FCMP, result of last compare
100 gavl_search_node(const gavl_root_t *root, const void *key,
101 int mode, gavl_node_t **nodep)
108 /*If external int than equivalent to cmp=*(int*)(n)-*(int*)key;*/
109 cmp=root->cmp_fnc(gavl_node2key(root,n),key);
112 }else if((cmp<0)||(mode&GAVL_FAFTER)){
118 if(mode&GAVL_FAFTER){
120 if(p) p=gavl_next_node(p);
124 if(cmp&&!(mode&GAVL_FCMP)){
128 if(mode&GAVL_FFIRST){
130 cmp=root->cmp_fnc(gavl_node2key(root,n),key);
135 cmp=root->cmp_fnc(gavl_node2key(root,n),key);
151 * gavl_find - Find Item for Provided Key
152 * @root: GAVL tree root
153 * @key: key value searched for
155 * Return Value: pointer to item associated to key value.
158 gavl_find(const gavl_root_t *root, const void *key)
162 ret=gavl_search_node(root, key, GAVL_FANY, &n);
163 if(!ret) return NULL;
164 return gavl_node2item(root,n);
168 * gavl_find_first - Find the First Item with Provided Key Value
169 * @root: GAVL tree root
170 * @key: key value searched for
172 * same as above, but first matching item is found.
173 * Return Value: pointer to the first item associated to key value.
176 gavl_find_first(const gavl_root_t *root, const void *key)
179 n=gavl_find_first_node(root, key);
180 return n?gavl_node2item(root,n):NULL;
184 * gavl_find_after - Find the First Item with Higher Key Value
185 * @root: GAVL tree root
186 * @key: key value searched for
188 * same as above, but first matching item is found.
189 * Return Value: pointer to the first item associated to key value.
192 gavl_find_after(const gavl_root_t *root, const void *key)
195 n=gavl_find_after(root, key);
196 return n?gavl_node2item(root,n):NULL;
200 * gavl_insert_node_at - Insert Existing Node to Already Computed Place into GAVL Tree
201 * @root: GAVL tree root
202 * @node: pointer to inserted node
203 * @where: pointer to found parent node
204 * @leftright: left (1) or right (0) branch
206 * Return Value: positive value informs about success
209 gavl_insert_node_at(gavl_root_t *root, gavl_node_t *node,
210 gavl_node_t *where, int leftright)
212 return gavl_insert_primitive_at(&root->root_node, node, where, leftright);
216 * gavl_insert_node - Insert Existing Node into GAVL Tree
217 * @root: GAVL tree root
218 * @node: pointer to inserted node
219 * @mode: if mode is %GAVL_FAFTER, multiple items with same key can
220 * be used, else strict ordering is required
222 * Return Value: positive value informs about success
225 gavl_insert_node(gavl_root_t *root, gavl_node_t *node, int mode)
230 cmp=gavl_search_node(root, gavl_node2key(root, node),
231 (mode|GAVL_FCMP), &where);
232 if((mode!=GAVL_FAFTER) && !cmp) return -1;
233 /*return gavl_insert_node_at(root, node, where, cmp);*/
234 /* insert_primitive called directly for speedup */
235 return gavl_insert_primitive_at(&root->root_node, node, where, cmp);
239 * gavl_insert - Insert New Item into GAVL Tree
240 * @root: GAVL tree root
241 * @item: pointer to inserted item
242 * @mode: if mode is GAVL_FAFTER, multiple items with same key can
243 * be used, else strict ordering is required
245 * Return Value: positive value informs about success, negative
246 * value indicates malloc fail or attempt to insert item
247 * with already defined key.
250 gavl_insert(gavl_root_t *root, void *item, int mode)
253 gavl_node_t *where, *n2add;
255 cmp=gavl_search_node(root, (char*)item+root->key_offs,
256 (mode|GAVL_FCMP), &where);
257 if((mode!=GAVL_FAFTER) && !cmp) return -1;
258 if(root->node_offs<0){
259 n2add=MALLOC(sizeof(gavl_node_t)+sizeof(void*));
260 if(!n2add) return -1;
261 *(void**)(n2add+1)=item;
263 n2add=(gavl_node_t*)((char*)item+root->node_offs);
265 /*return gavl_insert_node_at(root, n2add, where, cmp);*/
266 /* insert_primitive called directly for speedup */
267 return gavl_insert_primitive_at(&root->root_node, n2add, where, cmp);
271 * gavl_delete_node - Deletes/Unlinks Node from GAVL Tree
272 * @root: GAVL tree root
273 * @node: pointer to deleted node
275 * Return Value: positive value informs about success.
278 gavl_delete_node(gavl_root_t *root, gavl_node_t *node)
280 return gavl_delete_primitive(&root->root_node, node);
284 * gavl_delete - Delete/Unlink Item from GAVL Tree
285 * @root: GAVL tree root
286 * @item: pointer to deleted item
288 * Return Value: positive value informs about success, negative
289 * value indicates that item is not found in tree defined by root
292 gavl_delete(gavl_root_t *root, void *item)
297 if(root->node_offs>=0){
298 n=(gavl_node_t*)((char*)item+root->node_offs);
299 for(p=n; p->parent; p=p->parent);
300 if(p!=root->root_node)
303 if(!gavl_search_node(root, (char*)item+root->key_offs, GAVL_FFIRST, &n))
305 while(gavl_node2item(root,n)!=item){
308 if(root->cmp_fnc(gavl_node2key(root,n),(char*)item+root->key_offs))
312 /*ret=gavl_delete_node(root, n);*/
313 /* delete_primitive called directly for speedup */
314 ret=gavl_delete_primitive(&root->root_node, n);
315 if(root->node_offs<0)
321 * gavl_delete_and_next_node - Delete/Unlink Item from GAVL Tree
322 * @root: GAVL tree root
323 * @node: pointer to actual node which is unlinked from tree
324 * after function call, it can be unalocated or reused
325 * by application code after this call.
327 * This function can be used after call gavl_first_node() for destructive
328 * traversal through the tree, it cannot be combined with gavl_next_node()
329 * or gavl_prev_node() and root is emptied after the end of traversal.
330 * If the tree is used after unsuccessful/unfinished traversal, it
331 * must be balanced again. The height differences are inconsistent in other
332 * case. If traversal could be interrupted, the function gavl_cut_first()
333 * could be better choice.
334 * Return Value: pointer to next node or NULL, when all nodes are deleted
337 gavl_delete_and_next_node(gavl_root_t *root, gavl_node_t *node)
339 gavl_node_t *n, **np;
340 if(!node) node=gavl_first_node(root);
341 /* We are in big troubles if there is left child, somebody misused
342 this function => stop an pray, something bad happens in future */
343 if(node->left) return NULL;
344 if((n=node->parent)){
345 if(n->left==node) np=&n->left;
347 } else if(node==root->root_node) {
350 /* Cross tree arguments or corrupted tree */
355 n->parent=node->parent;
356 while(n->left) n=n->left;
362 /* Again, this cannot happen */
363 if(node->parent->left!=node) return NULL;
367 node->left=node->right=NULL;
372 /*===========================================================*/
373 /* basic types compare functions */
375 int gavl_cmp_int(const void *a, const void *b)
377 if (*(int*)a>*(int*)b) return 1;
378 if (*(int*)a<*(int*)b) return -1;
382 int gavl_cmp_long(const void *a, const void *b)
384 if (*(long*)a>*(long*)b) return 1;
385 if (*(long*)a<*(long*)b) return -1;
389 int gavl_cmp_ptr(const void *a, const void *b)
391 if (*(void**)a>*(void**)b) return 1;
392 if (*(void**)a<*(void**)b) return -1;
396 /*===========================================================*/
397 /* support for unbalanced trees */
399 #ifdef GAVL_UNBALANCED_SUPPORT
402 gavl_adjust_hdiff(gavl_node_t *node, int adj)
406 while((p=node->parent)&&adj){
409 /*printf("L%d ",adj);*/
413 if((adj+=hdiff)<=0) break;
416 if(adj<-hdiff) adj=-hdiff;
421 /*printf("R%d ",adj);*/
424 if((adj-=hdiff)<=0) break;
427 if(adj<hdiff) adj=hdiff;
435 /* Partial balance - reduces number of nodes with hdiff >1 or <-1 */
437 gavl_balance_enhance(gavl_node_t **subtree)
441 if(!*subtree) return 0;
443 while(p->left) p=p->left;
446 while(n->left) n=n->left;
451 if(!n || (p==*subtree)){
452 if((p->hdiff>1)||((p->hdiff<-1))){
453 gavl_balance_one(subtree);
459 if((p->hdiff>1)||((p->hdiff<-1))){
460 if(gavl_balance_one(&n->left))
461 gavl_adjust_hdiff(n->left,-1);
466 if((p->hdiff>1)||((p->hdiff<-1))){
467 if(gavl_balance_one(&n->right))
468 gavl_adjust_hdiff(n->right,-1);
479 /* Full tree balance */
481 gavl_balance(gavl_root_t *root)
487 if(!root->root_node) return 0;
488 for(n1=gavl_first_node(root);n1;n1=n2){
489 n2=gavl_delete_and_next_node(root, n1);
495 if(s->left && !s->right){
496 s->right=n1; n1->parent=s;
500 } else if(!s->parent || (s->parent->hdiff>s->hdiff+1)){
502 n1->parent=s->parent;
503 if(s->parent) s->parent->right=n1;
505 n1->hdiff=s->hdiff+1;
510 if(s->parent->hdiff<s->hdiff+1) s->parent->hdiff=s->hdiff+1;
517 if(s->parent->hdiff<s->hdiff+1) s->parent->hdiff=s->hdiff+1;
522 if(!n1->right) n1->hdiff=0;
523 else n1->hdiff=-n1->right->hdiff;
525 n1->hdiff+=n1->left->hdiff;
530 if(n2){ n1=n2; break;}
535 if(n1->left==n2) {np=&n1->left; n2=n1->right;}
536 else {np=&n1->right; n2=NULL;}
542 int adj,hdiff, balfl;
544 for(n1=s;n1->right;n1=n1->right);
549 if(n1) np=&n1->right;
554 if(adj>-hdiff) adj=-hdiff;
556 while((*np)->hdiff>1){
557 if(gavl_balance_one(np))
569 * gavl_cut_first - Cut First Item from Tree
570 * @root: GAVL tree root
572 * This enables fast delete of the first item without tree balancing.
573 * The resulting tree is degraded but height differences are kept consistent.
574 * Use of this function can result in height of tree maximally one greater
575 * the tree managed by optimal AVL functions.
576 * Return Value: returns the first item or NULL if the tree is empty
579 gavl_cut_first(gavl_root_t *root)
583 if(!(n=gavl_cut_first_primitive(&root->root_node)))
585 item=gavl_node2item(root,n);
586 if(root->node_offs<0)
591 #endif /*GAVL_UNBALANCED_SUPPORT*/