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
|
* 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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue