rbtree.c: use generic keys.
to make the rbtree more usefull. allow generic keys and user defined compare functions.
This commit is contained in:
parent
f76f494dcc
commit
027bf154a7
4 changed files with 85 additions and 164 deletions
|
|
@ -29,9 +29,6 @@ The binary tree node.
|
||||||
`key`::
|
`key`::
|
||||||
The key of this node
|
The key of this node
|
||||||
|
|
||||||
`data`::
|
|
||||||
pointer to the data associated with the key
|
|
||||||
|
|
||||||
`child`::
|
`child`::
|
||||||
pointers to the left and right child to this node
|
pointers to the left and right child to this node
|
||||||
|
|
||||||
|
|
@ -51,16 +48,16 @@ Structure that holds a tree of nodes
|
||||||
Pointer to the node that is the root of the tree.
|
Pointer to the node that is the root of the tree.
|
||||||
|
|
||||||
`delete_fn`::
|
`delete_fn`::
|
||||||
Pointer to the function that should handle the delete routines for the `rbnode->data` pointer.
|
Pointer to the function that should handle the delete routines for the `rbnode->key` pointer.
|
||||||
|
|
||||||
`update_fn`::
|
`update_fn`::
|
||||||
Pointer to the function that is called when the implementation performs an update of an `rbnode->data` pointer. +
|
Pointer to the function that is called when the implementation performs an update of an `rbnode->key` pointer. +
|
||||||
The function gets the following information passed in order: old pointer, new pointer.
|
The function gets the following information passed in order: old pointer, new pointer.
|
||||||
|
|
||||||
NOTE: You may only need this if you store the data in another structure and has to keep it synchronized with the RB-tree.
|
NOTE: You may only need this if you store the data in another structure and has to keep it synchronized with the RB-tree.
|
||||||
|
|
||||||
`cmp_fn`::
|
`cmp_fn`::
|
||||||
Pointer to the function that is used to compare `rbnode->data` pointers. +
|
Pointer to the function that is used to compare two `rbnode->key` pointers. +
|
||||||
Shall return a value greater than zero if 'ptr1' > 'ptr2', a value less than zero if 'ptr1' < 'ptr2' and zero if 'ptr1' == 'ptr2'.
|
Shall return a value greater than zero if 'ptr1' > 'ptr2', a value less than zero if 'ptr1' < 'ptr2' and zero if 'ptr1' == 'ptr2'.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
@ -73,7 +70,7 @@ Functions
|
||||||
If provided, calls `rbtree->update_fn` and `rbtree->delete_fn` if a node should be updated. +
|
If provided, calls `rbtree->update_fn` and `rbtree->delete_fn` if a node should be updated. +
|
||||||
Returns a nonzero value if a new node was inserted, zero if 'key' already existed and that node was updated.
|
Returns a nonzero value if a new node was inserted, zero if 'key' already existed and that node was updated.
|
||||||
|
|
||||||
NOTE: The memory pointed to by the 'data' pointer is *not* copied so you must ensure that it has a infinite lifetime.
|
NOTE: The memory pointed to by the 'key' pointer is *not* copied so you must ensure that it has a infinite lifetime.
|
||||||
|
|
||||||
`rbtree_delete()`::
|
`rbtree_delete()`::
|
||||||
|
|
||||||
|
|
@ -93,10 +90,7 @@ NOTE: The memory pointed to by the 'data' pointer is *not* copied so you must en
|
||||||
Searches the tree for 'key'. +
|
Searches the tree for 'key'. +
|
||||||
Returns a pointer to the node if found else `NULL`.
|
Returns a pointer to the node if found else `NULL`.
|
||||||
|
|
||||||
`rbtree_cmp_search()`::
|
NOTE: the function uses the `rbtree->cmp_fn` function to compare 'key' with a `rbnode->key`.
|
||||||
|
|
||||||
Searches the tree by compareing 'cmpdata' and `rbnode->data` to find a match. +
|
|
||||||
Returns the node if found, `NULL` otherwise.
|
|
||||||
|
|
||||||
`rbtree_is_empty()`::
|
`rbtree_is_empty()`::
|
||||||
|
|
||||||
|
|
|
||||||
79
src/rbtree.c
79
src/rbtree.c
|
|
@ -18,12 +18,11 @@
|
||||||
#define is_red(n) ((n) != NULL && (n)->color == RB_RED)
|
#define is_red(n) ((n) != NULL && (n)->color == RB_RED)
|
||||||
#define swap(n,d,q) ((n)->child[(n)->child[d] == (q)])
|
#define swap(n,d,q) ((n)->child[(n)->child[d] == (q)])
|
||||||
|
|
||||||
static rbnode* node_alloc(unsigned key, void *data) {
|
static rbnode* node_alloc(const void *key) {
|
||||||
|
|
||||||
rbnode *n = xmalloc(sizeof(rbnode));
|
rbnode *n = xmalloc(sizeof(rbnode));
|
||||||
|
|
||||||
n->key = key;
|
n->key = key;
|
||||||
n->data = data;
|
|
||||||
n->color = RB_RED;
|
n->color = RB_RED;
|
||||||
n->child[0] = NULL;
|
n->child[0] = NULL;
|
||||||
n->child[1] = NULL;
|
n->child[1] = NULL;
|
||||||
|
|
@ -40,7 +39,7 @@ static void node_dealloc(rbnode *n, void (*dealloc)(void *)) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dealloc)
|
if (dealloc)
|
||||||
dealloc(n->data);
|
dealloc((void *)n->key);
|
||||||
|
|
||||||
node_dealloc(n->child[0], dealloc);
|
node_dealloc(n->child[0], dealloc);
|
||||||
node_dealloc(n->child[1], dealloc);
|
node_dealloc(n->child[1], dealloc);
|
||||||
|
|
@ -61,22 +60,6 @@ static void rbwalk(rbnode *n, void (*action)(rbnode *)) {
|
||||||
rbwalk(n->child[1], action);
|
rbwalk(n->child[1], action);
|
||||||
}
|
}
|
||||||
|
|
||||||
static rbnode* rbcmp(rbnode *n, int (*cmp_fn)(const char *, const char *), const void *cmpdata) {
|
|
||||||
|
|
||||||
if (!n)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (cmp_fn(n->data, cmpdata) == 0)
|
|
||||||
return n;
|
|
||||||
|
|
||||||
rbnode *r = rbcmp(n->child[0], cmp_fn, cmpdata);
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
r = rbcmp(n->child[1], cmp_fn, cmpdata);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline rbnode* rotate_single(rbnode *root, unsigned char dir) {
|
static inline rbnode* rotate_single(rbnode *root, unsigned char dir) {
|
||||||
|
|
||||||
rbnode *save = root->child[!dir];
|
rbnode *save = root->child[!dir];
|
||||||
|
|
@ -103,34 +86,27 @@ inline int rbtree_is_empty(rbtree *tree) {
|
||||||
/*
|
/*
|
||||||
* Searches a tree by key.
|
* Searches a tree by key.
|
||||||
*/
|
*/
|
||||||
rbnode* rbtree_search(rbtree *tree, unsigned key) {
|
rbnode* rbtree_search(rbtree *tree, const void *key) {
|
||||||
|
|
||||||
rbnode *n;
|
rbnode *n;
|
||||||
|
|
||||||
if (tree == NULL || tree->root == NULL)
|
if (tree == NULL || tree->root == NULL || tree->cmp_fn == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
n = tree->root;
|
n = tree->root;
|
||||||
|
|
||||||
while(n) {
|
while(n) {
|
||||||
|
int cmp = tree->cmp_fn(n->key, key);
|
||||||
|
|
||||||
if (n->key == key)
|
if (cmp == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
n = n->child[n->key < key];
|
n = n->child[cmp < 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbnode* rbtree_cmp_search(rbtree *tree, const void *cmpdata) {
|
|
||||||
|
|
||||||
if (tree == NULL || tree->cmp_fn == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return rbcmp(tree->root, tree->cmp_fn, cmpdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rbtree_walk(rbtree *tree, void (*action)(rbnode *)) {
|
void rbtree_walk(rbtree *tree, void (*action)(rbnode *)) {
|
||||||
|
|
||||||
if (tree == NULL || action == NULL)
|
if (tree == NULL || action == NULL)
|
||||||
|
|
@ -148,7 +124,7 @@ void rbtree_free(rbtree *tree) {
|
||||||
tree->root = NULL;
|
tree->root = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rbtree_insert(rbtree *tree, unsigned key, void *data) {
|
int rbtree_insert(rbtree *tree, const void *key) {
|
||||||
|
|
||||||
rbnode head = {0};
|
rbnode head = {0};
|
||||||
|
|
||||||
|
|
@ -160,8 +136,11 @@ int rbtree_insert(rbtree *tree, unsigned key, void *data) {
|
||||||
|
|
||||||
unsigned char dir = 0, dir2, last, inserted = 0;
|
unsigned char dir = 0, dir2, last, inserted = 0;
|
||||||
|
|
||||||
|
if (!tree || !tree->cmp_fn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (tree->root == NULL) {
|
if (tree->root == NULL) {
|
||||||
tree->root = node_alloc(key, data);
|
tree->root = node_alloc(key);
|
||||||
inserted = 1;
|
inserted = 1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -173,8 +152,10 @@ int rbtree_insert(rbtree *tree, unsigned key, void *data) {
|
||||||
/* somewhere in here, there should be dragons */
|
/* somewhere in here, there should be dragons */
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
int cmp;
|
||||||
|
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
p->child[dir] = q = node_alloc(key, data);
|
p->child[dir] = q = node_alloc(key);
|
||||||
inserted = 1;
|
inserted = 1;
|
||||||
} else if (is_red(q->child[0]) && is_red(q->child[1])) {
|
} else if (is_red(q->child[0]) && is_red(q->child[1])) {
|
||||||
/* color flip case */
|
/* color flip case */
|
||||||
|
|
@ -192,11 +173,13 @@ int rbtree_insert(rbtree *tree, unsigned key, void *data) {
|
||||||
t->child[dir2] = rotate_double(g, !last);
|
t->child[dir2] = rotate_double(g, !last);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->key == key)
|
cmp = tree->cmp_fn(q->key, key);
|
||||||
|
|
||||||
|
if (cmp == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
last = dir;
|
last = dir;
|
||||||
dir = q->key < key;
|
dir = cmp < 0;
|
||||||
|
|
||||||
if (g)
|
if (g)
|
||||||
t = g;
|
t = g;
|
||||||
|
|
@ -205,11 +188,9 @@ int rbtree_insert(rbtree *tree, unsigned key, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
if (tree->update_fn)
|
|
||||||
tree->update_fn(q->data, data);
|
|
||||||
if (tree->delete_fn)
|
if (tree->delete_fn)
|
||||||
tree->delete_fn(q->data);
|
tree->delete_fn((void*)q->key);
|
||||||
q->data = data;
|
q->key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree->root = head.child[1];
|
tree->root = head.child[1];
|
||||||
|
|
@ -221,7 +202,7 @@ done:
|
||||||
return inserted;
|
return inserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rbtree_delete(rbtree *tree, unsigned key) {
|
int rbtree_delete(rbtree *tree, const void *key) {
|
||||||
|
|
||||||
rbnode head = {0};
|
rbnode head = {0};
|
||||||
|
|
||||||
|
|
@ -233,7 +214,7 @@ int rbtree_delete(rbtree *tree, unsigned key) {
|
||||||
|
|
||||||
unsigned char dir = 1, dir2, last;
|
unsigned char dir = 1, dir2, last;
|
||||||
|
|
||||||
if (rbtree_is_empty(tree))
|
if (rbtree_is_empty(tree) || !tree->cmp_fn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
q = &head;
|
q = &head;
|
||||||
|
|
@ -243,13 +224,15 @@ int rbtree_delete(rbtree *tree, unsigned key) {
|
||||||
/* more dragons (killed some of them though) */
|
/* more dragons (killed some of them though) */
|
||||||
|
|
||||||
while(q->child[dir]) {
|
while(q->child[dir]) {
|
||||||
last = dir;
|
int cmp;
|
||||||
|
|
||||||
g = p, p = q;
|
g = p, p = q;
|
||||||
q = q->child[dir];
|
q = q->child[dir];
|
||||||
dir = q->key < key;
|
last = dir;
|
||||||
|
|
||||||
if (q->key == key)
|
cmp = tree->cmp_fn(q->key, key);
|
||||||
|
dir = cmp < 0;
|
||||||
|
if (cmp == 0)
|
||||||
f = q;
|
f = q;
|
||||||
|
|
||||||
if (is_red(q) || is_red(q->child[dir]))
|
if (is_red(q) || is_red(q->child[dir]))
|
||||||
|
|
@ -288,12 +271,10 @@ int rbtree_delete(rbtree *tree, unsigned key) {
|
||||||
/* remove if found */
|
/* remove if found */
|
||||||
if (f) {
|
if (f) {
|
||||||
if (tree->delete_fn)
|
if (tree->delete_fn)
|
||||||
tree->delete_fn(f->data);
|
tree->delete_fn((void*)f->key);
|
||||||
|
|
||||||
if (f != q) {
|
if (f != q)
|
||||||
f->key = q->key;
|
f->key = q->key;
|
||||||
f->data = q->data;
|
|
||||||
}
|
|
||||||
swap(p, 1, q) = swap(q, 0, NULL);
|
swap(p, 1, q) = swap(q, 0, NULL);
|
||||||
xfree(q);
|
xfree(q);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
14
src/rbtree.h
14
src/rbtree.h
|
|
@ -18,8 +18,7 @@
|
||||||
|
|
||||||
/* node definition */
|
/* node definition */
|
||||||
typedef struct _rbn {
|
typedef struct _rbn {
|
||||||
unsigned key;
|
const void *key;
|
||||||
void *data;
|
|
||||||
struct _rbn *child[2];
|
struct _rbn *child[2];
|
||||||
unsigned char color;
|
unsigned char color;
|
||||||
} rbnode;
|
} rbnode;
|
||||||
|
|
@ -29,24 +28,21 @@ typedef struct {
|
||||||
/* user defined operations */
|
/* user defined operations */
|
||||||
void (*delete_fn)(void *);
|
void (*delete_fn)(void *);
|
||||||
void (*update_fn)(void *, void *);
|
void (*update_fn)(void *, void *);
|
||||||
/* note: char* is used here to make dereference easier inside the function */
|
int (*cmp_fn)(const void *, const void *);
|
||||||
int (*cmp_fn)(const char *, const char *);
|
|
||||||
} rbtree;
|
} rbtree;
|
||||||
|
|
||||||
#define RBTREE_INIT(delete, update, cmp) { NULL, delete, update, cmp}
|
#define RBTREE_INIT(delete, update, cmp) { NULL, delete, update, cmp}
|
||||||
|
|
||||||
int rbtree_is_empty(rbtree *tree);
|
int rbtree_is_empty(rbtree *tree);
|
||||||
|
|
||||||
rbnode* rbtree_search(rbtree *tree, unsigned key);
|
rbnode* rbtree_search(rbtree *tree, const void *key);
|
||||||
|
|
||||||
rbnode* rbtree_cmp_search(rbtree *tree, const void *data);
|
|
||||||
|
|
||||||
void rbtree_walk(rbtree *tree, void (*action)(rbnode *));
|
void rbtree_walk(rbtree *tree, void (*action)(rbnode *));
|
||||||
|
|
||||||
void rbtree_free(rbtree *tree);
|
void rbtree_free(rbtree *tree);
|
||||||
|
|
||||||
int rbtree_insert(rbtree *tree, unsigned key, void *data);
|
int rbtree_insert(rbtree *tree, const void *key);
|
||||||
|
|
||||||
int rbtree_delete(rbtree *tree, unsigned key);
|
int rbtree_delete(rbtree *tree, const void *key);
|
||||||
|
|
||||||
#endif /* __RBTREE_H */
|
#endif /* __RBTREE_H */
|
||||||
|
|
|
||||||
110
test/t_rbtree.c
110
test/t_rbtree.c
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
#define is_red(n) ((n) != NULL && (n)->color == RB_RED)
|
#define is_red(n) ((n) != NULL && (n)->color == RB_RED)
|
||||||
|
|
||||||
|
static int vcmp(const void *a, const void *b);
|
||||||
|
static void vdelete(void *ptr);
|
||||||
|
|
||||||
static int rb_assert(rbnode *node) {
|
static int rb_assert(rbnode *node) {
|
||||||
|
|
||||||
int rh, lh;
|
int rh, lh;
|
||||||
|
|
@ -39,8 +42,8 @@ static int rb_assert(rbnode *node) {
|
||||||
lh = rb_assert(ln);
|
lh = rb_assert(ln);
|
||||||
rh = rb_assert(rn);
|
rh = rb_assert(rn);
|
||||||
|
|
||||||
if ( (ln != NULL && ln->key >= node->key) &&
|
if ( (ln != NULL && vcmp(ln->key, node->key) >= 0) &&
|
||||||
(rn != NULL && rn->key <= node->key) ) {
|
(rn != NULL && vcmp(rn->key, node->key) <= 0) ) {
|
||||||
die("BST violation");
|
die("BST violation");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -58,59 +61,31 @@ static int rb_assert(rbnode *node) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vcmp(const char *a, const char *b);
|
|
||||||
static void vfree(void *ptr);
|
|
||||||
static void vupdate(void *old, void *new);
|
|
||||||
|
|
||||||
/* data */
|
/* data */
|
||||||
static rbtree tree = RBTREE_INIT(vfree, vupdate, vcmp);
|
static rbtree tree = RBTREE_INIT(vdelete, NULL, vcmp);
|
||||||
static int keyref[NODES];
|
static int keyref[NODES];
|
||||||
static char *dataref[NODES];
|
|
||||||
|
|
||||||
static int vcmp(const char *a, const char *b) {
|
static int vcmp(const void *a, const void *b) {
|
||||||
|
|
||||||
printf("cmp: %s -> %s\n", a, b);
|
return *((int*)a) - *((int*)b);
|
||||||
|
|
||||||
return strcmp(a, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vupdate(void *old, void *new) {
|
static void vdelete(void *ptr) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printf("update: %s -> %s\n", (char*)old, (char*)new);
|
printf("delete: %i\n", *((int*)ptr));
|
||||||
|
|
||||||
for(i=0; i < NODES; i++) {
|
for(i=0; i < NODES; i++) {
|
||||||
|
|
||||||
if (keyref[i] == -1)
|
if (keyref[i] == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (old == dataref[i]) {
|
if (ptr == &keyref[i]) {
|
||||||
dataref[i] = new;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vfree(void *ptr) {
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf("free: %s\n", (char*)ptr);
|
|
||||||
|
|
||||||
for(i=0; i < NODES; i++) {
|
|
||||||
|
|
||||||
if (keyref[i] == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ptr == dataref[i]) {
|
|
||||||
keyref[i] = -1;
|
keyref[i] = -1;
|
||||||
dataref[i] = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vwalk(rbnode *node) {
|
static void vwalk(rbnode *node) {
|
||||||
|
|
@ -120,46 +95,36 @@ static void vwalk(rbnode *node) {
|
||||||
/* check if this node exist in the reference list */
|
/* check if this node exist in the reference list */
|
||||||
for(i=0; i < NODES; i++) {
|
for(i=0; i < NODES; i++) {
|
||||||
|
|
||||||
if (node->key == keyref[i] && node->data == dataref[i]) {
|
if (node->key == &keyref[i]) {
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(found);
|
assert(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_insert() {
|
void test_insert() {
|
||||||
|
|
||||||
int i = 0, ret;
|
int i = 0;
|
||||||
uint ckey;
|
|
||||||
char *data;
|
|
||||||
|
|
||||||
utest_init_RNG();
|
|
||||||
|
|
||||||
/* insert values */
|
/* insert values */
|
||||||
while(i < NODES) {
|
while(i < NODES) {
|
||||||
|
|
||||||
ckey = (uint) (rand() % MAX_VAL);
|
rbnode *node;
|
||||||
data = utest_ran_string(16);
|
|
||||||
|
keyref[i] = (uint) (rand() % MAX_VAL);
|
||||||
|
|
||||||
/* insert into rbtree and assert it */
|
/* insert into rbtree and assert it */
|
||||||
ret = rbtree_insert(&tree, ckey, data);
|
node = rbtree_insert(&tree, &keyref[i]);
|
||||||
rb_assert(tree.root);
|
rb_assert(tree.root);
|
||||||
|
|
||||||
if (!ret)
|
assert(node);
|
||||||
continue;
|
|
||||||
|
|
||||||
printf("insert: %i %s\n", ckey, data);
|
printf("insert: %i\n", *((int*)node->key));
|
||||||
|
|
||||||
keyref[i] = ckey;
|
|
||||||
dataref[i] = data;
|
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insert duplicate key */
|
|
||||||
rbtree_insert(&tree, keyref[rand() % NODES], strdup("---- update ----"));
|
|
||||||
rb_assert(tree.root);
|
rb_assert(tree.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,8 +139,10 @@ void test_delete() {
|
||||||
key = keyref[rand() % NODES];
|
key = keyref[rand() % NODES];
|
||||||
while(key < 0);
|
while(key < 0);
|
||||||
|
|
||||||
rbtree_delete(&tree, key);
|
rbtree_delete(&tree, &key);
|
||||||
rb_assert(tree.root);
|
rb_assert(tree.root);
|
||||||
|
|
||||||
|
keyref[key] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,40 +159,23 @@ void test_search() {
|
||||||
printf("search: expecting to find key %i\n", keyref[index]);
|
printf("search: expecting to find key %i\n", keyref[index]);
|
||||||
|
|
||||||
/* search for a key we know exists */
|
/* search for a key we know exists */
|
||||||
n = rbtree_search(&tree, keyref[index]);
|
n = rbtree_search(&tree, &keyref[index]);
|
||||||
rb_assert(tree.root);
|
rb_assert(tree.root);
|
||||||
|
|
||||||
assert(n != NULL);
|
assert(n != NULL);
|
||||||
assert(n->key == keyref[index]);
|
assert(n->key == &keyref[index]);
|
||||||
assert_string(n->data, dataref[index]);
|
|
||||||
|
|
||||||
printf("search: expecting to not find key: %i\n", MAX_VAL+512);
|
index = MAX_VAL + 512;
|
||||||
|
|
||||||
|
printf("search: expecting to not find key: %i\n", index);
|
||||||
|
|
||||||
/* search for a key we now don't exist */
|
/* search for a key we now don't exist */
|
||||||
n = rbtree_search(&tree, MAX_VAL+512);
|
n = rbtree_search(&tree, &index);
|
||||||
rb_assert(tree.root);
|
rb_assert(tree.root);
|
||||||
|
|
||||||
assert(n == NULL);
|
assert(n == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_cmp_search() {
|
|
||||||
|
|
||||||
char *search;
|
|
||||||
rbnode *n;
|
|
||||||
|
|
||||||
do
|
|
||||||
search = dataref[rand()%NODES];
|
|
||||||
while(search == NULL);
|
|
||||||
|
|
||||||
printf("cmp_search: searching for %s\n", search);
|
|
||||||
|
|
||||||
n = rbtree_cmp_search(&tree, search);
|
|
||||||
|
|
||||||
rb_assert(tree.root);
|
|
||||||
assert(n != NULL);
|
|
||||||
assert_string(n->data, search);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_walk() {
|
void test_walk() {
|
||||||
|
|
||||||
rbtree_walk(&tree, vwalk);
|
rbtree_walk(&tree, vwalk);
|
||||||
|
|
@ -236,19 +186,19 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
tree.root = NULL;
|
tree.root = NULL;
|
||||||
|
|
||||||
|
utest_init_RNG();
|
||||||
|
|
||||||
/* a new tree is empty */
|
/* a new tree is empty */
|
||||||
assert(rbtree_is_empty(&tree));
|
assert(rbtree_is_empty(&tree));
|
||||||
|
|
||||||
test_insert();
|
test_insert();
|
||||||
|
|
||||||
test_search();
|
test_search();
|
||||||
test_cmp_search();
|
|
||||||
test_walk();
|
test_walk();
|
||||||
|
|
||||||
test_delete();
|
test_delete();
|
||||||
|
|
||||||
test_search();
|
test_search();
|
||||||
test_cmp_search();
|
|
||||||
test_walk();
|
test_walk();
|
||||||
|
|
||||||
/* free the tree */
|
/* free the tree */
|
||||||
|
|
|
||||||
Reference in a new issue