From 176a172411a5f2dbd68d5da0221b8323143c398d Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 8 Oct 2015 18:42:02 +0200 Subject: [PATCH] Extend the Tommy tree regresison test --- cmdline/selftest.c | 65 +++++++++++++++++++++++++++++++++++++++++++-- tommyds/tommytree.c | 23 +++++++++++----- tommyds/tommytree.h | 31 ++++++++++++++------- 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/cmdline/selftest.c b/cmdline/selftest.c index c5281bdd..365dc28f 100644 --- a/cmdline/selftest.c +++ b/cmdline/selftest.c @@ -267,6 +267,15 @@ static int tommy_test_search(const void* arg, const void* obj) return arg != obj; } +static int tommy_test_compare(const void* void_arg_a, const void* void_arg_b) +{ + if (void_arg_a < void_arg_b) + return -1; + if (void_arg_a > void_arg_b) + return 1; + return 0; +} + static unsigned tommy_test_foreach_count; static void tommy_test_foreach(void* obj) @@ -292,7 +301,8 @@ static void test_tommy(void) tommy_arrayblkof arrayblkof; tommy_list list; tommy_hashdyn hashdyn; - tommy_hashdyn_node node[TOMMY_SIZE]; + tommy_tree tree; + tommy_node node[TOMMY_SIZE+1]; unsigned i; tommy_array_init(&array); @@ -345,7 +355,7 @@ static void test_tommy(void) if (tommy_hashdyn_count(&hashdyn) != TOMMY_SIZE) goto bail; - if (tommy_hashdyn_memory_usage(&hashdyn) < TOMMY_SIZE * sizeof(void*)) + if (tommy_hashdyn_memory_usage(&hashdyn) < TOMMY_SIZE * sizeof(tommy_node)) goto bail; tommy_test_foreach_count = 0; @@ -374,6 +384,57 @@ static void test_tommy(void) tommy_hashdyn_done(&hashdyn); + tommy_tree_init(&tree, tommy_test_compare); + + for (i = 0; i < TOMMY_SIZE; ++i) + tommy_tree_insert(&tree, &node[i], (void*)(i+1)); + + /* try to insert a duplicate, count should not change */ + if (tommy_tree_insert(&tree, &node[TOMMY_SIZE], (void*)1) != (void*)1) + goto bail; + + if (tommy_tree_count(&tree) != TOMMY_SIZE) + goto bail; + + if (tommy_tree_memory_usage(&tree) < TOMMY_SIZE * sizeof(tommy_node)) + goto bail; + + if (tommy_tree_search(&tree, (void*)1) != (void*)1) + goto bail; + + if (tommy_tree_search(&tree, (void*)-1) != 0) + goto bail; + + if (tommy_tree_search_compare(&tree, tommy_test_compare, (void*)1) != (void*)1) + goto bail; + + if (tommy_tree_search_compare(&tree, tommy_test_compare, (void*)-1) != 0) + goto bail; + + tommy_test_foreach_count = 0; + tommy_tree_foreach(&tree, tommy_test_foreach); + if (tommy_test_foreach_count != TOMMY_SIZE) + goto bail; + + tommy_test_foreach_count = 0; + tommy_tree_foreach_arg(&tree, tommy_test_foreach_arg, &tommy_test_foreach_count); + if (tommy_test_foreach_count != TOMMY_SIZE) + goto bail; + + for (i = 0; i < TOMMY_SIZE / 2; ++i) + tommy_tree_remove_existing(&tree, &node[i]); + + for (i = 0; i < TOMMY_SIZE / 2; ++i) + if (tommy_tree_remove(&tree, (void*)(i+1)) != 0) + goto bail; + + for (i = TOMMY_SIZE / 2; i < TOMMY_SIZE; ++i) + if (tommy_tree_remove(&tree, (void*)(i+1)) == 0) + goto bail; + + if (tommy_tree_count(&tree) != 0) + goto bail; + return; bail: /* LCOV_EXCL_START */ diff --git a/tommyds/tommytree.c b/tommyds/tommytree.c index 7ea31c21..b67b2408 100644 --- a/tommyds/tommytree.c +++ b/tommyds/tommytree.c @@ -140,14 +140,17 @@ static tommy_tree_node* tommy_tree_insert_node(tommy_compare_func* cmp, tommy_tr void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data) { - node->data = data; - node->prev = 0; - node->next = 0; - node->key = 0; + tommy_tree_node* insert = node; - tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &node); + insert->data = data; + insert->prev = 0; + insert->next = 0; + insert->key = 0; - ++tree->count; + tree->root = tommy_tree_insert_node(tree->cmp, tree->root, &insert); + + if (insert == node) + ++tree->count; return node->data; } @@ -186,6 +189,8 @@ void* tommy_tree_remove(tommy_tree* tree, void* data) if (!node) return 0; + --tree->count; + return node->data; } @@ -229,7 +234,11 @@ void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node) { - return tommy_tree_remove(tree, node->data); + void* data = tommy_tree_remove(tree, node->data); + + assert(data != 0); + + return data; } static void tommy_tree_foreach_node(tommy_tree_node* root, tommy_foreach_func* func) diff --git a/tommyds/tommytree.h b/tommyds/tommytree.h index a4db28b7..a183f6cd 100644 --- a/tommyds/tommytree.h +++ b/tommyds/tommytree.h @@ -28,18 +28,23 @@ /** \file * AVL tree. * - * This tree is a standard AVL tree implementation that stores elements in the order defined - * by the comparsion function. + * This tree is a standard AVL tree implementation that stores elements in the + * order defined by the comparsion function. + * + * As difference from other tommy containers, duplicate elements cannot be inserted. * * \code * tommy_tree tree; * + * To initialize a tree you have to call tommy_tree_init() specifing a comparison + * function that will define the order in the tree. + * * tommy_tree_init(&tree, cmp); * \endcode * * To insert elements in the tree you have to call tommy_tree_insert() for * each element. - * In the insertion call you have to specify the address of the node, the + * In the insertion call you have to specify the address of the node and the * address of the object. * The address of the object is used to initialize the tommy_node::data field * of the node. @@ -75,7 +80,8 @@ * providing the key to search and remove. *  * \code - * struct object* obj = tommy_tree_remove(&tree, value_to_remove); + * struct object value_to_remove = { 1 }; + * struct object* obj = tommy_tree_remove(&tree, &value_to_remove); * if (obj) { * free(obj); // frees the object allocated memory * } @@ -84,7 +90,7 @@ * To destroy the tree you have to remove all the elements. * * If you need to iterate over all the elements in the tree, you can use - * tommy_hashtable_foreach() or tommy_hashtable_foreach_arg(). + * tommy_tree_foreach() or tommy_tree_foreach_arg(). * If you need a more precise control with a real iteration, you have to insert * all the elements also in a ::tommy_list, and use the list to iterate. * See the \ref multiindex example for more detail. @@ -104,6 +110,10 @@ */ typedef tommy_node tommy_tree_node; +/** + * Tree container type. + * \note Don't use internal fields directly, but access the container only using functions. + */ typedef struct tommy_tree_struct { tommy_tree_node* root; /**< Root node. */ tommy_count_t count; /**< Number of elements. */ @@ -112,13 +122,14 @@ typedef struct tommy_tree_struct { /** * Initializes the tree. + * \param cmp The comparison function that defines the orderin the tree. */ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp); /** * Inserts an element in the tree. * If the element is already present, it's not inserted again. - * You have to provide the pointer of the node embedded into the object, + * You have to provide the pointer of the node embedded into the object and * the pointer at the object. * \param node Pointer at the node embedded into the object to insert. * \param data Pointer at the object to insert. @@ -143,13 +154,13 @@ void* tommy_tree_remove(tommy_tree* tree, void* data); void* tommy_tree_search(tommy_tree* tree, void* data); /** - * Searches an element in the tree with a specific compare function. + * Searches an element in the tree with a specific comparison function. * * Like tommy_tree_search() but you can specify a different comparison function. * Note that this function must define a suborder of the original one. * - * The ::data argument is going to always be the first argument of the comparison function, - * and it can be something different than the objects in the tree. + * The ::data argument will be the first argument of the comparison function, + * and it can be of a different type of the objects in the tree. */ void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg); @@ -180,7 +191,7 @@ void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node); * * ... * - * // insert it in the hashtable + * // insert it in the tree * tommy_tree_insert(&tree, &obj->node, obj); * * ...