From: Ruben Kerkhof Date: Thu, 3 Mar 2016 21:16:10 +0000 (+0100) Subject: Merge branch 'collectd-5.4' into collectd-5.5 X-Git-Tag: collectd-5.5.2~40 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=2bda2a5648c87a2c5b8304238cd80ff17984c5cd;p=collectd.git Merge branch 'collectd-5.4' into collectd-5.5 --- 2bda2a5648c87a2c5b8304238cd80ff17984c5cd diff --cc src/daemon/utils_avltree.c index 58b8b847,00000000..fcfbb945 mode 100644,000000..100644 --- a/src/daemon/utils_avltree.c +++ b/src/daemon/utils_avltree.c @@@ -1,745 -1,0 +1,745 @@@ +/** + * collectd - src/utils_avltree.c + * Copyright (C) 2006,2007 Florian octo Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#include "config.h" + +#include +#include +#include +#include + +#include "utils_avltree.h" + +#define BALANCE(n) ((((n)->left == NULL) ? 0 : (n)->left->height) \ + - (((n)->right == NULL) ? 0 : (n)->right->height)) + +/* + * private data types + */ +struct c_avl_node_s +{ + void *key; + void *value; + + int height; + struct c_avl_node_s *left; + struct c_avl_node_s *right; + struct c_avl_node_s *parent; +}; +typedef struct c_avl_node_s c_avl_node_t; + +struct c_avl_tree_s +{ + c_avl_node_t *root; + int (*compare) (const void *, const void *); + int size; +}; + +struct c_avl_iterator_s +{ + c_avl_tree_t *tree; + c_avl_node_t *node; +}; + +/* + * private functions + */ +#if 0 +static void verify_tree (c_avl_node_t *n) +{ + if (n == NULL) + return; + + verify_tree (n->left); + verify_tree (n->right); + + assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1)); + assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n)); +} /* void verify_tree */ +#else +# define verify_tree(n) /**/ +#endif + +static void free_node (c_avl_node_t *n) +{ + if (n == NULL) + return; + + if (n->left != NULL) + free_node (n->left); + if (n->right != NULL) + free_node (n->right); + + free (n); +} + +static int calc_height (c_avl_node_t *n) +{ + int height_left; + int height_right; + + if (n == NULL) + return (0); + + height_left = (n->left == NULL) ? 0 : n->left->height; + height_right = (n->right == NULL) ? 0 : n->right->height; + + return (((height_left > height_right) + ? height_left + : height_right) + 1); +} /* int calc_height */ + +static c_avl_node_t *search (c_avl_tree_t *t, const void *key) +{ + c_avl_node_t *n; + int cmp; + + n = t->root; + while (n != NULL) + { + cmp = t->compare (key, n->key); + if (cmp == 0) + return (n); + else if (cmp < 0) + n = n->left; + else + n = n->right; + } + + return (NULL); +} + +/* (x) (y) + * / \ / \ + * (y) /\ /\ (x) + * / \ /_c\ ==> / a\ / \ + * /\ /\ /____\/\ /\ + * / a\ /_b\ /_b\ /_c\ + * /____\ + */ +static c_avl_node_t *rotate_right (c_avl_tree_t *t, c_avl_node_t *x) +{ + c_avl_node_t *p; + c_avl_node_t *y; + c_avl_node_t *b; + + assert (x != NULL); + assert (x->left != NULL); + + p = x->parent; + y = x->left; + b = y->right; + + x->left = b; + if (b != NULL) + b->parent = x; + + x->parent = y; + y->right = x; + + y->parent = p; + assert ((p == NULL) || (p->left == x) || (p->right == x)); + if (p == NULL) + t->root = y; + else if (p->left == x) + p->left = y; + else + p->right = y; + + x->height = calc_height (x); + y->height = calc_height (y); + + return (y); +} /* void rotate_right */ + +/* + * (x) (y) + * / \ / \ + * /\ (y) (x) /\ + * /_a\ / \ ==> / \ / c\ + * /\ /\ /\ /\/____\ + * /_b\ / c\ /_a\ /_b\ + * /____\ + */ +static c_avl_node_t *rotate_left (c_avl_tree_t *t, c_avl_node_t *x) +{ + c_avl_node_t *p; + c_avl_node_t *y; + c_avl_node_t *b; + + assert (x != NULL); + assert (x->right != NULL); + + p = x->parent; + y = x->right; + b = y->left; + + x->right = b; + if (b != NULL) + b->parent = x; + + x->parent = y; + y->left = x; + + y->parent = p; + assert ((p == NULL) || (p->left == x) || (p->right == x)); + if (p == NULL) + t->root = y; + else if (p->left == x) + p->left = y; + else + p->right = y; + + x->height = calc_height (x); + y->height = calc_height (y); + + return (y); +} /* void rotate_left */ + +static c_avl_node_t *rotate_left_right (c_avl_tree_t *t, c_avl_node_t *x) +{ + rotate_left (t, x->left); + return (rotate_right (t, x)); +} /* void rotate_left_right */ + +static c_avl_node_t *rotate_right_left (c_avl_tree_t *t, c_avl_node_t *x) +{ + rotate_right (t, x->right); + return (rotate_left (t, x)); +} /* void rotate_right_left */ + +static void rebalance (c_avl_tree_t *t, c_avl_node_t *n) +{ + int b_top; + int b_bottom; + + while (n != NULL) + { + b_top = BALANCE (n); + assert ((b_top >= -2) && (b_top <= 2)); + + if (b_top == -2) + { + assert (n->right != NULL); + b_bottom = BALANCE (n->right); - assert ((b_bottom >= -1) || (b_bottom <= 1)); ++ assert ((b_bottom >= -1) && (b_bottom <= 1)); + if (b_bottom == 1) + n = rotate_right_left (t, n); + else + n = rotate_left (t, n); + } + else if (b_top == 2) + { + assert (n->left != NULL); + b_bottom = BALANCE (n->left); - assert ((b_bottom >= -1) || (b_bottom <= 1)); ++ assert ((b_bottom >= -1) && (b_bottom <= 1)); + if (b_bottom == -1) + n = rotate_left_right (t, n); + else + n = rotate_right (t, n); + } + else + { + int height = calc_height (n); + if (height == n->height) + break; + n->height = height; + } + + assert (n->height == calc_height (n)); + + n = n->parent; + } /* while (n != NULL) */ +} /* void rebalance */ + +static c_avl_node_t *c_avl_node_next (c_avl_node_t *n) +{ + c_avl_node_t *r; /* return node */ + + if (n == NULL) + { + return (NULL); + } + + /* If we can't descent any further, we have to backtrack to the first + * parent that's bigger than we, i. e. who's _left_ child we are. */ + if (n->right == NULL) + { + r = n->parent; + while ((r != NULL) && (r->parent != NULL)) + { + if (r->left == n) + break; + n = r; + r = n->parent; + } + + /* n->right == NULL && r == NULL => t is root and has no next + * r->left != n => r->right = n => r->parent == NULL */ + if ((r == NULL) || (r->left != n)) + { + assert ((r == NULL) || (r->parent == NULL)); + return (NULL); + } + else + { + assert (r->left == n); + return (r); + } + } + else + { + r = n->right; + while (r->left != NULL) + r = r->left; + } + + return (r); +} /* c_avl_node_t *c_avl_node_next */ + +static c_avl_node_t *c_avl_node_prev (c_avl_node_t *n) +{ + c_avl_node_t *r; /* return node */ + + if (n == NULL) + { + return (NULL); + } + + /* If we can't descent any further, we have to backtrack to the first + * parent that's smaller than we, i. e. who's _right_ child we are. */ + if (n->left == NULL) + { + r = n->parent; + while ((r != NULL) && (r->parent != NULL)) + { + if (r->right == n) + break; + n = r; + r = n->parent; + } + + /* n->left == NULL && r == NULL => t is root and has no next + * r->right != n => r->left = n => r->parent == NULL */ + if ((r == NULL) || (r->right != n)) + { + assert ((r == NULL) || (r->parent == NULL)); + return (NULL); + } + else + { + assert (r->right == n); + return (r); + } + } + else + { + r = n->left; + while (r->right != NULL) + r = r->right; + } + + return (r); +} /* c_avl_node_t *c_avl_node_prev */ + +static int _remove (c_avl_tree_t *t, c_avl_node_t *n) +{ + assert ((t != NULL) && (n != NULL)); + + if ((n->left != NULL) && (n->right != NULL)) + { + c_avl_node_t *r; /* replacement node */ + if (BALANCE (n) > 0) /* left subtree is higher */ + { + assert (n->left != NULL); + r = c_avl_node_prev (n); + + } + else /* right subtree is higher */ + { + assert (n->right != NULL); + r = c_avl_node_next (n); + } + + assert ((r->left == NULL) || (r->right == NULL)); + + /* copy content */ + n->key = r->key; + n->value = r->value; + + n = r; + } + + assert ((n->left == NULL) || (n->right == NULL)); + + if ((n->left == NULL) && (n->right == NULL)) + { + /* Deleting a leave is easy */ + if (n->parent == NULL) + { + assert (t->root == n); + t->root = NULL; + } + else + { + assert ((n->parent->left == n) + || (n->parent->right == n)); + if (n->parent->left == n) + n->parent->left = NULL; + else + n->parent->right = NULL; + + rebalance (t, n->parent); + } + + free_node (n); + } + else if (n->left == NULL) + { + assert (BALANCE (n) == -1); + assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); + if (n->parent == NULL) + { + assert (t->root == n); + t->root = n->right; + } + else if (n->parent->left == n) + { + n->parent->left = n->right; + } + else + { + n->parent->right = n->right; + } + n->right->parent = n->parent; + + if (n->parent != NULL) + rebalance (t, n->parent); + + n->right = NULL; + free_node (n); + } + else if (n->right == NULL) + { + assert (BALANCE (n) == 1); + assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n)); + if (n->parent == NULL) + { + assert (t->root == n); + t->root = n->left; + } + else if (n->parent->left == n) + { + n->parent->left = n->left; + } + else + { + n->parent->right = n->left; + } + n->left->parent = n->parent; + + if (n->parent != NULL) + rebalance (t, n->parent); + + n->left = NULL; + free_node (n); + } + else + { + assert (0); + } + + return (0); +} /* void *_remove */ + +/* + * public functions + */ +c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *)) +{ + c_avl_tree_t *t; + + if (compare == NULL) + return (NULL); + + if ((t = (c_avl_tree_t *) malloc (sizeof (c_avl_tree_t))) == NULL) + return (NULL); + + t->root = NULL; + t->compare = compare; + t->size = 0; + + return (t); +} + +void c_avl_destroy (c_avl_tree_t *t) +{ + if (t == NULL) + return; + free_node (t->root); + free (t); +} + +int c_avl_insert (c_avl_tree_t *t, void *key, void *value) +{ + c_avl_node_t *new; + c_avl_node_t *nptr; + int cmp; + + if ((new = (c_avl_node_t *) malloc (sizeof (c_avl_node_t))) == NULL) + return (-1); + + new->key = key; + new->value = value; + new->height = 1; + new->left = NULL; + new->right = NULL; + + if (t->root == NULL) + { + new->parent = NULL; + t->root = new; + t->size = 1; + return (0); + } + + nptr = t->root; + while (42) + { + cmp = t->compare (nptr->key, new->key); + if (cmp == 0) + { + free_node (new); + return (1); + } + else if (cmp < 0) + { + /* nptr < new */ + if (nptr->right == NULL) + { + nptr->right = new; + new->parent = nptr; + rebalance (t, nptr); + break; + } + else + { + nptr = nptr->right; + } + } + else /* if (cmp > 0) */ + { + /* nptr > new */ + if (nptr->left == NULL) + { + nptr->left = new; + new->parent = nptr; + rebalance (t, nptr); + break; + } + else + { + nptr = nptr->left; + } + } + } /* while (42) */ + + verify_tree (t->root); + ++t->size; + return (0); +} /* int c_avl_insert */ + +int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue) +{ + c_avl_node_t *n; + int status; + + assert (t != NULL); + + n = search (t, key); + if (n == NULL) + return (-1); + + if (rkey != NULL) + *rkey = n->key; + if (rvalue != NULL) + *rvalue = n->value; + + status = _remove (t, n); + verify_tree (t->root); + --t->size; + return (status); +} /* void *c_avl_remove */ + +int c_avl_get (c_avl_tree_t *t, const void *key, void **value) +{ + c_avl_node_t *n; + + assert (t != NULL); + + n = search (t, key); + if (n == NULL) + return (-1); + + if (value != NULL) + *value = n->value; + + return (0); +} + +int c_avl_pick (c_avl_tree_t *t, void **key, void **value) +{ + c_avl_node_t *n; + c_avl_node_t *p; + + if ((key == NULL) || (value == NULL)) + return (-1); + if (t->root == NULL) + return (-1); + + n = t->root; + while ((n->left != NULL) || (n->right != NULL)) + { + if (n->left == NULL) + { + n = n->right; + continue; + } + else if (n->right == NULL) + { + n = n->left; + continue; + } + + if (n->left->height > n->right->height) + n = n->left; + else + n = n->right; + } + + p = n->parent; + if (p == NULL) + t->root = NULL; + else if (p->left == n) + p->left = NULL; + else + p->right = NULL; + + *key = n->key; + *value = n->value; + + free_node (n); + --t->size; + rebalance (t, p); + + return (0); +} /* int c_avl_pick */ + +c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t) +{ + c_avl_iterator_t *iter; + + if (t == NULL) + return (NULL); + + iter = (c_avl_iterator_t *) malloc (sizeof (c_avl_iterator_t)); + if (iter == NULL) + return (NULL); + memset (iter, '\0', sizeof (c_avl_iterator_t)); + iter->tree = t; + + return (iter); +} /* c_avl_iterator_t *c_avl_get_iterator */ + +int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value) +{ + c_avl_node_t *n; + + if ((iter == NULL) || (key == NULL) || (value == NULL)) + return (-1); + + if (iter->node == NULL) + { + for (n = iter->tree->root; n != NULL; n = n->left) + if (n->left == NULL) + break; + iter->node = n; + } + else + { + n = c_avl_node_next (iter->node); + } + + if (n == NULL) + return (-1); + + iter->node = n; + *key = n->key; + *value = n->value; + + return (0); +} /* int c_avl_iterator_next */ + +int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value) +{ + c_avl_node_t *n; + + if ((iter == NULL) || (key == NULL) || (value == NULL)) + return (-1); + + if (iter->node == NULL) + { + for (n = iter->tree->root; n != NULL; n = n->left) + if (n->right == NULL) + break; + iter->node = n; + } + else + { + n = c_avl_node_prev (iter->node); + } + + if (n == NULL) + return (-1); + + iter->node = n; + *key = n->key; + *value = n->value; + + return (0); +} /* int c_avl_iterator_prev */ + +void c_avl_iterator_destroy (c_avl_iterator_t *iter) +{ + free (iter); +} + +int c_avl_size (c_avl_tree_t *t) +{ + if (t == NULL) + return (0); + return (t->size); +}