115 lines
3.2 KiB
C
115 lines
3.2 KiB
C
/* This software is licensed by the MIT License, see LICENSE file */
|
|
/* Copyright © 2022 Gregory Lirent */
|
|
|
|
#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), 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, var_t value, void* _, vset_access_callback callback, bool cut) {
|
|
rbnode_t* c;
|
|
int cmp;
|
|
var_t v;
|
|
|
|
c = x->root;
|
|
|
|
while (!rbnode_is_empty(c)) {
|
|
v = vnode_peek(&c->value, x->type);
|
|
cmp = variable_compare(value, v);
|
|
|
|
if (cmp == 0) {
|
|
cmp = (callback) ? callback(v, _) : 0;
|
|
|
|
if (cut) {
|
|
c = rbnode_delete(&x->root, c);
|
|
vnode_free(&c->value, x->type);
|
|
free(c);
|
|
}
|
|
|
|
return cmp;
|
|
} else c = (cmp < 0) ? c->left : c->right;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
reverse = type&RBFOREACH_REVERSE;
|
|
|
|
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_breadth_first(&x->root, type&RBFOREACH_REVERSE);
|
|
break;
|
|
} else return libcdsb_builtin_foreach(x, data, callback);
|
|
}
|
|
|
|
while ((n = stack_pop(&iter))) {
|
|
if (!r) {
|
|
r = callback(vnode_peek(&n->value, x->type), data);
|
|
} else if (!flush) {
|
|
stack_flush(&iter);
|
|
return r;
|
|
}
|
|
|
|
if (flush) {
|
|
vnode_free(&n->value, x->type);
|
|
free(n);
|
|
}
|
|
}
|
|
|
|
if (flush) x->root = rbnode_empty;
|
|
|
|
return r;
|
|
}
|