common/rbtree: fixed a bug in delete
This commit is contained in:
parent
8d7b4a74c7
commit
7209cfb1c4
7 changed files with 52 additions and 37 deletions
|
|
@ -11,23 +11,20 @@
|
|||
* http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#include "xalloc.h"
|
||||
#include "debug.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
#define is_red(n) ((n) != NULL && (n)->color == RB_RED)
|
||||
#define swap(n,d,q) ((n)->child[(n)->child[d] == (q)])
|
||||
|
||||
static rbnode* node_alloc(uint key, void *ptr) {
|
||||
static rbnode* node_alloc(uint key, void *ptr, size_t len) {
|
||||
|
||||
rbnode *n = malloc(sizeof(rbnode));
|
||||
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
rbnode *n = xmalloc(sizeof(rbnode));
|
||||
|
||||
n->key = key;
|
||||
n->data = ptr;
|
||||
n->len = len;
|
||||
n->color = RB_RED;
|
||||
n->child[0] = NULL;
|
||||
n->child[1] = NULL;
|
||||
|
|
@ -46,14 +43,14 @@ static void node_dealloc(rbnode *n, void (*action)(rbnode *)) {
|
|||
if (action != NULL) {
|
||||
action(n);
|
||||
} else if (n->data != NULL) {
|
||||
free(n->data);
|
||||
xfree(n->data);
|
||||
n->data = NULL;
|
||||
}
|
||||
|
||||
node_dealloc(n->child[0], action);
|
||||
node_dealloc(n->child[1], action);
|
||||
|
||||
free(n);
|
||||
xfree(n);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -185,7 +182,7 @@ void rbtree_free(rbtree *tree, void (*action)(rbnode *)) {
|
|||
*
|
||||
* the function now returns -1 in that situation // H Hautakoski
|
||||
*/
|
||||
int rbtree_insert(rbtree *tree, uint key, void *data) {
|
||||
int rbtree_insert(rbtree *tree, uint key, void *data, size_t len) {
|
||||
|
||||
rbnode head = {0};
|
||||
|
||||
|
|
@ -198,7 +195,7 @@ int rbtree_insert(rbtree *tree, uint key, void *data) {
|
|||
unsigned char dir = 0, dir2, last, inserted = 0;
|
||||
|
||||
if (tree->root == NULL) {
|
||||
tree->root = node_alloc(key, data);
|
||||
tree->root = node_alloc(key, data, len);
|
||||
if (tree->root == NULL)
|
||||
return 0;
|
||||
goto done;
|
||||
|
|
@ -212,7 +209,7 @@ int rbtree_insert(rbtree *tree, uint key, void *data) {
|
|||
|
||||
for(;;) {
|
||||
if (q == NULL) {
|
||||
p->child[dir] = q = node_alloc(key, data);
|
||||
p->child[dir] = q = node_alloc(key, data, len);
|
||||
if (q == NULL)
|
||||
return 0;
|
||||
inserted = 1;
|
||||
|
|
@ -325,18 +322,15 @@ void* rbtree_delete(rbtree *tree, uint key) {
|
|||
tree->root->color = RB_BLACK;
|
||||
|
||||
/* remove if found */
|
||||
if (f != NULL) {
|
||||
ret = q->data;
|
||||
if (q == tree->root) {
|
||||
tree->root = NULL;
|
||||
} else {
|
||||
if (f != q) {
|
||||
f->key = q->key;
|
||||
f->data = q->data;
|
||||
}
|
||||
swap(p, 1, q) = swap(q, 0, NULL);
|
||||
}
|
||||
free(q);
|
||||
if (f) {
|
||||
ret = f->data;
|
||||
if (f != q) {
|
||||
f->key = q->key;
|
||||
f->data = xmemdup(q->data, q->len);
|
||||
f->len = q->len;
|
||||
}
|
||||
swap(p, 1, q) = swap(q, 0, NULL);
|
||||
xfree(q);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ void rbtree_walk(rbtree *tree, void (*action)(rbnode *));
|
|||
|
||||
void rbtree_free(rbtree *tree, void (*action)(rbnode *));
|
||||
|
||||
int rbtree_insert(rbtree *tree, uint key, void *data);
|
||||
int rbtree_insert(rbtree *tree, uint key, void *data, size_t len);
|
||||
|
||||
void* rbtree_delete(rbtree *tree, uint key);
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,17 @@ bail:
|
|||
die_errno("xstrdup");
|
||||
}
|
||||
|
||||
void* xmemdup(const void *src, size_t size) {
|
||||
|
||||
CHECK_INPUT(src);
|
||||
|
||||
void *dest = xmalloc(size);
|
||||
memcpy(dest, src, size);
|
||||
return dest;
|
||||
bail:
|
||||
die_errno("xmemdup");
|
||||
}
|
||||
|
||||
void xfree(void *ptr) {
|
||||
|
||||
CHECK_INPUT(ptr);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ void* xrealloc(void *, size_t);
|
|||
|
||||
char* xstrdup(const char *);
|
||||
|
||||
void* xmemdup(const void *, size_t);
|
||||
|
||||
void xfree(void *);
|
||||
|
||||
#endif /* __COMMON_XALLOC_H */
|
||||
|
|
|
|||
|
|
@ -42,16 +42,17 @@ static queue_t event_queue;
|
|||
static int addwatch(const char *path, const char *name) {
|
||||
|
||||
rbnode *node;
|
||||
char *cpath;
|
||||
char *npath;
|
||||
int wd;
|
||||
|
||||
cpath = path_normalize(path, name, 1);
|
||||
npath = path_normalize(path, name, 1);
|
||||
|
||||
wd = inotify_add_watch(fd, cpath, WATCH_MASK);
|
||||
wd = inotify_add_watch(fd, npath, WATCH_MASK);
|
||||
|
||||
if (wd < 0) {
|
||||
perror("NOTIFY ADD");
|
||||
dprint("%i path %s\n", errno == EBADF, cpath);
|
||||
dprint("%i path %s\n", errno == EBADF, npath);
|
||||
free(npath);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
|
@ -59,12 +60,13 @@ static int addwatch(const char *path, const char *name) {
|
|||
node = rbtree_search(&tree, wd);
|
||||
|
||||
if (node == NULL) {
|
||||
dprint("added wd = %i on %s\n", wd, cpath);
|
||||
rbtree_insert(&tree, wd, (void*)cpath);
|
||||
dprint("added wd = %i on %s\n", wd, npath);
|
||||
rbtree_insert(&tree, wd, (void*)npath, strlen(npath)+1);
|
||||
} else {
|
||||
dprint("updated wd = %i from %s to %s\n", wd, (char*)node->data, cpath);
|
||||
dprint("updated wd = %i from %s to %s\n", wd, (char*)node->data, npath);
|
||||
free(node->data);
|
||||
node->data = (void*) cpath;
|
||||
node->data = (void*) npath;
|
||||
node->len = strlen(npath)+1;
|
||||
}
|
||||
|
||||
return wd;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ rbtree :
|
|||
$(CC) $(CFLAGS) \
|
||||
unit.c \
|
||||
../src/common/die.c \
|
||||
../src/common/xalloc.c \
|
||||
../src/common/rbtree.c \
|
||||
t_rbtree.c -o test_rbtree
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ static int rb_assert(rbnode *node) {
|
|||
|
||||
/* data */
|
||||
static rbtree tree;
|
||||
static uint keyref[NODES];
|
||||
static uint keyref[NODES];
|
||||
static char *dataref[NODES];
|
||||
static uint search_key = -1;
|
||||
static char search_data[32];
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ void test_insert() {
|
|||
data = utest_ran_string(32);
|
||||
|
||||
/* insert into rbtree and assert it */
|
||||
ret = rbtree_insert(&tree, ckey, data);
|
||||
ret = rbtree_insert(&tree, ckey, data, 32);
|
||||
rb_assert(tree.root);
|
||||
|
||||
dprint("INSERT: %i %s\n", ckey, data);
|
||||
|
|
@ -89,6 +90,7 @@ void test_insert() {
|
|||
continue;
|
||||
|
||||
keyref[i] = ckey;
|
||||
dataref[i] = data;
|
||||
|
||||
if (i == ((NODES/2))) {
|
||||
search_key = ckey;
|
||||
|
|
@ -99,7 +101,7 @@ void test_insert() {
|
|||
}
|
||||
|
||||
/* insert duplicate key */
|
||||
assert(rbtree_insert(&tree, search_key, "duplicate") == -1);
|
||||
assert(rbtree_insert(&tree, search_key, "duplicate", 10) == -1);
|
||||
rb_assert(tree.root);
|
||||
}
|
||||
|
||||
|
|
@ -107,13 +109,16 @@ void test_delete() {
|
|||
|
||||
int i;
|
||||
uint key;
|
||||
char *data, *dref;
|
||||
|
||||
/* remove some values */
|
||||
for(i=0; i < 10; i++) {
|
||||
|
||||
key = keyref[(NODES/2)+i];
|
||||
dref = dataref[(NODES/2)+i];
|
||||
|
||||
rbtree_delete(&tree, key);
|
||||
data = rbtree_delete(&tree, key);
|
||||
assert_string(data, dref);
|
||||
rb_assert(tree.root);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue