avl_tree.c -- avl_ tree and linked list convenience
Copyright (C) 1998 Michael H. Buselli
2000-2005 Ivo Timmermans,
- 2000-2014 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2015 Guus Sliepen <guus@tinc-vpn.org>
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
This program is free software; you can redistribute it and/or modify
the code. Mail me if you found a bug.
Cleaned up and incorporated some of the ideas from the red-black tree
- library for inclusion into tinc (http://www.tinc-vpn.org/) by
+ library for inclusion into tinc (https://www.tinc-vpn.org/) by
Guus Sliepen <guus@tinc-vpn.org>.
*/
#endif
#ifndef AVL_DEPTH
-static int lg(unsigned int u) __attribute__ ((__const__));
+static int lg(unsigned int u) __attribute__((__const__));
-static int lg(unsigned int u)
-{
+static int lg(unsigned int u) {
int r = 1;
- if(!u)
+ if(!u) {
return 0;
+ }
if(u & 0xffff0000) {
u >>= 16;
r += 2;
}
- if(u & 0x00000002)
+ if(u & 0x00000002) {
r++;
+ }
return r;
}
/* Internal helper functions */
-static int avl_check_balance(const avl_node_t *node)
-{
+static int avl_check_balance(const avl_node_t *node) {
#ifdef AVL_DEPTH
int d;
return d < -1 ? -1 : d > 1 ? 1 : 0;
#else
-/* int d;
- * d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
- * d = d<-1?-1:d>1?1:0;
- */
+ /* int d;
+ * d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
+ * d = d<-1?-1:d>1?1:0;
+ */
int pl, r;
pl = lg(AVL_L_COUNT(node));
r = AVL_R_COUNT(node);
- if(r >> pl + 1)
+ if(r >> pl + 1) {
return 1;
+ }
- if(pl < 2 || r >> pl - 2)
+ if(pl < 2 || r >> pl - 2) {
return 0;
+ }
return -1;
#endif
}
-static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
-{
+static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
avl_node_t *child;
avl_node_t *gchild;
avl_node_t *parent;
parent = node->parent;
superparent =
- parent ? node ==
- parent->left ? &parent->left : &parent->right : &tree->root;
+ parent ? node ==
+ parent->left ? &parent->left : &parent->right : &tree->root;
- switch (avl_check_balance(node)) {
- case -1:
- child = node->left;
+ switch(avl_check_balance(node)) {
+ case -1:
+ child = node->left;
#ifdef AVL_DEPTH
- if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
+
+ if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
#else
- if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
+
+ if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
#endif
- node->left = child->right;
- if(node->left)
- node->left->parent = node;
-
- child->right = node;
- node->parent = child;
- *superparent = child;
- child->parent = parent;
+ node->left = child->right;
+
+ if(node->left) {
+ node->left->parent = node;
+ }
+
+ child->right = node;
+ node->parent = child;
+ *superparent = child;
+ child->parent = parent;
#ifdef AVL_COUNT
- node->count = AVL_CALC_COUNT(node);
- child->count = AVL_CALC_COUNT(child);
+ node->count = AVL_CALC_COUNT(node);
+ child->count = AVL_CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
- node->depth = AVL_CALC_DEPTH(node);
- child->depth = AVL_CALC_DEPTH(child);
+ node->depth = AVL_CALC_DEPTH(node);
+ child->depth = AVL_CALC_DEPTH(child);
#endif
- } else {
- gchild = child->right;
- node->left = gchild->right;
+ } else {
+ gchild = child->right;
+ node->left = gchild->right;
- if(node->left)
- node->left->parent = node;
- child->right = gchild->left;
+ if(node->left) {
+ node->left->parent = node;
+ }
+
+ child->right = gchild->left;
+
+ if(child->right) {
+ child->right->parent = child;
+ }
- if(child->right)
- child->right->parent = child;
- gchild->right = node;
+ gchild->right = node;
- gchild->right->parent = gchild;
- gchild->left = child;
+ gchild->right->parent = gchild;
+ gchild->left = child;
- gchild->left->parent = gchild;
+ gchild->left->parent = gchild;
- *superparent = gchild;
- gchild->parent = parent;
+ *superparent = gchild;
+ gchild->parent = parent;
#ifdef AVL_COUNT
- node->count = AVL_CALC_COUNT(node);
- child->count = AVL_CALC_COUNT(child);
- gchild->count = AVL_CALC_COUNT(gchild);
+ node->count = AVL_CALC_COUNT(node);
+ child->count = AVL_CALC_COUNT(child);
+ gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
- node->depth = AVL_CALC_DEPTH(node);
- child->depth = AVL_CALC_DEPTH(child);
- gchild->depth = AVL_CALC_DEPTH(gchild);
+ node->depth = AVL_CALC_DEPTH(node);
+ child->depth = AVL_CALC_DEPTH(child);
+ gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
- }
- break;
+ }
+
+ break;
- case 1:
- child = node->right;
+ case 1:
+ child = node->right;
#ifdef AVL_DEPTH
- if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
+
+ if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
#else
- if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
+
+ if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
#endif
- node->right = child->left;
- if(node->right)
- node->right->parent = node;
- child->left = node;
- node->parent = child;
- *superparent = child;
- child->parent = parent;
+ node->right = child->left;
+
+ if(node->right) {
+ node->right->parent = node;
+ }
+
+ child->left = node;
+ node->parent = child;
+ *superparent = child;
+ child->parent = parent;
#ifdef AVL_COUNT
- node->count = AVL_CALC_COUNT(node);
- child->count = AVL_CALC_COUNT(child);
+ node->count = AVL_CALC_COUNT(node);
+ child->count = AVL_CALC_COUNT(child);
#endif
#ifdef AVL_DEPTH
- node->depth = AVL_CALC_DEPTH(node);
- child->depth = AVL_CALC_DEPTH(child);
+ node->depth = AVL_CALC_DEPTH(node);
+ child->depth = AVL_CALC_DEPTH(child);
#endif
- } else {
- gchild = child->left;
- node->right = gchild->left;
+ } else {
+ gchild = child->left;
+ node->right = gchild->left;
+
+ if(node->right) {
+ node->right->parent = node;
+ }
- if(node->right)
- node->right->parent = node;
- child->left = gchild->right;
+ child->left = gchild->right;
+
+ if(child->left) {
+ child->left->parent = child;
+ }
- if(child->left)
- child->left->parent = child;
- gchild->left = node;
+ gchild->left = node;
- gchild->left->parent = gchild;
- gchild->right = child;
+ gchild->left->parent = gchild;
+ gchild->right = child;
- gchild->right->parent = gchild;
+ gchild->right->parent = gchild;
- *superparent = gchild;
- gchild->parent = parent;
+ *superparent = gchild;
+ gchild->parent = parent;
#ifdef AVL_COUNT
- node->count = AVL_CALC_COUNT(node);
- child->count = AVL_CALC_COUNT(child);
- gchild->count = AVL_CALC_COUNT(gchild);
+ node->count = AVL_CALC_COUNT(node);
+ child->count = AVL_CALC_COUNT(child);
+ gchild->count = AVL_CALC_COUNT(gchild);
#endif
#ifdef AVL_DEPTH
- node->depth = AVL_CALC_DEPTH(node);
- child->depth = AVL_CALC_DEPTH(child);
- gchild->depth = AVL_CALC_DEPTH(gchild);
+ node->depth = AVL_CALC_DEPTH(node);
+ child->depth = AVL_CALC_DEPTH(child);
+ gchild->depth = AVL_CALC_DEPTH(gchild);
#endif
- }
- break;
+ }
- default:
+ break;
+
+ default:
#ifdef AVL_COUNT
- node->count = AVL_CALC_COUNT(node);
+ node->count = AVL_CALC_COUNT(node);
#endif
#ifdef AVL_DEPTH
- node->depth = AVL_CALC_DEPTH(node);
+ node->depth = AVL_CALC_DEPTH(node);
#endif
}
+
node = parent;
}
}
/* (De)constructors */
-avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete)
-{
+avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
avl_tree_t *tree;
tree = xmalloc_and_zero(sizeof(avl_tree_t));
return tree;
}
-void avl_free_tree(avl_tree_t *tree)
-{
+void avl_free_tree(avl_tree_t *tree) {
free(tree);
}
-avl_node_t *avl_alloc_node(void)
-{
+avl_node_t *avl_alloc_node(void) {
return xmalloc_and_zero(sizeof(avl_node_t));
}
-void avl_free_node(avl_tree_t *tree, avl_node_t *node)
-{
- if(node->data && tree->delete)
+void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
+ if(node->data && tree->delete) {
tree->delete(node->data);
+ }
free(node);
}
/* Searching */
-void *avl_search(const avl_tree_t *tree, const void *data)
-{
+void *avl_search(const avl_tree_t *tree, const void *data) {
avl_node_t *node;
node = avl_search_node(tree, data);
return node ? node->data : NULL;
}
-void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result)
-{
+void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
avl_node_t *node;
node = avl_search_closest_node(tree, data, result);
return node ? node->data : NULL;
}
-void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data)
-{
+void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
avl_node_t *node;
node = avl_search_closest_smaller_node(tree, data);
return node ? node->data : NULL;
}
-void *avl_search_closest_greater(const avl_tree_t *tree, const void *data)
-{
+void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
avl_node_t *node;
node = avl_search_closest_greater_node(tree, data);
return node ? node->data : NULL;
}
-avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data)
-{
+avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
avl_node_t *node;
int result;
}
avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
- int *result)
-{
+ int *result) {
avl_node_t *node;
int c;
node = tree->root;
if(!node) {
- if(result)
+ if(result) {
*result = 0;
+ }
+
return NULL;
}
c = tree->compare(data, node->data);
if(c < 0) {
- if(node->left)
+ if(node->left) {
node = node->left;
- else {
- if(result)
+ } else {
+ if(result) {
*result = -1;
+ }
+
break;
}
} else if(c > 0) {
- if(node->right)
+ if(node->right) {
node = node->right;
- else {
- if(result)
+ } else {
+ if(result) {
*result = 1;
+ }
+
break;
}
} else {
- if(result)
+ if(result) {
*result = 0;
+ }
+
break;
}
}
}
avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
- const void *data)
-{
+ const void *data) {
avl_node_t *node;
int result;
node = avl_search_closest_node(tree, data, &result);
- if(result < 0)
+ if(result < 0) {
node = node->prev;
+ }
return node;
}
avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
- const void *data)
-{
+ const void *data) {
avl_node_t *node;
int result;
node = avl_search_closest_node(tree, data, &result);
- if(result > 0)
+ if(result > 0) {
node = node->next;
+ }
return node;
}
/* Insertion and deletion */
-avl_node_t *avl_insert(avl_tree_t *tree, void *data)
-{
+avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
avl_node_t *closest, *new;
int result;
} else {
closest = avl_search_closest_node(tree, data, &result);
- switch (result) {
- case -1:
- new = avl_alloc_node();
- new->data = data;
- avl_insert_before(tree, closest, new);
- break;
+ switch(result) {
+ case -1:
+ new = avl_alloc_node();
+ new->data = data;
+ avl_insert_before(tree, closest, new);
+ break;
- case 1:
- new = avl_alloc_node();
- new->data = data;
- avl_insert_after(tree, closest, new);
- break;
+ case 1:
+ new = avl_alloc_node();
+ new->data = data;
+ avl_insert_after(tree, closest, new);
+ break;
- default:
- return NULL;
+ default:
+ return NULL;
}
}
return new;
}
-avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node)
-{
+avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
avl_node_t *closest;
int result;
- if(!tree->root)
+ if(!tree->root) {
avl_insert_top(tree, node);
- else {
+ } else {
closest = avl_search_closest_node(tree, node->data, &result);
- switch (result) {
- case -1:
- avl_insert_before(tree, closest, node);
- break;
+ switch(result) {
+ case -1:
+ avl_insert_before(tree, closest, node);
+ break;
- case 1:
- avl_insert_after(tree, closest, node);
- break;
+ case 1:
+ avl_insert_after(tree, closest, node);
+ break;
- case 0:
- return NULL;
+ case 0:
+ return NULL;
}
}
return node;
}
-void avl_insert_top(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
node->prev = node->next = node->parent = NULL;
tree->head = tree->tail = tree->root = node;
}
void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
- avl_node_t *node)
-{
+ avl_node_t *node) {
if(!before) {
- if(tree->tail)
+ if(tree->tail) {
avl_insert_after(tree, tree->tail, node);
- else
+ } else {
avl_insert_top(tree, node);
+ }
+
return;
}
return;
}
- if(before->prev)
+ if(before->prev) {
before->prev->next = node;
- else
+ } else {
tree->head = node;
+ }
before->prev = node;
before->left = node;
avl_rebalance(tree, before);
}
-void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
-{
+void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
if(!after) {
- if(tree->head)
+ if(tree->head) {
avl_insert_before(tree, tree->head, node);
- else
+ } else {
avl_insert_top(tree, node);
+ }
+
return;
}
node->parent = after;
node->next = after->next;
- if(after->next)
+ if(after->next) {
after->next->prev = node;
- else
+ } else {
tree->tail = node;
+ }
after->next = node;
after->right = node;
avl_rebalance(tree, after);
}
-avl_node_t *avl_unlink(avl_tree_t *tree, void *data)
-{
+avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
avl_node_t *node;
node = avl_search_node(tree, data);
- if(node)
+ if(node) {
avl_unlink_node(tree, node);
+ }
return node;
}
-void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
avl_node_t *parent;
avl_node_t **superparent;
avl_node_t *subst, *left, *right;
avl_node_t *balnode;
- if(node->prev)
+ if(node->prev) {
node->prev->next = node->next;
- else
+ } else {
tree->head = node->next;
- if(node->next)
+ }
+
+ if(node->next) {
node->next->prev = node->prev;
- else
+ } else {
tree->tail = node->prev;
+ }
parent = node->parent;
superparent =
- parent ? node ==
- parent->left ? &parent->left : &parent->right : &tree->root;
+ parent ? node ==
+ parent->left ? &parent->left : &parent->right : &tree->root;
left = node->left;
right = node->right;
+
if(!left) {
*superparent = right;
- if(right)
+ if(right) {
right->parent = parent;
+ }
balnode = parent;
} else if(!right) {
balnode = parent;
} else {
subst = node->prev;
- if(!subst) // This only happens if node is not actually in a tree at all.
+
+ if(!subst) { // This only happens if node is not actually in a tree at all.
abort();
+ }
if(subst == left) {
balnode = subst;
balnode = subst->parent;
balnode->right = subst->left;
- if(balnode->right)
+ if(balnode->right) {
balnode->right->parent = balnode;
+ }
subst->left = left;
left->parent = subst;
#endif
}
-void avl_delete_node(avl_tree_t *tree, avl_node_t *node)
-{
+void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
avl_unlink_node(tree, node);
avl_free_node(tree, node);
}
-void avl_delete(avl_tree_t *tree, void *data)
-{
+void avl_delete(avl_tree_t *tree, void *data) {
avl_node_t *node;
node = avl_search_node(tree, data);
- if(node)
+ if(node) {
avl_delete_node(tree, node);
+ }
}
/* Fast tree cleanup */
-void avl_delete_tree(avl_tree_t *tree)
-{
+void avl_delete_tree(avl_tree_t *tree) {
avl_node_t *node, *next;
for(node = tree->head; node; node = next) {
/* Tree walking */
-void avl_foreach(const avl_tree_t *tree, avl_action_t action)
-{
+void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
avl_node_t *node, *next;
for(node = tree->head; node; node = next) {
}
}
-void avl_foreach_node(const avl_tree_t *tree, avl_action_t action)
-{
+void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
avl_node_t *node, *next;
for(node = tree->head; node; node = next) {
/* Indexing */
#ifdef AVL_COUNT
-unsigned int avl_count(const avl_tree_t *tree)
-{
+unsigned int avl_count(const avl_tree_t *tree) {
return AVL_NODE_COUNT(tree->root);
}
-avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index)
-{
+avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
avl_node_t *node;
unsigned int c;
return NULL;
}
-unsigned int avl_index(const avl_node_t *node)
-{
+unsigned int avl_index(const avl_node_t *node) {
avl_node_t *next;
unsigned int index;
index = AVL_L_COUNT(node);
while((next = node->parent)) {
- if(node == next->right)
+ if(node == next->right) {
index += AVL_L_COUNT(next) + 1;
+ }
+
node = next;
}
}
#endif
#ifdef AVL_DEPTH
-unsigned int avl_depth(const avl_tree_t *tree)
-{
+unsigned int avl_depth(const avl_tree_t *tree) {
return AVL_NODE_DEPTH(tree->root);
}
#endif