From 1d8e8efe90c3e429d6fc0bb05a5ba351cbf33f9f Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 24 Aug 2022 12:29:55 +0300 Subject: [PATCH] Update rbtree-based foreach implementation --- src/map/access.c | 100 ++++++++++++++++++++++++++++++--------------- src/map/include.h | 5 +++ src/set/access.c | 101 +++++++++++++++++++++++++++++++--------------- 3 files changed, 142 insertions(+), 64 deletions(-) diff --git a/src/map/access.c b/src/map/access.c index 83c51fe..d3b62cc 100644 --- a/src/map/access.c +++ b/src/map/access.c @@ -3,6 +3,48 @@ #include "include.h" +static int libcdsb_builtin_foreach(map_t* x, void* data, map_access_callback callback) { + stack_t z, *top, *bot, *cur; + mnode_t* n; + int r = 0; + + memset(&z, 0, sizeof(z)); + + if (rbnode_is_empty(z.value = x->root)) + return 0; + + for (top = bot = &z;;) { + for (cur = bot;;) { + + n = top->value; + + if (!mnode_is_empty(n->left)) cur = stack_insert(cur, n->left); + if (!mnode_is_empty(n->right)) cur = stack_insert(cur, n->right); + + if (!r) { + r = callback(vnode_peek(&n->key, x->type), x->type, vnode_peek(&n->value, n->type), n->type, data); + } else { + stack_flush(&z); + return r; + } + + 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; + } + + stack_flush(&z); + return r; +} + +/*#####################################################################################################################*/ + int libcdsb_map_find(map_t* x, const void* k, vtype t, void* _, map_access_callback callback, bool cut) { mnode_t* c; void *key; @@ -32,47 +74,41 @@ int libcdsb_map_find(map_t* x, const void* k, vtype t, void* _, map_access_callb } -int libcdsb_map_foreach(map_t* x, void* dt, map_access_callback callback, bool flush) { - stack_t z; - int r; - mnode_t* c; +int libcdsb_map_foreach(map_t* x, void* data, map_access_callback callback, rbforeach_t type, bool flush) { + bool reverse; + stack_t iter; + mnode_t* n; + int r = 0; - stack_init(&z); - stack_push(&z, x->root); + reverse = type&RBFOREACH_REVERSE; - r = 0; + switch (type&(RBFOREACH_INORDER|RBFOREACH_PREORDER|RBFOREACH_POSTORDER|RBFOREACH_BREADTH_FIRST)) { + case RBFOREACH_INORDER: iter = miter_inorder (&x->root, reverse); break; + case RBFOREACH_PREORDER: iter = miter_preorder (&x->root, reverse); break; + case RBFOREACH_POSTORDER: iter = miter_postorder(&x->root, reverse); break; - if (mnode_is_empty(x->root)) - return 0; + default: + case RBFOREACH_BREADTH_FIRST: if (reverse || flush) { + iter = miter_breath_first(&x->root, type&RBFOREACH_REVERSE); + break; + } else return libcdsb_builtin_foreach(x, data, callback); + } - while ((c = stack_pop(&z))) { - if ((r = callback(vnode_peek(&c->key, x->type), x->type, vnode_peek(&c->value, c->type), c->type, dt))) - break; - - if (!mnode_is_empty(c->right)) stack_push(&z, c->right); - if (!mnode_is_empty(c->left)) stack_push(&z, c->left); + while ((n = stack_pop(&iter))) { + if (!r) { + r = callback(vnode_peek(&n->key, x->type), x->type, vnode_peek(&n->value, n->type), n->type, data); + } else if (!flush) { + stack_flush(&iter); + return r; + } if (flush) { - vnode_free(&c->key, x->type); - vnode_free(&c->value, c->type); - free(c); + vnode_free(&n->value, x->type); + free(n); } } - if (flush) { - while (c) { - if (!mnode_is_empty(c->right)) stack_push(&z, c->right); - if (!mnode_is_empty(c->left)) stack_push(&z, c->left); - - vnode_free(&c->key, x->type); - vnode_free(&c->value, c->type); - free(c); - - c = stack_pop(&z); - } - - memset(x, 0, sizeof(*x)); - } else stack_flush(&z); + if (flush) x->root = mnode_empty; return r; } diff --git a/src/map/include.h b/src/map/include.h index 2c12f93..5587d97 100644 --- a/src/map/include.h +++ b/src/map/include.h @@ -35,4 +35,9 @@ static_assert(offsetof(struct libcdsb_set, type) == offsetof(struct l #define mnode_is_empty(n) ((n) == mnode_empty) #define mnode_is_root(n) mnode_is_empty((n)->parent) +#define miter_inorder(x, reverse) rbiter_inorder((void*)x, reverse) +#define miter_preorder(x, reverse) rbiter_preorder((void*)x, reverse) +#define miter_postorder(x, reverse) rbiter_postorder((void*)x, reverse) +#define miter_breath_first(x, reverse) rbiter_breath_first((void*)x, reverse) + #endif /* LIBCDSB_SRC_MAP_INCLUDE_H */ diff --git a/src/set/access.c b/src/set/access.c index 2f022c1..2e5a4c4 100644 --- a/src/set/access.c +++ b/src/set/access.c @@ -4,6 +4,48 @@ #include "../../include/set.h" #include "../__internal/rbtree.h" +static int libcdsb_builtin_foreach(set_t* x, void* data, vset_access_callback callback) { + stack_t z, *top, *bot, *cur; + rbnode_t* n; + int r = 0; + + memset(&z, 0, sizeof(z)); + + if (rbnode_is_empty(z.value = x->root)) + return 0; + + 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 (!r) { + r = callback(vnode_peek(&n->value, x->type), x->type, data); + } else { + stack_flush(&z); + return r; + } + + 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; + } + + stack_flush(&z); + return r; +} + +/*#####################################################################################################################*/ + int libcdsb_vset_find(vtype_set* x, const void* v, vtype t, void* _, vset_access_callback callback, bool cut) { rbnode_t* c; void *val; @@ -32,46 +74,41 @@ int libcdsb_vset_find(vtype_set* x, const void* v, vtype t, void* _, vset_access } -int libcdsb_vset_foreach(set_t* x, void* data, vset_access_callback callback, bool flush) { - stack_t z; - int r; - rbnode_t* c; +int libcdsb_vset_foreach(set_t* x, void* data, vset_access_callback callback, rbforeach_t type, bool flush) { + bool reverse; + stack_t iter; + rbnode_t* n; + int r = 0; - stack_init(&z); - stack_push(&z, x->root); + reverse = type&RBFOREACH_REVERSE; - r = 0; + switch (type&(RBFOREACH_INORDER|RBFOREACH_PREORDER|RBFOREACH_POSTORDER|RBFOREACH_BREADTH_FIRST)) { + case RBFOREACH_INORDER: iter = rbiter_inorder (&x->root, reverse); break; + case RBFOREACH_PREORDER: iter = rbiter_preorder (&x->root, reverse); break; + case RBFOREACH_POSTORDER: iter = rbiter_postorder(&x->root, reverse); break; + + default: + case RBFOREACH_BREADTH_FIRST: if (reverse || flush) { + iter = rbiter_breath_first(&x->root, type&RBFOREACH_REVERSE); + break; + } else return libcdsb_builtin_foreach(x, data, callback); + } - if (rbnode_is_empty(x->root)) - return 0; - - while ((c = stack_pop(&z))) { - if ((r = callback(vnode_peek(&c->value, x->type), x->type, data))) - break; - - - if (!rbnode_is_empty(c->right)) stack_push(&z, c->right); - if (!rbnode_is_empty(c->left)) stack_push(&z, c->left); + while ((n = stack_pop(&iter))) { + if (!r) { + r = callback(vnode_peek(&n->value, x->type), x->type, data); + } else if (!flush) { + stack_flush(&iter); + return r; + } if (flush) { - vnode_free(&c->value, x->type); - free(c); + vnode_free(&n->value, x->type); + free(n); } } - if (flush) { - while (c) { - if (!rbnode_is_empty(c->right)) stack_push(&z, c->right); - if (!rbnode_is_empty(c->left)) stack_push(&z, c->left); - - vnode_free(&c->value, x->type); - free(c); - - c = stack_pop(&z); - } - - memset(x, 0, sizeof(*x)); - } else stack_flush(&z); + if (flush) x->root = rbnode_empty; return r; }