Update rbtree-based foreach implementation
This commit is contained in:
+69
-32
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user