libcdsb/src/map/extra.c

122 lines
2.9 KiB
C
Raw Normal View History

2022-06-08 09:56:14 +03:00
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2022 Gregory Lirent */
#include "include.h"
2022-06-08 10:53:18 +03:00
_Bool libcdsb_map_update(map_t* x, const void* k, vtype kt, const void* v, vtype vt) {
2022-06-08 09:56:14 +03:00
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;
}
2022-06-08 21:00:33 +03:00
int libcdsb_map_find(map_t* x, const void* k, vtype t, void* _, map_access_callback callback, _Bool cut) {
mnode_t* c;
void *key;
int cmp;
c = x->root;
while (!mnode_is_empty(c)) {
key = vnode_peek(&c->key, x->type);
cmp = vtype_compare(key, x->type, k, t);
if (cmp == 0) {
cmp = (callback) ? callback(key, x->type, vnode_peek(&c->value, c->type), c->type, _) : 0;
if (cut) {
c = mnode_delete(&x->root, c);
vnode_free(&c->key, x->type);
vnode_free(&c->value, c->type);
free(c);
}
return cmp;
}
}
return -1;
}
int libcdsb_map_foreach(map_t* x, void* dt, map_access_callback callback, _Bool flush) {
2022-06-08 09:56:14 +03:00
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;
}