mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-11 22:15:14 +00:00
be384c6354
This is an import of the old ul2tree code as well as required bitops. All of them will have to be refreshed at one moment.
732 lines
22 KiB
C
732 lines
22 KiB
C
/*
|
|
* tree.h : tree manipulation macros and structures.
|
|
* (C) 2002 - Willy Tarreau - willy@ant-computing.com
|
|
*
|
|
*/
|
|
|
|
#ifndef __TREE_H__
|
|
#define __TREE_H__
|
|
|
|
#include <import/bitops.h>
|
|
#include <common/memory.h>
|
|
|
|
/* binary tree node : either 32 bits unsigned long int values, or
|
|
* 64 bits in two 32 bits unsigned long int values
|
|
*/
|
|
struct ultree {
|
|
unsigned long low; /* 32 bits low value of this node */
|
|
unsigned long high; /* 32 bits high value of this node, not used in 32 bits */
|
|
int level; /* bit level of this node */
|
|
void *data; /* carried data */
|
|
struct ultree *left, *right; /* children : left and right. NULL = leaf */
|
|
struct ultree *up; /* parent node. NULL = root */
|
|
};
|
|
|
|
/* binary tree node : 64 bits unsigned long long values */
|
|
struct ulltree {
|
|
unsigned long long value; /* 64 bits value of this node */
|
|
int level; /* bit level of this node */
|
|
void *data; /* carried data */
|
|
struct ulltree *left, *right; /* children : left and right. NULL = leaf */
|
|
struct ulltree *up; /* parent node. NULL = root */
|
|
};
|
|
|
|
/* binary tree node : 64 bits in either one ull or two 32 bits unsigned long int values. This
|
|
* is the common type for all the above trees, which should be cast into it. This makes
|
|
* pool_free() far simpler since all types share a same pool.
|
|
*/
|
|
struct tree64 {
|
|
union {
|
|
struct {
|
|
unsigned long low; /* 32 bits low value of this node */
|
|
unsigned long high; /* 32 bits high value of this node */
|
|
} ul;
|
|
struct {
|
|
unsigned long long value; /* 64 bits value of this node */
|
|
} ull;
|
|
} value;
|
|
int level; /* bit level of this node */
|
|
void *data; /* carried data */
|
|
struct tree64 *left, *right; /* children : left and right. NULL = leaf */
|
|
struct tree64 *up; /* parent node. NULL = root */
|
|
};
|
|
|
|
#define sizeof_tree64 (sizeof (struct tree64))
|
|
extern void **pool_tree64;
|
|
|
|
static int node_right_lookup, node_lookup;
|
|
|
|
#define ULTREE_HEAD(l) struct ultree (l) = { .left=NULL, .right=NULL, .up=NULL, .low=0, .level=LONGBITS, .data=NULL }
|
|
#define ULTREE_INIT(l) { (l)->data = (l)->left = (l)->right = NULL; }
|
|
#define ULTREE_INIT_ROOT(l) { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->low=0; (l)->level=LONGBITS; }
|
|
|
|
#define ULLTREE_HEAD(l) struct ulltree (l) = { .left=NULL, .right=NULL, .up=NULL, .value=0, .level=LLONGBITS, .data=NULL }
|
|
#define ULLTREE_INIT(l) { (l)->data = (l)->left = (l)->right = NULL; }
|
|
#define ULLTREE_INIT_ROOT(l) { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->value=0; (l)->level=LLONGBITS; }
|
|
|
|
#define UL2TREE_HEAD(l) struct ultree (l) = { .left=NULL, .right=NULL, .up=NULL, .high=0, .low=0, .level=LLONGBITS, .data=NULL }
|
|
#define UL2TREE_INIT(l) { (l)->left = (l)->right = (l)->data = NULL; }
|
|
#define UL2TREE_INIT_ROOT(l) { (l)->left=(l)->right=(l)->up=(l)->data=NULL; (l)->high=(l)->low=0; (l)->level=LLONGBITS; }
|
|
|
|
/*
|
|
* inserts necessary nodes to reach <x> in tree starting at <root>. The node
|
|
* is not created if it exists. It is returned.
|
|
*/
|
|
inline static struct ulltree *__ulltree_insert(struct ulltree *root, unsigned long long x) {
|
|
int m;
|
|
struct ulltree *next, *new, *node;
|
|
struct ulltree **branch;
|
|
int ffs;
|
|
|
|
next = root;
|
|
ffs = ffs_fast64(x);
|
|
|
|
do {
|
|
root = next;
|
|
|
|
if (x == next->value) {
|
|
return next;
|
|
}
|
|
|
|
if (x & (1ULL << (next->level - 1))) { /* right branch */
|
|
branch = &next->right;
|
|
next = *branch;
|
|
} else {
|
|
branch = &next->left;
|
|
next = *branch;
|
|
}
|
|
|
|
if (next == NULL) {
|
|
/* we'll have to insert our node here */
|
|
*branch = new = (struct ulltree *)pool_alloc(tree64);
|
|
ULLTREE_INIT(new);
|
|
new->up = root;
|
|
new->value = x;
|
|
new->level = ffs;
|
|
return new;
|
|
}
|
|
|
|
/* we'll keep walking down as long as we have all bits in common */
|
|
} while ((x & ~((1ULL << next->level) - 1)) == next->value);
|
|
|
|
|
|
/* ok, now we know that we must insert between both. */
|
|
|
|
/* the new interconnect node */
|
|
*branch = node = (struct ulltree *)pool_alloc(tree64); /* was <next> */
|
|
ULLTREE_INIT(node);
|
|
node->up = root;
|
|
next->up = node;
|
|
|
|
/* we need the common higher bits between x and next->value. */
|
|
|
|
/* what differences are there between x and the node here ?
|
|
* NOTE that m is always < level(parent) because highest bit
|
|
* of x and next-value are identical here (else they would be
|
|
* on a different branch).
|
|
*/
|
|
m = fls_fast64(x ^ next->value) + 1; /* m = lowest identical bit */
|
|
node->value = x & ~((1ULL << m) - 1); /* value of common bits */
|
|
|
|
if (node->value == x) { /* <x> is exactly on this node */
|
|
/* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
|
|
node->level = ffs;
|
|
|
|
if (next->value & (1ULL << (node->level - 1))) /* right branch */
|
|
node->right = next;
|
|
else
|
|
node->left = next;
|
|
return node;
|
|
}
|
|
|
|
/* the new leaf now */
|
|
node->level = m; /* set the level to the lowest common bit */
|
|
new = (struct ulltree *)pool_alloc(tree64);
|
|
ULLTREE_INIT(new);
|
|
new->value = x;
|
|
new->level = ffs;
|
|
|
|
if (x > next->value) {
|
|
node->left = next;
|
|
node->right = new;
|
|
}
|
|
else {
|
|
node->left = new;
|
|
node->right = next;
|
|
}
|
|
new->up = node;
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* inserts necessary nodes to reach <x> in tree starting at <root>. The node
|
|
* is not created if it exists. It is returned.
|
|
*/
|
|
inline static struct ultree *__ultree_insert(struct ultree *root, unsigned long x) {
|
|
int m;
|
|
struct ultree *next, *new, *node;
|
|
struct ultree **branch;
|
|
int ffs;
|
|
|
|
next = root;
|
|
ffs = ffs_fast32(x);
|
|
|
|
do {
|
|
root = next;
|
|
|
|
if (x == next->low) {
|
|
return next;
|
|
}
|
|
|
|
if ((x >> (next->level - 1)) & 1) { /* right branch */
|
|
branch = &next->right;
|
|
next = *branch;
|
|
} else {
|
|
branch = &next->left;
|
|
next = *branch;
|
|
}
|
|
|
|
if (next == NULL) {
|
|
/* we'll have to insert our node here */
|
|
*branch = new = (struct ultree *)pool_alloc(tree64);
|
|
ULTREE_INIT(new);
|
|
new->up = root;
|
|
new->low = x;
|
|
new->level = ffs;
|
|
return new;
|
|
}
|
|
|
|
/* we'll keep walking down as long as we have all bits in common */
|
|
} while ((x & ~((1 << next->level) - 1)) == next->low);
|
|
|
|
/* ok, now we know that we must insert between both. */
|
|
|
|
/* the new interconnect node */
|
|
*branch = node = (struct ultree *)pool_alloc(tree64); /* was <next> */
|
|
ULTREE_INIT(node);
|
|
node->up = root;
|
|
next->up = node;
|
|
|
|
/* we need the common higher bits between x and next->low. */
|
|
|
|
/* what differences are there between x and the node here ?
|
|
* NOTE that m is always < level(parent) because highest bit
|
|
* of x and next->low are identical here (else they would be
|
|
* on a different branch).
|
|
*/
|
|
m = fls_fast32(x ^ next->low) + 1; /* m = lower identical bit */
|
|
node->low = x & ~((1 << m) - 1); /* value of common bits */
|
|
|
|
if (node->low == x) { /* <x> is exactly on this node */
|
|
/* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
|
|
node->level = ffs;
|
|
|
|
if (next->low & (1 << (node->level - 1))) /* right branch */
|
|
node->right = next;
|
|
else
|
|
node->left = next;
|
|
return node;
|
|
}
|
|
|
|
/* the new leaf now */
|
|
node->level = m; /* set the level to the lowest common bit */
|
|
new = (struct ultree *)pool_alloc(tree64);
|
|
ULTREE_INIT(new);
|
|
new->low = x;
|
|
new->level = ffs;
|
|
|
|
if (x > next->low) {
|
|
node->left = next;
|
|
node->right = new;
|
|
}
|
|
else {
|
|
node->left = new;
|
|
node->right = next;
|
|
}
|
|
new->up = node;
|
|
return new;
|
|
}
|
|
|
|
|
|
/*
|
|
* inserts necessary nodes to reach <h:l> in tree starting at <root>. The node
|
|
* is not created if it exists. It is returned.
|
|
*/
|
|
inline static struct ultree *__ul2tree_insert(struct ultree *root, unsigned long h, unsigned long l) {
|
|
int m;
|
|
struct ultree *next, *new, *node;
|
|
struct ultree **branch;
|
|
|
|
next = root;
|
|
|
|
do {
|
|
root = next;
|
|
|
|
if (h == next->high && l == next->low) {
|
|
return next;
|
|
}
|
|
|
|
branch = &next->left;
|
|
if (next->level >= 33) {
|
|
if ((h >> (next->level - 33)) & 1) { /* right branch */
|
|
branch = &next->right;
|
|
node_right_lookup++;
|
|
}
|
|
}
|
|
else {
|
|
if ((l >> (next->level - 1)) & 1) { /* right branch */
|
|
branch = &next->right;
|
|
node_right_lookup++;
|
|
}
|
|
}
|
|
next = *branch;
|
|
|
|
node_lookup++;
|
|
if (next == NULL) {
|
|
/* we'll have to insert our node here */
|
|
*branch = new =(struct ultree *)pool_alloc(tree64);
|
|
UL2TREE_INIT(new);
|
|
new->up = root;
|
|
new->high = h;
|
|
new->low = l;
|
|
if (l)
|
|
new->level = __ffs_fast32(l);
|
|
else
|
|
new->level = __ffs_fast32(h) + 32;
|
|
|
|
return new;
|
|
}
|
|
|
|
/* we'll keep walking down as long as we have all bits in common */
|
|
if (next->level >= 32) {
|
|
if ((h & ~((1 << (next->level-32)) - 1)) != next->high)
|
|
break;
|
|
}
|
|
else {
|
|
if (h != next->high)
|
|
break;
|
|
if ((l & ~((1 << next->level) - 1)) != next->low)
|
|
break;
|
|
}
|
|
} while (1);
|
|
|
|
/* ok, now we know that we must insert between both. */
|
|
|
|
/* the new interconnect node */
|
|
*branch = node = (struct ultree *)pool_alloc(tree64); /* was <next> */
|
|
UL2TREE_INIT(node);
|
|
node->up = root;
|
|
next->up = node;
|
|
|
|
/* we need the common higher bits between x and next->high:low. */
|
|
|
|
/* what differences are there between x and the node here ?
|
|
* NOTE that m is always < level(parent) because highest bit
|
|
* of x and next->high:low are identical here (else they would be
|
|
* on a different branch).
|
|
*/
|
|
if (h != next->high) {
|
|
m = fls_fast32(h ^ next->high) + 1; /* m = lower identical bit */
|
|
node->high = h & ~((1 << m) - 1); /* value of common bits */
|
|
m += 32;
|
|
node->low = 0;
|
|
} else {
|
|
node->high = h;
|
|
m = fls_fast32(l ^ next->low) + 1; /* m = lower identical bit */
|
|
node->low = l & ~((1 << m) - 1); /* value of common bits */
|
|
}
|
|
|
|
if (node->high == h && node->low == l) { /* <h:l> is exactly on this node */
|
|
/* we must set its real position (eg: 8,10 => m=1 => val=8, m=3)*/
|
|
if (l) {
|
|
node->level = ffs_fast32(l);
|
|
if (next->low & (1 << (node->level - 1))) /* right branch */
|
|
node->right = next;
|
|
else
|
|
node->left = next;
|
|
}
|
|
else {
|
|
node->level = ffs_fast32(h) + 32;
|
|
if (next->high & (1 << (node->level - 33))) /* right branch */
|
|
node->right = next;
|
|
else
|
|
node->left = next;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
/* the new leaf now */
|
|
node->level = m; /* set the level to the lowest common bit */
|
|
new = (struct ultree *)pool_alloc(tree64);
|
|
UL2TREE_INIT(new);
|
|
new->high = h;
|
|
new->low = l;
|
|
if (l)
|
|
new->level = __ffs_fast32(l);
|
|
else
|
|
new->level = __ffs_fast32(h) + 32;
|
|
|
|
if (h > next->high || (h == next->high && l > next->low)) {
|
|
node->left = next;
|
|
node->right = new;
|
|
}
|
|
else {
|
|
node->left = new;
|
|
node->right = next;
|
|
}
|
|
new->up = node;
|
|
return new;
|
|
}
|
|
|
|
|
|
/*
|
|
* finds a value in the tree <root>. If it cannot be found, NULL is returned.
|
|
*/
|
|
inline static struct ultree *__ultree_find(struct ultree *root, unsigned long x) {
|
|
do {
|
|
if (x == root->low)
|
|
return root;
|
|
|
|
if ((x >> (root->level - 1)) & 1)
|
|
root = root->right;
|
|
else
|
|
root = root->left;
|
|
|
|
if (root == NULL)
|
|
return NULL;
|
|
|
|
/* we'll keep walking down as long as we have all bits in common */
|
|
} while ((x & ~((1 << root->level) - 1)) == root->low);
|
|
|
|
/* should be there, but nothing. */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* finds a value in the tree <root>. If it cannot be found, NULL is returned.
|
|
*/
|
|
inline static struct ulltree *__ulltree_find(struct ulltree *root, unsigned long long x) {
|
|
do {
|
|
if (x == root->value)
|
|
return root;
|
|
|
|
if ((x >> (root->level - 1)) & 1)
|
|
root = root->right;
|
|
else
|
|
root = root->left;
|
|
|
|
if (root == NULL)
|
|
return NULL;
|
|
|
|
/* we'll keep walking down as long as we have all bits in common */
|
|
} while ((x & ~((1ULL << root->level) - 1)) == root->value);
|
|
|
|
/* should be there, but nothing. */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* walks down the tree <__root> and assigns each of its data to <__data>.
|
|
* <__stack> is an int array of at least N entries where N is the maximum number
|
|
* of levels of the tree. <__slen> is an integer variable used as a stack index.
|
|
* The instruction following the foreach statement is executed for each data,
|
|
* after the data has been unlinked from the tree.
|
|
* The nodes are deleted automatically, so it is illegal to manually delete a
|
|
* node within this loop.
|
|
*/
|
|
#define tree64_foreach_destructive(__root, __data, __stack, __slen) \
|
|
for (__slen = 0, __stack[0] = __root, __data = NULL; ({ \
|
|
__label__ __left, __right, __again, __end; \
|
|
typeof(__root) __ptr = __stack[__slen]; \
|
|
__again: \
|
|
__data = __ptr->data; \
|
|
if (__data != NULL) { \
|
|
__ptr->data = NULL; \
|
|
goto __end; \
|
|
} \
|
|
else if (__ptr->left != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->left; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__left: \
|
|
if (__ptr->right != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->right; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__right: \
|
|
if (!__slen--) \
|
|
goto __end; /* nothing left, don't delete the root node */ \
|
|
else { \
|
|
typeof (__root) __old; \
|
|
pool_free(tree64, __ptr); \
|
|
__old = __ptr; \
|
|
__ptr = __stack[__slen]; \
|
|
if (__ptr->left == __old) { \
|
|
/* unlink this node from its parent */ \
|
|
__ptr->left = NULL; \
|
|
goto __left; \
|
|
} \
|
|
else { \
|
|
/* no need to unlink, the parent will also die */ \
|
|
goto __right; \
|
|
} \
|
|
} \
|
|
__end: \
|
|
(__slen >= 0); /* nothing after loop */}); )
|
|
|
|
|
|
/*
|
|
* walks down the tree <__root> of type <__type> and assigns each of its data
|
|
* to <__data>. <__stack> is an int array of at least N entries where N is the
|
|
* maximum number of levels of the tree. <__slen> is an integer variable used
|
|
* as a stack index. The instruction following the foreach statement is
|
|
* executed for each data, after the data has been unlinked from the tree.
|
|
*/
|
|
#define tree_foreach_destructive(__type, __root, __data, __stack, __slen) \
|
|
for (__slen = 0, __stack[0] = __root, __data = NULL; ({ \
|
|
__label__ __left, __right, __again, __end; \
|
|
typeof(__root) __ptr = __stack[__slen]; \
|
|
__again: \
|
|
__data = __ptr->data; \
|
|
if (__data != NULL) { \
|
|
__ptr->data = NULL; \
|
|
goto __end; \
|
|
} \
|
|
else if (__ptr->left != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->left; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__left: \
|
|
if (__ptr->right != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->right; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__right: \
|
|
if (!__slen--) \
|
|
goto __end; /* nothing left, don't delete the root node */ \
|
|
else { \
|
|
typeof (__root) __old; \
|
|
pool_free(__type, __ptr); \
|
|
__old = __ptr; \
|
|
__ptr = __stack[__slen]; \
|
|
if (__ptr->left == __old) { \
|
|
/* unlink this node from its parent */ \
|
|
__ptr->left = NULL; \
|
|
goto __left; \
|
|
} \
|
|
else { \
|
|
/* no need to unlink, the parent will also die */ \
|
|
goto __right; \
|
|
} \
|
|
} \
|
|
__end: \
|
|
(__slen >= 0); /* nothing after loop */}); )
|
|
|
|
|
|
/*
|
|
* walks down the tree <__root> and assigns <__data> a pointer to each of its
|
|
* data pointers. <__stack> is an int array of at least N entries where N is the
|
|
* maximum number of levels of the tree. <__slen> is an integer variable used as
|
|
* a stack index. The instruction following the foreach statement is executed
|
|
* for each data.
|
|
* The tree will walk down only when the data field is empty (NULL), so it
|
|
* allows inner breaks, and will restart without losing items. The nodes data
|
|
* will be set to NULL after the inner code, or when the inner code does
|
|
* '__stack[__slen]->data = NULL';
|
|
* The nodes are deleted automatically, so it is illegal to manually delete a
|
|
* node within this loop.
|
|
*/
|
|
#define tree64_foreach(__root, __data, __stack, __slen) \
|
|
for (__slen = 0, __stack[0] = __root, __data = NULL; ({ \
|
|
__label__ __left, __right, __again, __end; \
|
|
typeof(__root) __ptr = __stack[__slen]; \
|
|
__again: \
|
|
if (__ptr->data != NULL) { \
|
|
__data = __ptr->data; \
|
|
goto __end; \
|
|
} \
|
|
else if (__ptr->left != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->left; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__left: \
|
|
if (__ptr->right != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->right; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__right: \
|
|
if (!__slen--) \
|
|
goto __end; /* nothing left, don't delete the root node */ \
|
|
else { \
|
|
typeof (__root) __old; \
|
|
pool_free(tree64, __ptr); \
|
|
__old = __ptr; \
|
|
__ptr = __stack[__slen]; \
|
|
if (__ptr->left == __old) { \
|
|
/* unlink this node from its parent */ \
|
|
__ptr->left = NULL; \
|
|
goto __left; \
|
|
} \
|
|
else { \
|
|
/* no need to unlink, the parent will also die */ \
|
|
goto __right; \
|
|
} \
|
|
} \
|
|
__end: \
|
|
(__slen >= 0); }); ((typeof(__root))__stack[__slen])->data = NULL)
|
|
|
|
|
|
|
|
/*
|
|
* walks down the tree <__root> and assigns <__node> to each of its nodes.
|
|
* <__stack> is an int array of at least N entries where N is the
|
|
* maximum number of levels of the tree. <__slen> is an integer variable used as
|
|
* a stack index. The instruction following the foreach statement is executed
|
|
* for each node.
|
|
* The tree will walk down only when the data field is empty (NULL), so it
|
|
* allows inner breaks, and will restart without losing items. The nodes data
|
|
* will be set to NULL after the inner code, or when the inner code does
|
|
* '__node->data = NULL';
|
|
* The nodes are deleted automatically, so it is illegal to manually delete a
|
|
* node within this loop.
|
|
*/
|
|
#define tree64_foreach_node(__root, __node, __stack, __slen) \
|
|
for (__slen = 0, __stack[0] = __root; ({ \
|
|
__label__ __left, __right, __again, __end; \
|
|
typeof(__root) __ptr = __stack[__slen]; \
|
|
__again: \
|
|
if (__ptr->data != NULL) { \
|
|
__node = __ptr; \
|
|
goto __end; \
|
|
} \
|
|
else if (__ptr->left != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->left; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__left: \
|
|
if (__ptr->right != NULL) { \
|
|
__stack[++__slen] = __ptr = __ptr->right; \
|
|
goto __again; \
|
|
} \
|
|
else \
|
|
__right: \
|
|
if (!__slen--) \
|
|
goto __end; /* nothing left, don't delete the root node */ \
|
|
else { \
|
|
typeof (__root) __old; \
|
|
pool_free(tree64, __ptr); \
|
|
__old = __ptr; \
|
|
__ptr = __stack[__slen]; \
|
|
if (__ptr->left == __old) { \
|
|
/* unlink this node from its parent */ \
|
|
__ptr->left = NULL; \
|
|
goto __left; \
|
|
} \
|
|
else { \
|
|
/* no need to unlink, the parent will also die */ \
|
|
goto __right; \
|
|
} \
|
|
} \
|
|
__end: \
|
|
(__slen >= 0); }); ((typeof(__root))__stack[__slen])->data = NULL)
|
|
|
|
|
|
/*
|
|
* removes the current node if possible, and its parent if it doesn't handle
|
|
* data. A pointer to the parent or grandparent is returned (the parent of the
|
|
* last one deleted in fact). This function should be compatible with any
|
|
* tree struct because of the void types.
|
|
* WARNING : never call it from within a tree_foreach() because this last one
|
|
* uses a stack which will not be updated.
|
|
*/
|
|
|
|
inline static void *__tree_delete_only_one(void *firstnode) {
|
|
struct tree64 *down, **uplink;
|
|
struct tree64 *node = firstnode;
|
|
|
|
/* don't kill the root or a populated link */
|
|
if (node->data || node->up == NULL)
|
|
return node;
|
|
if (node->left && node->right)
|
|
return node;
|
|
/* since we know that at least left or right is null, we can do arithmetics on them */
|
|
down = (void *)((long)node->left | (long)node->right);
|
|
/* find where we are linked */
|
|
if (node == node->up->left)
|
|
uplink = &node->up->left;
|
|
else
|
|
uplink = &node->up->right;
|
|
|
|
*uplink = down; /* we relink the lower branch above us or simply cut it */
|
|
if (down) {
|
|
down->up = node->up;
|
|
/* we know that we cannot do more because we kept one branch */
|
|
}
|
|
else {
|
|
/* we'll redo this once for the node above us because there was no branch below us,
|
|
* so maybe it doesn't need to exist for only one branch
|
|
*/
|
|
down = node;
|
|
node = node->up;
|
|
pool_free(tree64, down);
|
|
if (node->data || node->up == NULL)
|
|
return node;
|
|
/* now we're sure we were sharing this empty node with another branch, let's find it */
|
|
down = (void *)((long)node->left | (long)node->right);
|
|
if (node == node->up->left)
|
|
uplink = &node->up->left;
|
|
else
|
|
uplink = &node->up->right;
|
|
*uplink = down; /* we relink the lower branch above */
|
|
down->up = node->up;
|
|
}
|
|
/* free the last node */
|
|
pool_free(tree64, node);
|
|
return down->up;
|
|
}
|
|
|
|
/*
|
|
* removes the current node if possible, and all of its parents which do not
|
|
* carry data. A pointer to the parent of the last one deleted is returned.
|
|
* This function should be compatible with any tree struct because of the void
|
|
* types.
|
|
* WARNING : never call it from within a tree_foreach() because this last one
|
|
* uses a stack which will not be updated.
|
|
*/
|
|
|
|
inline static void *__tree_delete(void *firstnode) {
|
|
struct tree64 *down, **uplink, *up;
|
|
struct tree64 *node = firstnode;
|
|
|
|
while (1) {
|
|
/* don't kill the root or a populated link */
|
|
if (node->data || (up = node->up) == NULL)
|
|
return node;
|
|
if (node->left && node->right)
|
|
return node;
|
|
/* since we know that at least left or right is null, we can do arithmetics on them */
|
|
down = (void *)((long)node->left | (long)node->right);
|
|
/* find where we are linked */
|
|
if (node == up->left)
|
|
uplink = &up->left;
|
|
else
|
|
uplink = &up->right;
|
|
|
|
*uplink = down; /* we relink the lower branch above us or simply cut it */
|
|
pool_free(tree64, node);
|
|
node = up;
|
|
if (down)
|
|
down->up = node;
|
|
}
|
|
}
|
|
|
|
#endif /* __TREE_H__ */
|