libcdsb/src/dict/extra.c

210 lines
5.1 KiB
C
Raw Normal View History

2022-08-14 21:06:38 +03:00
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2022 Gregory Lirent */
#include "include.h"
/*#####################################################################################################################*/
static void dict_rehash(dict_t* s, size_t capacity) {
stack_t z;
int cmp;
dnode_t *c, *p, *n, **r;
dnode_t **nodes = malloc(capacity * sizeof(*nodes));
while (s->capacity--) {
if (!dnode_is_empty(s->nodes[s->capacity]))
stack_push(&z, s->nodes[s->capacity]);
}
while ((c = stack_pop(&z))) {
if (!dnode_is_empty(c->right)) {
stack_push(&z, c->right);
c->right = dnode_empty;
}
if (!dnode_is_empty(c->left)) {
stack_push(&z, c->left);
c->left = dnode_empty;
}
n = *(r = &nodes[vnode_hash(c->key, c->key_type) / capacity]);
if (!dnode_is_empty(*r)) {
do {
p = n;
cmp = vnode_compare(&c->key, c->key_type, &n->key, n->key_type);
n = (cmp <= 0) ? n->left : n->right;
} while (!dnode_is_empty(n));
if (cmp < 0) p->left = c;
else p->right = c;
c->parent = p;
c->colored = 1;
if (!dnode_is_root(p))
dnode_fixup(r, n);
} else {
*r = c;
c->colored = 0;
c->parent = dnode_empty;
}
}
free(s->nodes);
s->capacity = capacity;
s->nodes = nodes;
}
/*#####################################################################################################################*/
bool libcdsb_dict_shrink_to_fit(dict_t* s) {
size_t capacity;
capacity = (s->size / CAPACITY_BLOCK) + 1;
capacity *= CAPACITY_BLOCK;
while (((double)s->size / capacity) > 0.65)
capacity += CAPACITY_BLOCK;
if (capacity >= s->capacity)
return false;
dict_rehash(s, capacity);
return true;
}
bool libcdsb_dict_update(dict_t* x, const void* k, vtype kt, const void* v, vtype vt) {
dnode_t **r, *n, *p;
vnode_t kn, vn;
int cmp;
if (!x->capacity || (double)x->size / x->capacity > REBUILD_POINT_MAX) {
dict_rehash(x, x->capacity + CAPACITY_BLOCK);
}
n = *(r = &x->nodes[vnode_hash(k, kt) / x->capacity]);
kn = vnode_create(k, kt);
vn = vnode_create(v, vt);
if (!dnode_is_empty(n)) {
do {
p = n;
cmp = vtype_compare(k, kt, vnode_peek(&n->key, n->key_type), n->key_type);
if (cmp == 0) {
dnode_free(n, nullptr);
n->key = kn;
n->value = vn;
n->key_type = kt;
n->val_type = vt;
return true;
}
n = (cmp < 0) ? n->left : n->right;
} while (!dnode_is_empty(n));
n = dnode_create(kn, p, 1);
if (cmp < 0) p->left = n;
else p->right = n;
if (!dnode_is_root(p))
dnode_fixup(r, n);
} else n = *r = dnode_create(kn, dnode_empty, 0);
n->value = vn;
n->key_type = kt;
n->val_type = vt;
return false;
}
int libcdsb_dict_get(dict_t* x, const void* k, vtype t, void* _, dict_access_callback callback, bool cut) {
dnode_t *c, **r;
void* key;
int cmp;
if (x->capacity) {
c = *(r = &x->nodes[vnode_hash(k, t) / x->capacity]);
while (!dnode_is_empty(c)) {
key = vnode_peek(&c->key, c->key_type);
cmp = vtype_compare(k, t, key, c->key_type);
if (cmp == 0) {
cmp = (callback) ? callback(key, t, vnode_peek(&c->value, c->val_type), c->val_type, _) : 0;
if (cut) {
c = dnode_delete(r, c);
dnode_free(c, nullptr);
free(c);
}
return cmp;
} else c = (cmp < 0) ? c->left : c->right;
}
}
return -1;
}
int libcdsb_dict_foreach(dict_t* x, void* dt, dict_access_callback callback, bool flush) {
stack_t z;
int r;
dnode_t* c;
r = 0;
z.prev = 0;
z.value = 0;
for (size_t i = 0; i < x->capacity; ++i) {
if (!dnode_is_empty(x->nodes[i]))
stack_push(&z, x->nodes[i]);
}
while ((c = stack_pop(&z))) {
if ((r = callback(vnode_peek(&c->key, c->key_type), c->key_type, vnode_peek(&c->value, c->val_type), c->val_type, dt)))
break;
if (!dnode_is_empty(c->right)) stack_push(&z, c->right);
if (!dnode_is_empty(c->left)) stack_push(&z, c->left);
if (flush) {
dnode_free(c, nullptr);
free(c);
}
}
if (flush) {
while (c) {
if (!dnode_is_empty(c->right)) stack_push(&z, c->right);
if (!dnode_is_empty(c->left)) stack_push(&z, c->left);
dnode_free(c, nullptr);
free(c);
c = stack_pop(&z);
}
free(x->nodes);
memset(x, 0, sizeof(*x));
} else stack_flush(&z);
return r;
}