2
0
Fork 0

[core] Add implementation of 32bit radix trees (radix.{h.c})

personal/stbuehler/wip
Thomas Porzelt 2009-05-29 15:03:19 +02:00
parent 0e001f21e5
commit 451cdd1579
4 changed files with 333 additions and 0 deletions

View File

@ -27,6 +27,8 @@
#include <lighttpd/typedefs.h>
#include <lighttpd/module.h>
#include <lighttpd/radix.h>
#include <lighttpd/chunk.h>
#include <lighttpd/chunk_parser.h>

69
include/lighttpd/radix.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef _LIGHTTPD_RADIX_H_
#define _LIGHTTPD_RADIX_H_
/*
* Radix tree with 32bit key, lookup, insert and remove in O(32).
* This is where the bit magic happens.
*/
struct RadixNode32 {
guint32 key;
guint32 mask;
gpointer data;
struct RadixNode32 *parent;
struct RadixNode32 *right;
struct RadixNode32 *left;
};
typedef struct RadixNode32 RadixNode32;
struct RadixTree32 {
RadixNode32 **root;
guint32 size;
guint32 root_width;
guint32 root_mask;
};
typedef struct RadixTree32 RadixTree32;
LI_API RadixTree32 *radixtree32_new(guint32 root_width);
LI_API guint32 radixtree32_free(RadixTree32 *tree);
LI_API void radixtree32_insert(RadixTree32 *tree, guint32 key, guint32 mask, gpointer data);
LI_API gboolean radixtree32_remove(RadixTree32 *tree, guint32 key, guint32 mask);
/* lookup tree node (best match) */
LI_API RadixNode32 *radixtree32_lookup_node(RadixTree32 *tree, guint32 key);
/* lookup data pointer (best match) */
LI_API gpointer radixtree32_lookup(RadixTree32 *tree, guint32 key);
/* lookup data pointer (exact match) */
LI_API gpointer radixtree32_lookup_exact(RadixTree32 *tree, guint32 key);
/*
struct RadixNode128 {
guint32 key[4];
guint32 mask[3];
gpointer data;
struct RadixNode128 *parent;
struct RadixNode128 *right;
struct RadixNode128 *left;
};
typedef struct RadixNode128 RadixNode128;
struct RadixTree128 {
RadixNode128 **root;
guint64 size;
guint32 root_width;
guint32 root_mask;
}
LI_api RadixTree128 *radixtree128_new(guint32 root_width);
LI_API guint radixtree128_free(RadixTree128 *tree);
LI_API void radixtree128_insert(RadixTree128 *tree, guint32 *key, guint32 *mask, gpointer data);
LI_API gboolean radixtree128_remove(RadixTree128 *tree, guint32 *key, guint32 *mask);
LI_API gpointer radixtree128_lookup(RadixTree128 *tree, guint32 *key);
*/
#endif

View File

@ -293,6 +293,7 @@ SET(COMMON_SRC
options.c
plugin.c
profiler.c
radix.c
request.c
response.c
server.c

261
src/radix.c Normal file
View File

@ -0,0 +1,261 @@
#include <lighttpd/base.h>
RadixTree32 *radixtree32_new(guint32 root_width) {
guint32 i;
RadixTree32 *tree = g_slice_new(RadixTree32);
if (root_width == 0)
root_width = 1;
else if (root_width > 8)
root_width = 8;
tree->root = g_new0(RadixNode32*, 1 << root_width);
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;
}
guint radixtree32_free(RadixTree32 *tree) {
guint32 i;
RadixNode32 *node, *parent;
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;
}
g_slice_free(RadixNode32, node);
node = parent;
n++;
}
}
}
g_free(tree->root);
g_slice_free(RadixTree32, tree);
return n;
}
void radixtree32_insert(RadixTree32 *tree, guint32 key, guint32 mask, gpointer data) {
RadixNode32 *last_node, *leaf;
RadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
//g_print("root: %p, %x & %x => %x\n", (void*)node, key, tree->root_mask, (key & tree->root_mask) >> (32 - tree->root_width));
if (!node) {
/* no root node yet */
node = g_slice_new(RadixNode32);
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;
}
do {//g_print("%x & %x => %x != %x\n", key, node->mask, key & node->mask, node->key);
if ((key & mask & node->mask) != node->key) {guint i;
/* node key differs, split tree */
guint32 tmp;
RadixNode32 *new_node;i=0;
/* the new internal node */
new_node = g_slice_new(RadixNode32);
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 */
leaf = g_slice_new(RadixNode32);
leaf->key = key & mask;
leaf->mask = mask;
leaf->data = data;
leaf->parent = new_node;
leaf->left = NULL;
leaf->right = NULL;
do {//g_print("xxx #%u %x & %x => %x != %x\n", i++, key, new_node->mask, key&new_node->mask, node->key);
tmp = new_node->mask;
new_node->mask <<= 1;
new_node->key &= new_node->mask;
} while ((key & mask & new_node->mask) != new_node->key);
//g_print("xxx %x & %x => %x != %x\n", key, new_node->mask, key&new_node->mask, node->key);
//if (key & (~ (~ new_node->mask >> 1))) {
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 >> 1)))
if ((key & node->mask) > (key & (~ (~ node->mask >> 1))))
node = node->right;
else
node = node->left;
} while (node);
/* new leaf at end of tree */
leaf = g_slice_new0(RadixNode32);
leaf->data = data;
leaf->key = key & mask;
leaf->mask = mask;
leaf->parent = last_node;
//if (key & (~ (~ last_node->key >> 1)))
if ((key & last_node->mask) > (key & (~ (~ last_node->mask >> 1))))
last_node->right = leaf;
else
last_node->left = leaf;
tree->size++;
}
gboolean radixtree32_remove(RadixTree32 *tree, guint32 key, guint32 mask) {
RadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
while (node) {
if (!node->data || (key & mask) != node->key) {
/* compare next bit */
//if (key & (~ (~ node->key >> 1)))
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 */
RadixNode32 *sibling = (node->parent->left == node) ? node->parent->right : node->parent->left;
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--;
g_slice_free(RadixNode32, node->parent);
}
} else {
/* tree root */
tree->root[(key & tree->root_mask) >> (32 - tree->root_width)] = NULL;
}
} else {
/* internal node */
node->data = NULL;
return TRUE;
}
tree->size--;
g_slice_free(RadixNode32, node);
return TRUE;
}
return FALSE;
}
RadixNode32 *radixtree32_lookup_node(RadixTree32 *tree, guint32 key) {
RadixNode32 *node = tree->root[(key & tree->root_mask) >> (32 - tree->root_width)];
RadixNode32 *result = NULL;
while (node) {//g_print("%x & %x => %x != %x\n", key, node->mask, key & node->mask, node->key);
if ((key & node->mask) != node->key)
return result;
if (node->data)
result = node;
/* compare next bit */
//if (key & (~ (~ node->key >> 1)))
if ((key & node->mask) > (key & (~ (~ node->mask >> 1))))
node = node->right;
else
node = node->left;
}
return result;
}
gpointer radixtree32_lookup(RadixTree32 *tree, guint32 key) {
RadixNode32 *node = radixtree32_lookup_node(tree, key);
return node ? node->data : NULL;
}
gpointer radixtree32_lookup_exact(RadixTree32 *tree, guint32 key) {
RadixNode32 *node = radixtree32_lookup_node(tree, key);
if (!node)
return NULL;
return (node->key == key) ? node->data : NULL;
}