summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/tree.c49
-rw-r--r--test/tree_bench.c2
-rw-r--r--test/tree_test.c37
-rw-r--r--zix/common.h5
-rw-r--r--zix/tree.h12
5 files changed, 90 insertions, 15 deletions
diff --git a/src/tree.c b/src/tree.c
index 3276685..13b7745 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -27,10 +27,12 @@
typedef struct ZixTreeNodeImpl ZixTreeNode;
struct ZixTreeImpl {
- ZixTreeNode* root;
- ZixComparator cmp;
- void* cmp_data;
- bool allow_duplicates;
+ ZixTreeNode* root;
+ ZixDestroyFunc destroy;
+ ZixComparator cmp;
+ void* cmp_data;
+ size_t size;
+ bool allow_duplicates;
};
struct ZixTreeNodeImpl {
@@ -67,22 +69,30 @@ struct ZixTreeNodeImpl {
ZIX_API
ZixTree*
-zix_tree_new(bool allow_duplicates, ZixComparator cmp, void* cmp_data)
+zix_tree_new(bool allow_duplicates,
+ ZixComparator cmp,
+ void* cmp_data,
+ ZixDestroyFunc destroy)
{
ZixTree* t = malloc(sizeof(ZixTree));
t->root = NULL;
+ t->destroy = destroy;
t->cmp = cmp;
t->cmp_data = cmp_data;
+ t->size = 0;
t->allow_duplicates = allow_duplicates;
return t;
}
static void
-zix_tree_free_rec(ZixTreeNode* n)
+zix_tree_free_rec(ZixTree* t, ZixTreeNode* n)
{
if (n) {
- zix_tree_free_rec(n->left);
- zix_tree_free_rec(n->right);
+ zix_tree_free_rec(t, n->left);
+ zix_tree_free_rec(t, n->right);
+ if (t->destroy) {
+ t->destroy(n->data);
+ }
free(n);
}
}
@@ -91,11 +101,16 @@ ZIX_API
void
zix_tree_free(ZixTree* t)
{
- zix_tree_free_rec(t->root);
-
+ zix_tree_free_rec(t, t->root);
free(t);
}
+size_t
+zix_tree_size(ZixTree* t)
+{
+ return t->size;
+}
+
static void
rotate(ZixTreeNode* p, ZixTreeNode* q)
{
@@ -131,8 +146,6 @@ rotate(ZixTreeNode* p, ZixTreeNode* q)
p->parent = q;
}
-
-
/**
* Rotate left about @a p.
*
@@ -413,6 +426,8 @@ zix_tree_insert(ZixTree* t, void* e, ZixTreeIter** ti)
DUMP(t);
+ ++t->size;
+
#ifdef ZIX_TREE_VERIFY
if (!verify(t, t->root)) {
return ZIX_STATUS_ERROR;
@@ -435,7 +450,12 @@ zix_tree_remove(ZixTree* t, ZixTreeIter* ti)
if ((n == t->root) && !n->left && !n->right) {
t->root = NULL;
+ if (t->destroy) {
+ t->destroy(n->data);
+ }
free(n);
+ --t->size;
+ assert(t->size == 0);
return ZIX_STATUS_SUCCESS;
}
@@ -559,8 +579,13 @@ zix_tree_remove(ZixTree* t, ZixTreeIter* ti)
DUMP(t);
+ if (t->destroy) {
+ t->destroy(n->data);
+ }
free(n);
+ --t->size;
+
#ifdef ZIX_TREE_VERIFY
if (!verify(t, t->root)) {
return ZIX_STATUS_ERROR;
diff --git a/test/tree_bench.c b/test/tree_bench.c
index d0e2611..ff6bd5e 100644
--- a/test/tree_bench.c
+++ b/test/tree_bench.c
@@ -62,7 +62,7 @@ bench_zix_tree(size_t n_elems,
intptr_t r;
ZixTreeIter* ti;
- ZixTree* t = zix_tree_new(true, int_cmp, NULL);
+ ZixTree* t = zix_tree_new(true, int_cmp, NULL, NULL);
srand(seed);
diff --git a/test/tree_test.c b/test/tree_test.c
index 943dca7..b89d5a8 100644
--- a/test/tree_test.c
+++ b/test/tree_test.c
@@ -60,7 +60,7 @@ stress(int test_num, size_t n_elems)
intptr_t r;
ZixTreeIter* ti;
- ZixTree* t = zix_tree_new(true, int_cmp, NULL);
+ ZixTree* t = zix_tree_new(true, int_cmp, NULL, NULL);
srand(seed);
@@ -79,6 +79,12 @@ stress(int test_num, size_t n_elems)
}
}
+ // Ensure tree size is correct
+ if (zix_tree_size(t) != n_elems) {
+ fprintf(stderr, "Tree size %zu != %zu\n", zix_tree_size(t), n_elems);
+ return test_fail();
+ }
+
srand(seed);
// Search for all elements
@@ -146,6 +152,35 @@ stress(int test_num, size_t n_elems)
}
}
+ // Ensure the tree is empty
+ if (zix_tree_size(t) != 0) {
+ fprintf(stderr, "Tree size %zu != 0\n", zix_tree_size(t));
+ return test_fail();
+ }
+
+ srand(seed);
+
+ // Insert n_elems elements again (to test non-empty destruction)
+ for (size_t i = 0; i < n_elems; ++i) {
+ r = ith_elem(test_num, n_elems, i);
+ int status = zix_tree_insert(t, (void*)r, &ti);
+ if (status) {
+ fprintf(stderr, "Insert failed\n");
+ return test_fail();
+ }
+ if ((intptr_t)zix_tree_get(ti) != r) {
+ fprintf(stderr, "Data corrupt (saw %" PRIdPTR ", expected %zu)\n",
+ (intptr_t)zix_tree_get(ti), r);
+ return test_fail();
+ }
+ }
+
+ // Ensure tree size is correct
+ if (zix_tree_size(t) != n_elems) {
+ fprintf(stderr, "Tree size %zu != %zu\n", zix_tree_size(t), n_elems);
+ return test_fail();
+ }
+
zix_tree_free(t);
return EXIT_SUCCESS;
diff --git a/zix/common.h b/zix/common.h
index a7edf76..8ed0b0b 100644
--- a/zix/common.h
+++ b/zix/common.h
@@ -60,6 +60,11 @@ typedef int (*ZixComparator)(const void* a, const void* b, void* user_data);
Function for testing equality of two elements.
*/
typedef bool (*ZixEqualFunc)(const void* a, const void* b);
+
+/**
+ Function to destroy an element.
+*/
+typedef void (*ZixDestroyFunc)(const void* ptr);
/**@}
*/
diff --git a/zix/tree.h b/zix/tree.h
index cdcec10..378db28 100644
--- a/zix/tree.h
+++ b/zix/tree.h
@@ -18,6 +18,7 @@
#define ZIX_TREE_H
#include <stdbool.h>
+#include <stddef.h>
#include "zix/common.h"
@@ -46,7 +47,10 @@ typedef struct ZixTreeNodeImpl ZixTreeIter;
Create a new (empty) tree.
*/
ZixTree*
-zix_tree_new(bool allow_duplicates, ZixComparator cmp, void* cmp_data);
+zix_tree_new(bool allow_duplicates,
+ ZixComparator cmp,
+ void* cmp_data,
+ ZixDestroyFunc destroy);
/**
Free @a t.
@@ -55,6 +59,12 @@ void
zix_tree_free(ZixTree* t);
/**
+ Return the number of elements in @a t.
+*/
+size_t
+zix_tree_size(ZixTree* t);
+
+/**
Insert the element @a e into @a t and point @a ti at the new element.
*/
ZixStatus