From 4a174df6da863325c39c6cdac7ebd8397fce3d2a Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 24 Aug 2022 12:28:45 +0300 Subject: [PATCH] Add rbtree iterator implementation --- src/__internal/include.h | 13 ++++ src/__internal/rbtree.h | 12 ++- src/rbtree.c | 157 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+), 3 deletions(-) diff --git a/src/__internal/include.h b/src/__internal/include.h index 1fcb493..ab46005 100644 --- a/src/__internal/include.h +++ b/src/__internal/include.h @@ -64,6 +64,17 @@ extern int libcdsb_builtin_vtype_compare_values (const void* s0, vtype t0, extern int libcdsb_builtin_vtype_compare_values_eq(const void* s0, const void* s1, vtype t) pure__ wur__; extern hash_t libcdsb_builtin_vtype_hash (const void* value, vtype type) pure__ wur__; +ainline(stack_t* libcdsb_builtin_stack_insert(stack_t* x, void* v)) { + stack_t* p = x->prev; + + if (!is_null(x->prev = malloc(sizeof(*x)))) { + x->prev->prev = p; + x->prev->value = v; + } else abort(); + + return x->prev; +} + #define aligned_alloc libcdsb_aalloc #define malloc libcdsb_malloc #define calloc libcdsb_calloc @@ -72,7 +83,9 @@ extern hash_t libcdsb_builtin_vtype_hash (const void* value, vtype t #define stack_init libcdsb_stack_init #define stack_push libcdsb_stack_push #define stack_push_many libcdsb_stack_push_many +#define stack_insert libcdsb_builtin_stack_insert #define stack_pop libcdsb_stack_pop +#define stack_reverse libcdsb_stack_reverse #define stack_flush libcdsb_stack_flush #define strlen libcdsb_strlen #define strasciilen libcdsb_strasciilen diff --git a/src/__internal/rbtree.h b/src/__internal/rbtree.h index a974485..3cdde2b 100644 --- a/src/__internal/rbtree.h +++ b/src/__internal/rbtree.h @@ -21,9 +21,10 @@ extern void* libcdsb_builtin_rbtree_node_create(void* value, rbnode_t* paren extern void libcdsb_builtin_rbtree_node_fixup (rbnode_t** root, rbnode_t* node) Nonnull__(1,2); extern rbnode_t* libcdsb_builtin_rbtree_node_delete(rbnode_t** root, rbnode_t* node) Nonnull__(1,2); -extern rbnode_t* libcdsb_builtin_rbtree_next_inorder (rbnode_t** root, rbnode_t* prev, bool reverse); -extern rbnode_t* libcdsb_builtin_rbtree_next_preorder (rbnode_t** root, rbnode_t* prev, bool reverse); -extern rbnode_t* libcdsb_builtin_rbtree_next_postorder(rbnode_t** root, rbnode_t* prev, bool reverse); +extern stack_t libcdsb_builtin_rbtree_iter_inorder (rbnode_t** root, bool reverse); +extern stack_t libcdsb_builtin_rbtree_iter_preorder (rbnode_t** root, bool reverse); +extern stack_t libcdsb_builtin_rbtree_iter_postorder (rbnode_t** root, bool reverse); +extern stack_t libcdsb_builtin_rbtree_iter_breath_first(rbnode_t** root, bool reverse); #define rbnode_empty ((rbnode_t*)LIBCDSB_BUILTIN_RBTREE_NODE_EMPTY) #define rbnode_create(v, p, c) ((rbnode_t*)libcdsb_builtin_rbtree_node_create(v, p, c, sizeof(rbnode_t))) @@ -33,4 +34,9 @@ extern rbnode_t* libcdsb_builtin_rbtree_next_postorder(rbnode_t** root, rbnode_t #define rbnode_is_empty(n) ((n) == rbnode_empty) #define rbnode_is_root(n) rbnode_is_empty((n)->parent) +#define rbiter_inorder libcdsb_builtin_rbtree_iter_inorder +#define rbiter_preorder libcdsb_builtin_rbtree_iter_preorder +#define rbiter_postorder libcdsb_builtin_rbtree_iter_postorder +#define rbiter_breath_first libcdsb_builtin_rbtree_iter_breath_first + #endif /* LIBCDSB_SRC_INTERNAL_RBTREE_H */ diff --git a/src/rbtree.c b/src/rbtree.c index 4d9df47..025ff6d 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -193,3 +193,160 @@ void* libcdsb_builtin_rbtree_node_create(void* v, rbnode_t* p, int c, int n) { return x; } + + +stack_t libcdsb_builtin_rbtree_iter_inorder(rbnode_t** root, bool reverse) { + rbnode_t *n, hack; + stack_t z, *bot; + + memset(&z, 0, sizeof(z)); + + if (rbnode_is_empty(*root)) + return z; + + hack.right = *root; + n = &hack; + + for (bot = &z;;) { + for (;;) { + if (rbnode_is_empty(n->right)) { + + if (rbnode_is_root(n->parent) || n->parent->left == n) { + n = n->parent; + break; + } else n = n->parent; + + if (rbnode_is_root(n->parent) || n->parent->left == n) { + n = n->parent; + break; + } + + do { + n = n->parent; + } while (n->parent->right == n); + + n = n->parent; + } else { + n = n->right; + + while (!rbnode_is_empty(n->left)) + n = n->left; + + break; + } + + if (rbnode_is_root(n)) { + bot = z.prev; + z = *bot; + + free(bot); + + if (reverse) + stack_reverse(&z); + + return z; + } + } + + bot = stack_insert(bot, n); + } +} + + +stack_t libcdsb_builtin_rbtree_iter_preorder(rbnode_t** root, bool reverse) { + stack_t z, *cur, *next; + rbnode_t *n; + + memset(&z, 0, sizeof(z)); + + if (rbnode_is_empty(*root)) + return z; + + z.value = *root; + cur = &z; + + do { + n = (next = cur)->value; + + if (!rbnode_is_empty(n->left)) next = stack_insert(cur, n->left); + if (!rbnode_is_empty(n->right)) stack_insert(next, n->right); + } while (!is_null(cur = cur->prev)); + + if (reverse) + stack_reverse(&z); + + return z; +} + + +stack_t libcdsb_builtin_rbtree_iter_postorder(rbnode_t** root, bool reverse) { + rbnode_t *p, *n; + stack_t z, *bot; + + bot = &z; + z.prev = 0; + z.value = 0; + + if (rbnode_is_empty(p = *root)) + return z; + + goto mid_; + + do { + if (n->parent->right != n && !rbnode_is_empty(n->parent->right)) { + p = n->parent->right; + do { mid_: + n = p; + p = !rbnode_is_empty(p->left) ? p->left : p->right; + } while (!rbnode_is_empty(p)); + } else n = n->parent; + + bot = stack_insert(bot, n); + } while (!rbnode_is_root(n)); + + bot = z.prev; + z = *bot; + + free(bot); + + if (reverse) + stack_reverse(&z); + + return z; +} + + +stack_t libcdsb_builtin_rbtree_iter_breath_first(rbnode_t** root, bool reverse) { + + stack_t z, *top, *bot, *cur; + rbnode_t* n; + + memset(&z, 0, sizeof(z)); + + if (rbnode_is_empty(z.value = *root)) + return z; + + for (top = bot = &z;;) { + for (cur = bot;;) { + + n = top->value; + + if (!rbnode_is_empty(n->left)) cur = stack_insert(cur, n->left); + if (!rbnode_is_empty(n->right)) cur = stack_insert(cur, n->right); + + if (top == bot) { + top = top->prev; + break; + } else top = top->prev; + } + + if (!is_null(top)) { + while (!is_null(bot->prev)) bot = bot->prev; + } else break; + } + + if (reverse) + stack_reverse(&z); + + return z; +}