2009-07-07 16:45:47 +00:00
|
|
|
|
|
|
|
#include <lighttpd/radix.h>
|
2009-05-29 13:03:19 +00:00
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
liRadixTree32 *li_radixtree32_new(guint32 root_width) {
|
2009-05-29 13:03:19 +00:00
|
|
|
guint32 i;
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixTree32 *tree = g_slice_new(liRadixTree32);
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
if (root_width == 0)
|
|
|
|
root_width = 1;
|
|
|
|
else if (root_width > 8)
|
|
|
|
root_width = 8;
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
tree->root = g_new0(liRadixNode32*, 1 << root_width);
|
2009-05-29 13:03:19 +00:00
|
|
|
tree->size = 0;
|
|
|
|
tree->root_width = root_width;
|
|
|
|
tree->root_mask = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < root_width; i++)
|
|
|
|
tree->root_mask = ~(~tree->root_mask >> 1);
|
|
|
|
|
|
|
|
return tree;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
guint li_radixtree32_free(liRadixTree32 *tree) {
|
2009-05-29 13:03:19 +00:00
|
|
|
guint32 i;
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixNode32 *node, *parent;
|
2009-05-29 13:03:19 +00:00
|
|
|
guint32 n = 0;
|
|
|
|
|
|
|
|
/* walk the tree and free every node */
|
|
|
|
for (i = 0; i < ((guint32)1 << tree->root_width); i++) {
|
|
|
|
node = tree->root[i];
|
|
|
|
|
|
|
|
while (node) {
|
|
|
|
if (node->left)
|
|
|
|
node = node->left;
|
|
|
|
else if (node->right)
|
|
|
|
node = node->right;
|
|
|
|
else {
|
|
|
|
parent = node->parent;
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
if (parent->left == node)
|
|
|
|
parent->left = NULL;
|
|
|
|
else
|
|
|
|
parent->right = NULL;
|
|
|
|
}
|
|
|
|
|
2009-07-08 19:06:07 +00:00
|
|
|
g_slice_free(liRadixNode32, node);
|
2009-05-29 13:03:19 +00:00
|
|
|
node = parent;
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(tree->root);
|
2009-07-08 19:06:07 +00:00
|
|
|
g_slice_free(liRadixTree32, tree);
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
void li_radixtree32_insert(liRadixTree32 *tree, guint32 key, guint32 mask, gpointer data) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixNode32 *last_node, *leaf;
|
|
|
|
liRadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
|
2009-07-16 10:57:11 +00:00
|
|
|
|
2009-05-29 13:03:19 +00:00
|
|
|
if (!node) {
|
|
|
|
/* no root node yet */
|
2009-07-08 19:06:07 +00:00
|
|
|
node = g_slice_new(liRadixNode32);
|
2009-05-29 13:03:19 +00:00
|
|
|
node->key = key & mask;
|
|
|
|
node->mask = mask;
|
|
|
|
node->data = data;
|
|
|
|
node->parent = NULL;
|
|
|
|
node->left = NULL;
|
|
|
|
node->right = NULL;
|
|
|
|
tree->root[(key & tree->root_mask) >> (32 - tree->root_width)] = node;
|
|
|
|
tree->size++;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-16 10:57:11 +00:00
|
|
|
do {
|
|
|
|
if ((key & mask & node->mask) != node->key) {
|
2009-05-29 13:03:19 +00:00
|
|
|
/* node key differs, split tree */
|
2009-07-16 10:57:11 +00:00
|
|
|
liRadixNode32 *new_node;
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
/* the new internal node */
|
2009-07-08 19:06:07 +00:00
|
|
|
new_node = g_slice_new(liRadixNode32);
|
2009-05-29 13:03:19 +00:00
|
|
|
new_node->data = NULL;
|
|
|
|
new_node->parent = node->parent;
|
|
|
|
new_node->mask = node->mask;
|
|
|
|
new_node->key = node->key;
|
|
|
|
|
|
|
|
node->parent = new_node;
|
|
|
|
|
|
|
|
/* the new leaf */
|
2009-07-08 19:06:07 +00:00
|
|
|
leaf = g_slice_new(liRadixNode32);
|
2009-05-29 13:03:19 +00:00
|
|
|
leaf->key = key & mask;
|
|
|
|
leaf->mask = mask;
|
|
|
|
leaf->data = data;
|
|
|
|
leaf->parent = new_node;
|
|
|
|
leaf->left = NULL;
|
|
|
|
leaf->right = NULL;
|
|
|
|
|
2009-07-16 10:57:11 +00:00
|
|
|
do {
|
2009-05-29 13:03:19 +00:00
|
|
|
new_node->mask <<= 1;
|
|
|
|
new_node->key &= new_node->mask;
|
|
|
|
} while ((key & mask & new_node->mask) != new_node->key);
|
|
|
|
|
|
|
|
if ((key & new_node->mask) > (key & (~ (~ new_node->mask >> 1)))) {
|
|
|
|
new_node->left = node;
|
|
|
|
new_node->right = leaf;
|
|
|
|
} else {
|
|
|
|
new_node->left = leaf;
|
|
|
|
new_node->right = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_node->parent) {
|
|
|
|
if (new_node->parent->left == node)
|
|
|
|
new_node->parent->left = new_node;
|
|
|
|
else
|
|
|
|
new_node->parent->right = new_node;
|
|
|
|
} else {
|
|
|
|
tree->root[(key & tree->root_mask) >> (32 - tree->root_width)] = new_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
tree->size++;
|
|
|
|
|
|
|
|
return;
|
|
|
|
} else if ((key & mask) == node->key) {
|
|
|
|
node->data = data;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_node = node;
|
|
|
|
|
|
|
|
/* compare next bit */
|
|
|
|
if ((key & node->mask) > (key & (~ (~ node->mask >> 1))))
|
|
|
|
node = node->right;
|
|
|
|
else
|
|
|
|
node = node->left;
|
|
|
|
} while (node);
|
|
|
|
|
|
|
|
/* new leaf at end of tree */
|
2009-07-08 19:06:07 +00:00
|
|
|
leaf = g_slice_new0(liRadixNode32);
|
2009-05-29 13:03:19 +00:00
|
|
|
leaf->data = data;
|
|
|
|
leaf->key = key & mask;
|
|
|
|
leaf->mask = mask;
|
|
|
|
leaf->parent = last_node;
|
|
|
|
|
|
|
|
if ((key & last_node->mask) > (key & (~ (~ last_node->mask >> 1))))
|
|
|
|
last_node->right = leaf;
|
|
|
|
else
|
|
|
|
last_node->left = leaf;
|
|
|
|
|
|
|
|
tree->size++;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gboolean li_radixtree32_remove(liRadixTree32 *tree, guint32 key, guint32 mask) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
while (node) {
|
|
|
|
if (!node->data || (key & mask) != node->key) {
|
|
|
|
/* compare next bit */
|
|
|
|
if ((key & node->mask) > (key & (~ (~ node->mask >> 1))))
|
|
|
|
node = node->right;
|
|
|
|
else
|
|
|
|
node = node->left;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!node->left && !node->right) {
|
|
|
|
/* leaf */
|
|
|
|
if (node->parent) {
|
|
|
|
if (node->parent->data) {
|
|
|
|
/* set current node to parent */
|
|
|
|
node->data = node->parent->data;
|
|
|
|
node->key = node->parent->key;
|
|
|
|
node->mask = node->parent->mask;
|
|
|
|
node->parent->data = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
/* the parent internal node has no data, we can set our sibling as the new internal node */
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixNode32 *sibling = (node->parent->left == node) ? node->parent->right : node->parent->left;
|
2009-05-29 13:03:19 +00:00
|
|
|
if (node->parent->parent) {
|
|
|
|
if (node->parent->parent->left == node->parent)
|
|
|
|
node->parent->parent->left = sibling;
|
|
|
|
else
|
|
|
|
node->parent->parent->right = sibling;
|
|
|
|
} else {
|
|
|
|
/* the parent is the tree root, set root to our sibling */
|
|
|
|
tree->root[(key & tree->root_mask) >> (32 - tree->root_width)] = sibling;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* old internal node not needed anymore */
|
|
|
|
tree->size--;
|
2009-07-08 19:06:07 +00:00
|
|
|
g_slice_free(liRadixNode32, node->parent);
|
2009-05-29 13:03:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* tree root */
|
|
|
|
tree->root[(key & tree->root_mask) >> (32 - tree->root_width)] = NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* internal node */
|
|
|
|
node->data = NULL;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
tree->size--;
|
2009-07-08 19:06:07 +00:00
|
|
|
g_slice_free(liRadixNode32, node);
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
liRadixNode32 *li_radixtree32_lookup_node(liRadixTree32 *tree, guint32 key) {
|
2009-07-08 19:06:07 +00:00
|
|
|
liRadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
|
|
|
|
liRadixNode32 *result = NULL;
|
2009-05-29 13:03:19 +00:00
|
|
|
|
2009-07-16 10:57:11 +00:00
|
|
|
while (node) {
|
2009-05-29 13:03:19 +00:00
|
|
|
if ((key & node->mask) != node->key)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
if (node->data)
|
|
|
|
result = node;
|
|
|
|
|
|
|
|
/* compare next bit */
|
|
|
|
if ((key & node->mask) > (key & (~ (~ node->mask >> 1))))
|
|
|
|
node = node->right;
|
|
|
|
else
|
|
|
|
node = node->left;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gpointer li_radixtree32_lookup(liRadixTree32 *tree, guint32 key) {
|
|
|
|
liRadixNode32 *node = li_radixtree32_lookup_node(tree, key);
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
return node ? node->data : NULL;
|
|
|
|
}
|
|
|
|
|
2009-07-09 20:17:24 +00:00
|
|
|
gpointer li_radixtree32_lookup_exact(liRadixTree32 *tree, guint32 key) {
|
|
|
|
liRadixNode32 *node = li_radixtree32_lookup_node(tree, key);
|
2009-05-29 13:03:19 +00:00
|
|
|
|
|
|
|
if (!node)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return (node->key == key) ? node->data : NULL;
|
2009-07-16 20:17:14 +00:00
|
|
|
}
|