From e94cdc978388debfbe183d226fc7daf5617390b9 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Tue, 7 Jun 2022 21:34:30 +0300 Subject: [PATCH 1/4] Clean the rbtree implementation --- src/__internal/rbtree.h | 23 +---- src/rbtree.c | 194 ++-------------------------------------- 2 files changed, 7 insertions(+), 210 deletions(-) diff --git a/src/__internal/rbtree.h b/src/__internal/rbtree.h index 33d4fb5..79edf6b 100644 --- a/src/__internal/rbtree.h +++ b/src/__internal/rbtree.h @@ -6,14 +6,6 @@ #ifndef LIBCDSB_SRC_INTERNAL_RBTREE_H #define LIBCDSB_SRC_INTERNAL_RBTREE_H -typedef enum libcdsb_rbtree_iter_flags { - RBI_INORDER = 0, - RBI_PREORDER = 1, - RBI_POSTORDER = 2, - - RBI_REVERSE = 4, -} rbiter_f; - typedef struct libcdsb_rbtree_node { struct libcdsb_rbtree_node* left; struct libcdsb_rbtree_node* right; @@ -23,30 +15,17 @@ typedef struct libcdsb_rbtree_node { short colored; } rbnode_t; -typedef struct libcdsb_rbtree_iter { - struct libcdsb_rbtree_node* cursor; - int flags; -} rbiter_t; - -extern const rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1]; +extern rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1]; extern void* libcdsb_rbtree_node_create(void* value, rbnode_t* parent, int colored, int size); extern void libcdsb_rbtree_node_fixup (rbnode_t** root, rbnode_t* node); extern rbnode_t* libcdsb_rbtree_node_delete(rbnode_t** root, rbnode_t* node); -extern _Bool libcdsb_rbtree_iter_init (rbiter_t* iter, rbnode_t *const *root, rbiter_f flags); -extern rbnode_t* libcdsb_rbtree_iter_next (rbiter_t* iter); -extern void libcdsb_rbtree_iter_reset(rbiter_t* iter); - #define rbnode_empty ((rbnode_t*)LIBCDSB_RBTREE_NODE_EMPTY) #define rbnode_create(v, p, c) ((rbnode_t*)libcdsb_rbtree_node_create(v, p, c, sizeof(rbnode_t))) #define rbnode_fixup libcdsb_rbtree_node_fixup #define rbnode_delete libcdsb_rbtree_node_delete -#define rbiter_init libcdsb_rbtree_iter_init -#define rbiter_next libcdsb_rbtree_iter_next -#define rbiter_reset libcdsb_rbtree_iter_reset - #define rbnode_is_empty(n) ((n) == rbnode_empty) #define rbnode_is_root(n) rbnode_is_empty((n)->parent) diff --git a/src/rbtree.c b/src/rbtree.c index a8681b7..9c7d328 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -3,9 +3,6 @@ #include "__internal/rbtree.h" -#define RBI_BREAK ((rbiter_f)3) -#define RBI_FIRST ((rbiter_f)8) - typedef enum libcdsb_rbtree_node_direction { RBD_LEFT = 1, RBD_RIGHT = 2 @@ -16,7 +13,7 @@ typedef enum libcdsb_rbtree_node_direction { /*#####################################################################################################################*/ -const rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{ +rbnode_t LIBCDSB_RBTREE_NODE_EMPTY[1] = {{ .colored = 0, .value = 0, .parent = rbnode_empty, @@ -45,105 +42,12 @@ static inline void rotate(rbnode_t **x, rbnode_t *c, rbdir_t d) { } static inline void replace(rbnode_t** x, rbnode_t* c, rbnode_t* n) { - rbnode_t* p; - - p = c->parent; - - if (!rbnode_is_empty(p)) { - if (p->left == c) { - p->left = n; - } else p->right = n; + if (!rbnode_is_root(c)) { + if (c->parent->left == c) { + c->parent->left = n; + } else c->parent->right = n; } else *x = n; - - n->parent = p; -} - - -/*#####################################################################################################################*/ - - -static rbnode_t* inorder_next(rbnode_t* c, rbiter_f f) { - rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; - rbnode_t* p; - - for (;;) { - if (rbnode_is_empty(rbdir_inv(c, d))) { - p = c->parent; - - if (rbnode_is_root(p) || rbdir_dir(p, d) == c) { - return p; - } - - c = p; - p = c->parent; - - if (rbnode_is_root(p) || rbdir_dir(p, d) == c) { - return p; - } - - do { - c = p; - p = c->parent; - } while(rbdir_inv(p, d) == c); - - c = p; - - } else { c = rbdir_inv(c, d); break; } - - if (rbnode_is_root(c)) return c; - } - - while (!rbnode_is_empty(rbdir_dir(c, d))) - c = rbdir_dir(c, d); - - return c; -} - -static rbnode_t* postorder_next(rbnode_t* c, rbiter_f f) { - rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; - rbnode_t* p; - - if (rbnode_is_empty(p = c->parent)) - return c; - - if (rbdir_dir(p, d) == c && !rbnode_is_empty(rbdir_inv(p, d))) { - c = rbdir_inv(p, d); - - while (!rbnode_is_empty(c)) { - p = c; - c = (!rbnode_is_empty(rbdir_inv(p, d))) - ? rbdir_inv(p, d) - : rbdir_dir(p, d); - } - } - - return p; -} - -static rbnode_t* preorder_next(rbnode_t* c, rbiter_f f) { - rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; - rbnode_t* p; - - if (!rbnode_is_empty(rbdir_dir(c, d))) - return rbdir_dir(c, d); - - for (;;) { - if (!rbnode_is_empty(rbdir_inv(c, d))) { - return rbdir_inv(c, d); - } - - p = c->parent; - - while (rbdir_inv(p, d) == c) { - c = p; - p = c->parent; - } - - if (rbnode_is_empty(p)) - return c; - - c = p; - } + n->parent = c->parent; } @@ -290,89 +194,3 @@ void* libcdsb_rbtree_node_create(void* v, rbnode_t* p, int c, int n) { return x; } - - -/*#####################################################################################################################*/ - - -_Bool libcdsb_rbtree_iter_init(rbiter_t* iter, rbnode_t *const *root, rbiter_f f) { - rbdir_t d = (f&RBI_REVERSE) ? RBD_RIGHT : RBD_LEFT; - rbnode_t* c = *root; - - if (!rbnode_is_empty(c)) { - if (!(f&RBI_BREAK)) { - while (rbdir_dir(c, d) != rbnode_empty) { - c = rbdir_dir(c, d); - } - } else if ((f&RBI_BREAK) == RBI_POSTORDER) { - rbnode_t* p; - - do { - p = c; - c = (!rbnode_is_empty(rbdir_dir(c, d))) ? rbdir_dir(c, d) : rbdir_inv(c, d); - } while (!rbnode_is_empty(c)); - - c = p; - } - } else { - iter->cursor = rbnode_empty; - iter->flags = 0; - return false; - } - - iter->cursor = c; - iter->flags = f|RBI_FIRST; - - return true; -} - - - -void libcdsb_rbtree_iter_reset(rbiter_t* iter) { - if (iter->flags&RBI_FIRST) return; - - while (!rbnode_is_empty(iter->cursor->parent)) { - iter->cursor = iter->cursor->parent; - } - - if ((iter->flags&RBI_BREAK) == RBI_BREAK) { - libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags&~RBI_BREAK); - } else libcdsb_rbtree_iter_init(iter, &iter->cursor, iter->flags); -} - - -rbnode_t* libcdsb_rbtree_iter_next(rbiter_t* iter) { - - rbnode_t* c; - - c = iter->cursor; - - if (rbnode_is_empty(c)) - return rbnode_empty; - - if (!(iter->flags&RBI_FIRST)) { - if (rbnode_is_root(c)) { - if ((iter->flags&RBI_BREAK) == RBI_INORDER) { - iter->flags |= RBI_BREAK; - } else { - libcdsb_rbtree_iter_reset(iter); - if (iter->flags&RBI_POSTORDER) { - iter->flags |= RBI_BREAK; - return c; - } else return rbnode_empty; - } - } - } else if ((iter->flags&RBI_BREAK) == RBI_BREAK) { - iter->flags = (iter->flags&~(RBI_BREAK^RBI_POSTORDER)); - return rbnode_empty; - } else iter->flags &= ~RBI_FIRST; - - switch (iter->flags&RBI_BREAK) { - case RBI_POSTORDER: iter->cursor = postorder_next(c, iter->flags); break; - case RBI_PREORDER: iter->cursor = preorder_next(c, iter->flags); break; - case RBI_INORDER: - default: iter->cursor = inorder_next(c, iter->flags); break; - } - - return c; -} From 8a813e877adea6c8e12a0845449fd45ff39f2574 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Tue, 7 Jun 2022 21:35:13 +0300 Subject: [PATCH 2/4] Add stack --- include/extra/memory.h | 15 ++++++++++++ src/extra.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/include/extra/memory.h b/include/extra/memory.h index d0a584d..fb3ca3a 100644 --- a/include/extra/memory.h +++ b/include/extra/memory.h @@ -7,6 +7,16 @@ #ifndef LIBCDSB_EXTRA_MEMORY_H #define LIBCDSB_EXTRA_MEMORY_H +typedef struct libcdsb_stack_node { + struct libcdsb_stack_node* prev; + void* value; +} stack_t; + +extern void libcdsb_stack_init (stack_t* stack); +extern void libcdsb_stack_push (stack_t* stack, void* value); +extern void* libcdsb_stack_pop (stack_t* stack); +extern void libcdsb_stack_flush(stack_t* stack); + extern void* libcdsb_aalloc (size_t a, size_t n) LIBCDSB_nt__ LIBCDSB_wur__; extern void* libcdsb_malloc (size_t n) LIBCDSB_nt__ LIBCDSB_wur__; extern void* libcdsb_calloc (size_t n, size_t c) LIBCDSB_nt__ LIBCDSB_wur__; @@ -17,4 +27,9 @@ extern void* libcdsb_realloc(void *p, size_t n) LIBCDSB_nt__ LIBCDSB_wur__; #define calloc libcdsb_calloc #define realloc libcdsb_realloc +#define stack_init libcdsb_stack_init +#define stack_push libcdsb_stack_push +#define stack_pop libcdsb_stack_pop +#define stack_flush libcdsb_stack_flush + #endif /* LIBCDSB_EXTRA_MEMORY_H */ diff --git a/src/extra.c b/src/extra.c index 4d8ae6a..a1c261c 100644 --- a/src/extra.c +++ b/src/extra.c @@ -81,6 +81,59 @@ char* libcdsb_strndup(const char* s, size_t n) { /*#####################################################################################################################*/ +void libcdsb_stack_init(stack_t* x) { + memset(x, 0, sizeof(*x)); +} + + +void libcdsb_stack_push(stack_t* x, void* value) { + stack_t* n; + + if (x->value) { + if (!(n = malloc(sizeof(*n)))) + abort(); + + n->prev = x->prev; + n->value = x->value; + x->prev = n; + } + + x->value = value; +} + +void* libcdsb_stack_pop(stack_t* x) { + + stack_t* n; + void* v; + + v = x->value; + + if (x->prev) { + n = x->prev; + x->prev = n->prev; + x->value = n->value; + free(n); + } else x->value = 0; + + return v; +} + + +void libcdsb_stack_flush(stack_t* stack) { + stack_t* c; + + while (stack->prev) { + c = stack->prev; + stack->prev = c->prev; + free(c); + } + + stack->value = 0; +} + +/*#####################################################################################################################*/ + + size_t libcdsb_strlen(const char* s) { static const size_t m = (sizeof(size_t) == 8) ? 0x8080808080808080UL : 0x80808080UL; static const size_t d = (sizeof(size_t) == 8) ? 0x0101010101010101UL : 0x01010101UL; From b6a97576e4c7b899dc179cc552801eb7dcf22dfb Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Tue, 7 Jun 2022 21:41:09 +0300 Subject: [PATCH 3/4] Change iteration implementation to the stack based --- src/set/base.c | 94 +++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/set/base.c b/src/set/base.c index 0b93fbb..141801a 100644 --- a/src/set/base.c +++ b/src/set/base.c @@ -4,36 +4,6 @@ #include "../../include/set.h" #include "../__internal/rbtree.h" -/*#####################################################################################################################*/ - - -static int tree_compare(rbiter_t* s0, rbiter_t* s1, vtype t) { - rbnode_t* p0; - rbnode_t* p1; - int cmp; - - for(;;) { - p0 = rbiter_next(s0); - p1 = rbiter_next(s1); - - if (rbnode_is_empty(p0) || rbnode_is_empty(p1)) { - goto end_; - } else cmp = vnode_compare(&p0->value, t, &p1->value, t); - - if (cmp != 0) break; - } - - for(;;) { - p0 = rbiter_next(s0); - p1 = rbiter_next(s1); - - if (rbnode_is_empty(p0) || rbnode_is_empty(p1)) { - end_: - if (p0 == p1) return cmp; - return (rbnode_is_empty(p0)) ? -1 : 1; - } - } -} /*#####################################################################################################################*/ @@ -43,10 +13,13 @@ void vset_init(vtype_set* x, vtype t) { x->type = t; } + void vset_free(vtype_set* x) { rbnode_t* t; rbnode_t* c; + c = x->root; + while (!rbnode_is_empty(x->root)) { if (!rbnode_is_empty(c->left)) { c = c->left; @@ -71,28 +44,61 @@ void vset_free(vtype_set* x) { x->type = 0; } + size_t vset_size(const vtype_set* x) { - size_t n; - rbiter_t i; + stack_t s = { .prev = 0, .value = x->root }; + size_t n = 0; + rbnode_t* c; - n = 0; - - if (rbiter_init(&i, &x->root, 0)) { - while (!rbnode_is_empty(rbiter_next(&i))) - ++n; + while ((c = stack_pop(&s))) { + ++n; + if (!rbnode_is_empty(c->left)) + stack_push(&s, c->left); + if (!rbnode_is_empty(c->right)) + stack_push(&s, c->right); } return n; } + int vset_compare(const vtype_set* s0, const vtype_set* s1) { - rbiter_t iter[2]; + stack_t s = { .prev = 0, .value = 0 }; + vtype t = s0->type; + int c = 0; - if (s0 == s1) return 0; - if (s0->type == s1->type) { - rbiter_init(iter+0, &s0->root, RBI_INORDER); - rbiter_init(iter+1, &s1->root, RBI_INORDER); + if (s0 == s1 || s0->root == s1->root) return 0; + if (s0->type != s1->type) return s0->type - s1->type; - return tree_compare(iter+0, iter+1, s0->type); - } else return s0->type < s1->type ? -1 : 1; + stack_push(&s, s0->root); + stack_push(&s, s1->root); + + for (rbnode_t *c0, *c1;;) { + c0 = stack_pop(&s); + c1 = stack_pop(&s); + + if (is_null(c0)) return 0; + + if (rbnode_is_empty(c0) || rbnode_is_empty(c1)) { + if (c0 != c1) { + stack_flush(&s); + return rbnode_is_empty(c0) ? -1 : 1; + } + } else if ((c = vnode_compare(c0->value, t, c1->value, t))) { + if (c0->left == c1->right) { + c = vnode_compare(c1->value, t, c0->right->value, t); + if (!c) c = vnode_compare(c1->left->value, t, c0->value, t); + } else if (c0->right == c1->left) { + c = vnode_compare(c0->value, t, c1->right->value, t); + if (!c) c = vnode_compare(c0->left->value, t, c1->value, t); + } + + if (c) { stack_flush(&s); return c; } + } else { + stack_push(&s, c0->left); + stack_push(&s, c1->left); + stack_push(&s, c0->right); + stack_push(&s, c1->right); + } + } } From 0922870d0478c825cac1fd672ce26d831e01e641 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Tue, 7 Jun 2022 21:42:11 +0300 Subject: [PATCH 4/4] Extend the foreach implementation --- include/extra/array.h | 2 +- include/extra/list.h | 2 +- include/extra/set.h | 2 +- src/array/extra.c | 4 ++-- src/list/extra.c | 4 ++-- src/set/extra.c | 22 ++++++++++++++-------- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/include/extra/array.h b/include/extra/array.h index fd662a9..f720a78 100644 --- a/include/extra/array.h +++ b/include/extra/array.h @@ -17,6 +17,6 @@ extern ssize_t libcdsb_array_get(vtype_value* x, vtype_array* s, ssize_t index, extern ssize_t libcdsb_array_find(const vtype_array* x, const void* value, vtype value_type) LIBCDSB_nt__ LIBCDSB_nn1__; extern ssize_t libcdsb_array_push( vtype_array* x, const void* value, vtype value_type) LIBCDSB_nt__ LIBCDSB_nn1__; -extern int libcdsb_array_foreach(const vtype_array* x, int (*callback)(void* value, ssize_t index, vtype type)) LIBCDSB_nt__ LIBCDSB_nn12__; +extern int libcdsb_array_foreach(const vtype_array* x, void* data, int (*callback)(void* value, ssize_t index, vtype type, void* data)) LIBCDSB_nt__ LIBCDSB_nn13__; #endif /* LIBCDSB_EXTRA_ARRAY_H */ diff --git a/include/extra/list.h b/include/extra/list.h index 6ef3c89..a227b0e 100644 --- a/include/extra/list.h +++ b/include/extra/list.h @@ -19,6 +19,6 @@ extern size_t libcdsb_list_count(const vtype_list* s, const void* value, vtype extern ssize_t libcdsb_list_get(vtype_value* x, vtype_list* s, ssize_t index, _Bool cut) LIBCDSB_nt__ LIBCDSB_nn2__; -extern int libcdsb_list_foreach(const vtype_list* x, int (*callback)(void* value, ssize_t index, vtype type)) LIBCDSB_nt__ LIBCDSB_nn12__; +extern int libcdsb_list_foreach(const vtype_list* x, void* data, int (*callback)(void* value, ssize_t index, vtype type, void* data)) LIBCDSB_nt__ LIBCDSB_nn13__; #endif /* LIBCDSB_EXTRA_LIST_H */ diff --git a/include/extra/set.h b/include/extra/set.h index 80fabf9..7f37db5 100644 --- a/include/extra/set.h +++ b/include/extra/set.h @@ -11,6 +11,6 @@ extern _Bool libcdsb_vset_find (vtype_value* x, vtype_set* s, const void* value, vtype type, _Bool cut); extern _Bool libcdsb_vset_insert(vtype_set* x, const void* value, vtype type); -extern int libcdsb_vset_foreach(const vtype_set* x, int (*callback)(const void* value, vtype type)) LIBCDSB_nt__ LIBCDSB_nn12__; +extern int libcdsb_vset_foreach(const vtype_set* x, void* data, int (*callback)(const void* value, vtype type, void* data)) LIBCDSB_nt__ LIBCDSB_nn13__; #endif /* LIBCDSB_EXTRA_SET_H */ diff --git a/src/array/extra.c b/src/array/extra.c index 211d423..4486800 100644 --- a/src/array/extra.c +++ b/src/array/extra.c @@ -76,7 +76,7 @@ ssize_t libcdsb_array_get(val_t* x, arr_t* s, ssize_t i, _Bool cut) { /*#####################################################################################################################*/ -int libcdsb_array_foreach(const vtype_array* x, int (*callback)(void* value, ssize_t index, vtype type)) { +int libcdsb_array_foreach(const vtype_array* x, void* data, int (*callback)(void* value, ssize_t index, vtype type, void* data)) { void* p; void* e; @@ -88,7 +88,7 @@ int libcdsb_array_foreach(const vtype_array* x, int (*callback)(void* value, ssi n = 0; while (p < e) { - if ((r = callback(p, n, x->type))) + if ((r = callback(p, n, x->type, data))) return r; p += vtype_size(x->type); diff --git a/src/list/extra.c b/src/list/extra.c index 570b679..9e8405c 100644 --- a/src/list/extra.c +++ b/src/list/extra.c @@ -163,7 +163,7 @@ _Bool libcdsb_list_update(list_t* x, ssize_t i, const void* v, vtype t, int ins) /*#####################################################################################################################*/ -int libcdsb_list_foreach(const vtype_list* x, int (*callback)(void* value, ssize_t index, vtype type)) { +int libcdsb_list_foreach(const vtype_list* x, void* data, int (*callback)(void* value, ssize_t index, vtype type, void* data)) { lnode_t* c; size_t n; @@ -173,7 +173,7 @@ int libcdsb_list_foreach(const vtype_list* x, int (*callback)(void* value, ssize n = 0; while (!is_null(c)) { - if ((r = callback(vnode_peek(&c->node, c->type), n, c->type)) != 0) + if ((r = callback(vnode_peek(&c->node, c->type), n, c->type, data)) != 0) return r; c = c->next; ++n; diff --git a/src/set/extra.c b/src/set/extra.c index 3c3be91..9acc2d1 100644 --- a/src/set/extra.c +++ b/src/set/extra.c @@ -76,17 +76,23 @@ _Bool libcdsb_vset_insert(set_t* x, const void* v, vtype t) { /*#####################################################################################################################*/ -int libcdsb_vset_foreach(const vtype_set* x, int (*callback)(const void* value, vtype type)) { - rbiter_t i; - int r; +int libcdsb_vset_foreach(const set_t* x, void* data, int (*callback)(const void* value, vtype type, void* data)) { + stack_t s = { .prev = 0, .value = x->root }; + int r = 0; rbnode_t* c; - if (rbiter_init(&i, &x->root, 0)) { - while (!rbnode_is_empty(c = rbiter_next(&i))) { - if ((r = callback(vnode_peek(&c->value, x->type), x->type))) - return r; + if (rbnode_is_empty(x->root)) return 0; + + while ((c = stack_pop(&s))) { + if ((r = callback(vnode_peek(&c->value, x->type), x->type, data))) { + stack_flush(&s); + break; } + if (!rbnode_is_empty(c->left)) + stack_push(&s, c->left); + if (!rbnode_is_empty(c->right)) + stack_push(&s, c->right); } - return 0; + return r; }