Implemented a simlpe red-black tree which should give better performance

for certain lookups.

The rb_tree will act as a general purpose key/value storage, and
also give a performance boost in the cases where the other
simple alternative would be to use a linked_list.

On average this should give on average O(log n) lookups, while the linked_list
would be O(n) at worst.
This commit is contained in:
Jan Vidar Krey
2012-11-01 02:52:00 +01:00
parent 5d6184961b
commit 3dcbb63a31
4 changed files with 598 additions and 79 deletions

View File

@@ -54,6 +54,7 @@ extern int exotic_run(struct exotic_handle* handle);
#include "test_memory.tcc"
#include "test_message.tcc"
#include "test_misc.tcc"
#include "test_rbtree.tcc"
#include "test_sid.tcc"
#include "test_tiger.tcc"
#include "test_timer.tcc"
@@ -696,6 +697,33 @@ int main(int argc, char** argv)
exotic_add_test(&handle, &exotic_test_utf8_valid_10, "utf8_valid_10");
exotic_add_test(&handle, &exotic_test_utf8_valid_11, "utf8_valid_11");
exotic_add_test(&handle, &exotic_test_utf8_valid_12, "utf8_valid_12");
exotic_add_test(&handle, &exotic_test_rbtree_create_destroy, "rbtree_create_destroy");
exotic_add_test(&handle, &exotic_test_rbtree_create_1, "rbtree_create_1");
exotic_add_test(&handle, &exotic_test_rbtree_size_0, "rbtree_size_0");
exotic_add_test(&handle, &exotic_test_rbtree_insert_1, "rbtree_insert_1");
exotic_add_test(&handle, &exotic_test_rbtree_insert_2, "rbtree_insert_2");
exotic_add_test(&handle, &exotic_test_rbtree_insert_3, "rbtree_insert_3");
exotic_add_test(&handle, &exotic_test_rbtree_insert_3_again, "rbtree_insert_3_again");
exotic_add_test(&handle, &exotic_test_rbtree_size_1, "rbtree_size_1");
exotic_add_test(&handle, &exotic_test_rbtree_search_1, "rbtree_search_1");
exotic_add_test(&handle, &exotic_test_rbtree_search_2, "rbtree_search_2");
exotic_add_test(&handle, &exotic_test_rbtree_search_3, "rbtree_search_3");
exotic_add_test(&handle, &exotic_test_rbtree_search_4, "rbtree_search_4");
exotic_add_test(&handle, &exotic_test_rbtree_remove_1, "rbtree_remove_1");
exotic_add_test(&handle, &exotic_test_rbtree_size_2, "rbtree_size_2");
exotic_add_test(&handle, &exotic_test_rbtree_remove_2, "rbtree_remove_2");
exotic_add_test(&handle, &exotic_test_rbtree_remove_3, "rbtree_remove_3");
exotic_add_test(&handle, &exotic_test_rbtree_remove_3_again, "rbtree_remove_3_again");
exotic_add_test(&handle, &exotic_test_rbtree_search_5, "rbtree_search_5");
exotic_add_test(&handle, &exotic_test_rbtree_search_6, "rbtree_search_6");
exotic_add_test(&handle, &exotic_test_rbtree_search_7, "rbtree_search_7");
exotic_add_test(&handle, &exotic_test_rbtree_search_8, "rbtree_search_8");
exotic_add_test(&handle, &exotic_test_rbtree_size_3, "rbtree_size_3");
exotic_add_test(&handle, &exotic_test_rbtree_insert_10000, "rbtree_insert_10000");
exotic_add_test(&handle, &exotic_test_rbtree_size_4, "rbtree_size_4");
exotic_add_test(&handle, &exotic_test_rbtree_check_10000, "rbtree_check_10000");
exotic_add_test(&handle, &exotic_test_rbtree_iterate_10000, "rbtree_iterate_10000");
exotic_add_test(&handle, &exotic_test_rbtree_remove_5000, "rbtree_remove_5000");
exotic_add_test(&handle, &exotic_test_sid_create_pool, "sid_create_pool");
exotic_add_test(&handle, &exotic_test_sid_check_0a, "sid_check_0a");
exotic_add_test(&handle, &exotic_test_sid_check_0b, "sid_check_0b");

144
autotest/test_rbtree.tcc Normal file
View File

