122 lines
3.0 KiB
C
122 lines
3.0 KiB
C
|
/* This software is licensed by the MIT License, see LICENSE file */
|
||
|
/* Copyright © 2022 Gregory Lirent */
|
||
|
|
||
|
#include "include.h"
|
||
|
|
||
|
|
||
|
_Bool libcdsb_map_find(val_t* x, map_t* s, const void* k, vtype t, _Bool cut) {
|
||
|
mnode_t* c;
|
||
|
int cmp;
|
||
|
|
||
|
c = s->root;
|
||
|
|
||
|
while (!mnode_is_empty(c)) {
|
||
|
|
||
|
cmp = vtype_compare(vnode_peek(&c->value, s->type), s->type, k, t);
|
||
|
|
||
|
if (cmp == 0) {
|
||
|
if (cut) {
|
||
|
c = mnode_delete(&s->root, c);
|
||
|
if (!is_null(x)) {
|
||
|
value_set(x, c->value, c->type, VF_WRITEABLE|VF_REMOVABLE);
|
||
|
} else vnode_free(&c->value, c->type);
|
||
|
vnode_free(&c->key, s->type);
|
||
|
free(c);
|
||
|
} else if (!is_null(x)) value_set(x, &c->value, c->type, VF_WRITEABLE|VF_CHANGEABLE);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
c = (cmp < 0) ? c->right : c->left;
|
||
|
}
|
||
|
return rbnode_empty;
|
||
|
}
|
||
|
|
||
|
|
||
|
_Bool libcdsb_vset_update(map_t* x, const void* k, vtype kt, const void* v, vtype vt) {
|
||
|
int cmp;
|
||
|
mnode_t* n;
|
||
|
mnode_t* p;
|
||
|
vnode_t kn;
|
||
|
|
||
|
n = x->root;
|
||
|
kn = vnode_tcreate(x->type, k, kt);
|
||
|
kt = x->type;
|
||
|
k = vnode_peek(&kn, kt);
|
||
|
|
||
|
if (!mnode_is_empty(n)) {
|
||
|
do {
|
||
|
p = n;
|
||
|
cmp = vtype_compare(k, kt, vnode_peek(&n->key, kt), kt);
|
||
|
|
||
|
if (cmp == 0) {
|
||
|
vnode_free(&n->key, kt);
|
||
|
vnode_free(&n->value, n->type);
|
||
|
|
||
|
n->key = kn;
|
||
|
n->value = vnode_create(v, vt);
|
||
|
n->type = vt;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
n = (cmp < 0) ? n->left : n->right;
|
||
|
} while (!mnode_is_empty(n));
|
||
|
|
||
|
n = mnode_create(kn, p, 1);
|
||
|
|
||
|
if (cmp < 0) p->left = n;
|
||
|
else p->right = n;
|
||
|
|
||
|
if (!mnode_is_root(p))
|
||
|
mnode_fixup(&x->root, n);
|
||
|
|
||
|
} else n = x->root = mnode_create(kn, mnode_empty, 0);
|
||
|
|
||
|
n->value = vnode_create(v, vt);
|
||
|
n->type = vt;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
int libcdsb_map_foreach(map_t* x, void* dt, map_foreach_callback callback, _Bool flush) {
|
||
|
stack_t z = { .prev = 0, .value = x->root };
|
||
|
int r = 0;
|
||
|
mnode_t* c;
|
||
|
|
||
|
if (mnode_is_empty(x->root)) return 0;
|
||
|
|
||
|
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);
|
||
|
|
||
|
if (flush) {
|
||
|
vnode_free(&c->key, x->type);
|
||
|
vnode_free(&c->value, c->type);
|
||
|
free(c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
|
||
|
return r;
|
||
|
}
|