Archived
1
0
Fork 0

common/rbtree: fixed a bug in delete

This commit is contained in:
Henrik Hautakoski 2010-10-02 08:20:48 +02:00
parent 8d7b4a74c7
commit 7209cfb1c4
7 changed files with 52 additions and 37 deletions

View file

@ -11,23 +11,20 @@
* http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx * http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
*/ */
#include <malloc.h> #include "xalloc.h"
#include "debug.h" #include "debug.h"
#include "rbtree.h" #include "rbtree.h"
#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(uint key, void *ptr) { static rbnode* node_alloc(uint key, void *ptr, size_t len) {
rbnode *n = malloc(sizeof(rbnode)); rbnode *n = xmalloc(sizeof(rbnode));
if (n == NULL)
return NULL;
n->key = key; n->key = key;
n->data = ptr; n->data = ptr;
n->len = len;
n->color = RB_RED; n->color = RB_RED;
n->child[0] = NULL; n->child[0] = NULL;
n->child[1] = NULL; n->child[1] = NULL;
@ -46,14 +43,14 @@ static void node_dealloc(rbnode *n, void (*action)(rbnode *)) {
if (action != NULL) { if (action != NULL) {
action(n); action(n);
} else if (n->data != NULL) { } else if (n->data != NULL) {
free(n->data); xfree(n->data);
n->data = NULL; n->data = NULL;
} }
node_dealloc(n->child[0], action); node_dealloc(n->child[0], action);
node_dealloc(n->child[1], 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 * 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}; rbnode head = {0};
@ -198,7 +195,7 @@ int rbtree_insert(rbtree *tree, uint key, void *data) {
unsigned char dir = 0, dir2, last, inserted = 0; unsigned char dir = 0, dir2, last, inserted = 0;
if (tree->root == NULL) { if (tree->root == NULL) {
tree->root = node_alloc(key, data); tree->root = node_alloc(key, data, len);
if (tree->root == NULL) if (tree->root == NULL)
return 0; return 0;
goto done; goto done;
@ -212,7 +209,7 @@ int rbtree_insert(rbtree *tree, uint key, void *data) {
for(;;) { for(;;) {
if (q == NULL) { if (q == NULL) {
p->child[dir] = q = node_alloc(key, data); p->child[dir] = q = node_alloc(key, data, len);
if (q == NULL) if (q == NULL)
return 0; return 0;
inserted = 1; inserted = 1;
@ -325,18 +322,15 @@ void* rbtree_delete(rbtree *tree, uint key) {
tree->root->color = RB_BLACK; tree->root->color = RB_BLACK;
/* remove if found */ /* remove if found */
if (f != NULL) { if (f) {
ret = q->data; ret = f->data;
if (q == tree->root) { if (f != q) {
tree->root = NULL; f->key = q->key;
} else { f->data = xmemdup(q->data, q->len);
if (f != q) { f->len = q->len;
f->key = q->key; }
f->data = q->data; swap(p, 1, q) = swap(q, 0, NULL);
} xfree(q);
swap(p, 1, q) = swap(q, 0, NULL);
}
free(q);
} }
return ret; return ret;

View file

@ -42,7 +42,7 @@ void rbtree_walk(rbtree *tree, void (*action)(rbnode *));
void rbtree_free(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); void* rbtree_delete(rbtree *tree, uint key);

View file

@ -75,6 +75,17 @@ bail:
die_errno("xstrdup"); 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) { void xfree(void *ptr) {
CHECK_INPUT(ptr); CHECK_INPUT(ptr);

View file

@ -21,6 +21,8 @@ void* xrealloc(void *, size_t);
char* xstrdup(const char *); char* xstrdup(const char *);
void* xmemdup(const void *, size_t);
void xfree(void *); void xfree(void *);
#endif /* __COMMON_XALLOC_H */ #endif /* __COMMON_XALLOC_H */

View file

@ -42,16 +42,17 @@ static queue_t event_queue;
static int addwatch(const char *path, const char *name) { static int addwatch(const char *path, const char *name) {
rbnode *node; rbnode *node;
char *cpath; char *npath;
int wd; 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) { if (wd < 0) {
perror("NOTIFY ADD"); perror("NOTIFY ADD");
dprint("%i path %s\n", errno == EBADF, cpath); dprint("%i path %s\n", errno == EBADF, npath);
free(npath);
return -errno; return -errno;
} }
@ -59,12 +60,13 @@ static int addwatch(const char *path, const char *name) {
node = rbtree_search(&tree, wd); node = rbtree_search(&tree, wd);
if (node == NULL) { if (node == NULL) {
dprint("added wd = %i on %s\n", wd, cpath); dprint("added wd = %i on %s\n", wd, npath);
rbtree_insert(&tree, wd, (void*)cpath); rbtree_insert(&tree, wd, (void*)npath, strlen(npath)+1);
} else { } 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); free(node->data);
node->data = (void*) cpath; node->data = (void*) npath;
node->len = strlen(npath)+1;
} }
return wd; return wd;

View file

@ -28,6 +28,7 @@ rbtree :
$(CC) $(CFLAGS) \ $(CC) $(CFLAGS) \
unit.c \ unit.c \
../src/common/die.c \ ../src/common/die.c \
../src/common/xalloc.c \
../src/common/rbtree.c \ ../src/common/rbtree.c \
t_rbtree.c -o test_rbtree t_rbtree.c -o test_rbtree

View file

@ -60,7 +60,8 @@ static int rb_assert(rbnode *node) {
/* data */ /* data */
static rbtree tree; static rbtree tree;
static uint keyref[NODES]; static uint keyref[NODES];
static char *dataref[NODES];
static uint search_key = -1; static uint search_key = -1;
static char search_data[32]; static char search_data[32];
@ -79,7 +80,7 @@ void test_insert() {
data = utest_ran_string(32); data = utest_ran_string(32);
/* insert into rbtree and assert it */ /* insert into rbtree and assert it */
ret = rbtree_insert(&tree, ckey, data); ret = rbtree_insert(&tree, ckey, data, 32);
rb_assert(tree.root); rb_assert(tree.root);
dprint("INSERT: %i %s\n", ckey, data); dprint("INSERT: %i %s\n", ckey, data);
@ -89,6 +90,7 @@ void test_insert() {
continue; continue;
keyref[i] = ckey; keyref[i] = ckey;
dataref[i] = data;
if (i == ((NODES/2))) { if (i == ((NODES/2))) {
search_key = ckey; search_key = ckey;
@ -99,7 +101,7 @@ void test_insert() {
} }
/* insert duplicate key */ /* insert duplicate key */
assert(rbtree_insert(&tree, search_key, "duplicate") == -1); assert(rbtree_insert(&tree, search_key, "duplicate", 10) == -1);
rb_assert(tree.root); rb_assert(tree.root);
} }
@ -107,13 +109,16 @@ void test_delete() {
int i; int i;
uint key; uint key;
char *data, *dref;
/* remove some values */ /* remove some values */
for(i=0; i < 10; i++) { for(i=0; i < 10; i++) {
key = keyref[(NODES/2)+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); rb_assert(tree.root);
} }
} }