Update rbtree-based foreach implementation
This commit is contained in:
parent
4a174df6da
commit
1d8e8efe90
100
src/map/access.c
100
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
101
src/set/access.c
101
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user