170 lines
4.2 KiB
C
170 lines
4.2 KiB
C
/* 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) {
|
|
dnode_t **nodes, *c, *n, **p;
|
|
size_t i;
|
|
|
|
i = s->capacity;
|
|
nodes = calloc(sizeof(*nodes), capacity);
|
|
|
|
while (i--) {
|
|
c = s->nodes[i];
|
|
|
|
while (!is_null(c)) {
|
|
p = nodes + (vnode_hash(&c->key, c->key_type) % capacity);
|
|
n = c->prev;
|
|
c->prev = *p;
|
|
|
|
*p = c;
|
|
c = n;
|
|
}
|
|
}
|
|
|
|
free(s->nodes);
|
|
s->nodes = nodes;
|
|
s->capacity = capacity;
|
|
}
|
|
|
|
/*#####################################################################################################################*/
|
|
|
|
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 *c, **p;
|
|
|
|
if (!x->capacity || (double)x->size / x->capacity > REBUILD_POINT_MAX)
|
|
dict_rehash(x, x->capacity + CAPACITY_BLOCK);
|
|
|
|
c = *(p = x->nodes + (vtype_hash(k, kt) % x->capacity));
|
|
|
|
while (!is_null(c)) {
|
|
if (vtype_compare(k, kt, vnode_peek(&c->key, c->key_type), c->key_type) == 0) {
|
|
vnode_free(&c->value, c->value_type);
|
|
|
|
c->value = vnode_create(v, vt);
|
|
c->value_type = vt;
|
|
|
|
return true;
|
|
} else c = c->prev;
|
|
}
|
|
|
|
c = malloc(sizeof(*c));
|
|
|
|
c->prev = *p;
|
|
c->key = vnode_create(k, kt);
|
|
c->value = vnode_create(v, vt);
|
|
c->key_type = kt;
|
|
c->value_type = vt;
|
|
|
|
*p = c;
|
|
++x->size;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
int libcdsb_dict_find(dict_t* x, const void* k, vtype t, void* dt, dict_access_callback callback, bool cut) {
|
|
dnode_t *c, **p;
|
|
int r;
|
|
void* key;
|
|
|
|
if (x->capacity) {
|
|
c = *(p = x->nodes + (vtype_hash(k, t) % x->capacity));
|
|
|
|
while (!is_null(c)) {
|
|
key = vnode_peek(&c->key, c->key_type);
|
|
if (vtype_compare(k, t, key, c->key_type) == 0) {
|
|
r = (callback) ? callback(key, c->key_type, vnode_peek(&c->value, c->value_type), c->value_type, dt) : 0;
|
|
|
|
if (cut) {
|
|
*p = c->prev;
|
|
vnode_free(&c->key, c->key_type);
|
|
vnode_free(&c->value, c->value_type);
|
|
free(c);
|
|
--x->size;
|
|
}
|
|
|
|
return r;
|
|
} else c = *(p = &c->prev);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
int libcdsb_dict_foreach(dict_t* x, void* dt, dict_access_callback callback, bool flush) {
|
|
dnode_t *c;
|
|
ssize_t i;
|
|
int r;
|
|
|
|
r = 0;
|
|
i = x->capacity;
|
|
|
|
while (i) {
|
|
c = x->nodes[--i];
|
|
|
|
while (!is_null(c)) {
|
|
r = callback(vnode_peek(&c->key, c->key_type), c->key_type,
|
|
vnode_peek(&c->value, c->value_type), c->value_type, dt);
|
|
|
|
c = c->prev;
|
|
|
|
if (r) {
|
|
if (!flush) goto end_;
|
|
else goto flush_loop_;
|
|
} else if (flush) {
|
|
vnode_free(&x->nodes[i]->key, x->nodes[i]->key_type);
|
|
vnode_free(&x->nodes[i]->value, x->nodes[i]->value_type);
|
|
free(x->nodes[i]);
|
|
|
|
x->nodes[i] = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flush) {
|
|
while (i) {
|
|
--i;
|
|
|
|
while (!is_null(x->nodes[i])) { flush_loop_:
|
|
vnode_free(&x->nodes[i]->key, x->nodes[i]->key_type);
|
|
vnode_free(&x->nodes[i]->value, x->nodes[i]->value_type);
|
|
|
|
c = x->nodes[i]->prev;
|
|
free(x->nodes[i]);
|
|
|
|
x->nodes[i] = c;
|
|
}
|
|
}
|
|
|
|
free(x->nodes);
|
|
memset(x, 0, sizeof(*x));
|
|
}
|
|
|
|
end_:
|
|
return r;
|
|
}
|