@@ -0,0 +1,144 @@
#include <uhub.h>
#include <util/rbtree.h>
#define MAX_NODES 10000
static struct rb_tree* tree = NULL;
int test_tree_compare(const void* a, const void* b)
{
return strcmp((const char*) a, (const char*) b);
}
EXO_TEST(rbtree_create_destroy, {
int ok = 0;
struct rb_tree* atree;
atree = rb_tree_create(test_tree_compare, &hub_malloc, &hub_free);
if (atree) ok = 1;
rb_tree_destroy(atree);
return ok;
});
EXO_TEST(rbtree_create_1, {
tree = rb_tree_create(test_tree_compare, &hub_malloc, &hub_free);
return tree != NULL;
});
EXO_TEST(rbtree_size_0, { return rb_tree_size(tree) == 0; });
EXO_TEST(rbtree_insert_1, {
return rb_tree_insert(tree, "one", "1");
});
EXO_TEST(rbtree_insert_2, {
return rb_tree_insert(tree, "two", "2");
});
EXO_TEST(rbtree_insert_3, {
return rb_tree_insert(tree, "three", "3");
});
EXO_TEST(rbtree_insert_3_again, {
return !rb_tree_insert(tree, "three", "3-again");
});
EXO_TEST(rbtree_size_1, { return rb_tree_size(tree) == 3; });
static int test_check_search(const char* key, const char* expect)
{
const char* value = (const char*) rb_tree_get(tree, key);
if (!value) return !expect;
if (!expect) return 0;
return strcmp(value, expect) == 0;
}
EXO_TEST(rbtree_search_1, { return test_check_search("one", "1"); });
EXO_TEST(rbtree_search_2, { return test_check_search("two", "2"); });
EXO_TEST(rbtree_search_3, { return test_check_search("three", "3"); });
EXO_TEST(rbtree_search_4, { return test_check_search("four", NULL); });
EXO_TEST(rbtree_remove_1, {
return rb_tree_remove(tree, "one");
});
EXO_TEST(rbtree_size_2, { return rb_tree_size(tree) == 2; });
EXO_TEST(rbtree_remove_2, {
return rb_tree_remove(tree, "two");
});
EXO_TEST(rbtree_remove_3, {
return rb_tree_remove(tree, "three");
});
EXO_TEST(rbtree_remove_3_again, {
return !rb_tree_remove(tree, "three");
});
EXO_TEST(rbtree_search_5, { return test_check_search("one", NULL); });
EXO_TEST(rbtree_search_6, { return test_check_search("two", NULL); });
EXO_TEST(rbtree_search_7, { return test_check_search("three", NULL); });
EXO_TEST(rbtree_search_8, { return test_check_search("four", NULL); });
EXO_TEST(rbtree_size_3, { return rb_tree_size(tree) == 0; });
EXO_TEST(rbtree_insert_10000, {
int i;
for (i = 0; i < MAX_NODES ; i++)
{
const char* key = strdup(uhub_itoa(i));
const char* val = strdup(uhub_itoa(i + 16384));
if (!rb_tree_insert(tree, key, val))
return 0;
}
return 1;
});
EXO_TEST(rbtree_size_4, { return rb_tree_size(tree) == MAX_NODES ; });
EXO_TEST(rbtree_check_10000, {
int i;
for (i = 0; i < MAX_NODES ; i++)
{
char* key = strdup(uhub_itoa(i));
const char* expect = uhub_itoa(i + 16384);
if (!test_check_search(key, expect))
return 0;
hub_free(key);
}
return 1;
});
EXO_TEST(rbtree_iterate_10000, {
int i = 0;
struct rb_node* n = (struct rb_node*) rb_tree_first(tree);
while (n)
{
struct rb_node* p = n;
n = (struct rb_node*) rb_tree_next(tree);
i++;
}
return i == MAX_NODES ;
});
static void free_node(struct rb_node* n)
{
hub_free(n->key);
hub_free(n->value);
}
EXO_TEST(rbtree_remove_5000, {
int i = 0;
struct rb_node* n = (struct rb_node*) rb_tree_first(tree);
for (i = 0; i < MAX_NODES ; i += 2)
{
const char* key = uhub_itoa(i);
rb_tree_remove_node(tree, key, &free_node);
}
return 1;
});