Update rbtree-based foreach implementation

This commit is contained in:
Gregory Lirent 2022-08-24 12:29:55 +03:00
parent 4a174df6da
commit 1d8e8efe90
3 changed files with 142 additions and 64 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}