Simplify dnode_t excess logic

This commit is contained in:
Gregory Lirent 2022-08-18 02:27:26 +03:00
parent 72770c3561
commit b2fa470bce
4 changed files with 215 additions and 309 deletions

View File

@ -3,142 +3,61 @@
#include "include.h" #include "include.h"
#define dtree_duplicate(s) rbtree_duplicate((rbnode_t*)s, (void*)dnode_duplicate, nullptr)
#define dtree_compare(s0, s1) rbtree_compare((void*)s0, (void*)s1, (void*)dnode_compare, nullptr)
static dnode_t* dnode_duplicate(const dnode_t* s, dnode_t* p, void* not_used) {
dnode_t* x;
x = dnode_create(vnode_duplicate(&s->key, s->key_type), p, s->colored);
x->key_type = s->key_type;
x->val_type = s->val_type;
x->value = vnode_duplicate(&s->value, s->val_type);
return x;
}
static int dnode_compare(const dnode_t *s0, const dnode_t *s1, void* not_used) {
int c = vnode_compare(&s0->key, s1->key_type, &s1->key, s1->key_type);
return (!c) ? vnode_compare(&s0->value, s1->val_type, &s1->value, s1->val_type) : c;
}
/*#####################################################################################################################*/
static int dict_compare_equal_capacity(const dict_t* s0, const dict_t* s1) {
int c;
for (size_t i = 0; i < s0->capacity; ++i) {
if ((c = dtree_compare(s0->nodes[i], s1->nodes[i]))) {
return c;
}
}
return 0;
}
static int dict_compare_unequal_capacity(const dict_t* s0, const dict_t* s1) {
const dict_t *x, *y;
dnode_t *c0, *c1;
int cmp;
stack_t z;
if (s0->capacity <= s1->capacity) {
x = s0;
y = s1;
} else {
x = s1;
y = s0;
}
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 ((c0 = stack_pop(&z))) {
c1 = y->nodes[vnode_hash(c0->key, c0->key_type) / y->capacity];
cmp = 1;
while (!dnode_is_empty(c1)) {
cmp = vnode_compare(c0->key, c0->key_type, c1->key, c1->key_type);
if (cmp == 0) break;
c1 = (cmp < 0) ? c1->left : c1->right;
}
if (cmp) return x == s0 ? cmp : ~cmp + 1;
if (!dnode_is_empty(c0->right)) stack_push(&z, c0->right);
if (!dnode_is_empty(c0->left)) stack_push(&z, c0->left);
}
return 0;
}
/*#####################################################################################################################*/ /*#####################################################################################################################*/
hash_t dict_hash(const dict_t* s) { hash_t dict_hash(const dict_t* s) {
dnode_t *l, *r; dnode_t *min, *max;
hash_t hash; size_t i;
dnode_t *c;
hash_t hash;
if (!s->size) return 0; if (!s->size)
return 0;
l = dnode_empty; min = max = nullptr;
r = dnode_empty; i = s->capacity;
for (size_t i = 0; i < s->capacity; ++i) { while (i--) {
if (!dnode_is_empty(s->nodes[i])) { c = s->nodes[i];
if (dnode_is_empty(l) || vnode_compare(s->nodes[i]->key, s->nodes[i]->key_type, l->key, l->key_type) < 0) {
l = s->nodes[i];
}
if (dnode_is_empty(r) || vnode_compare(s->nodes[i]->key, s->nodes[i]->key_type, r->key, r->key_type) > 0) { while (!is_null(c)) {
r = s->nodes[i]; if (is_null(min) || vnode_compare(&c->key, c->key_type, &min->key, min->key_type) < 0) min = c;
} if (is_null(max) || vnode_compare(&c->key, c->key_type, &max->key, max->key_type) > 0) max = c;
c = c->prev;
} }
} }
while (!dnode_is_empty(l->left)) hash = vnode_hash(&min->key, min->key_type);
l = l->left;
while (!dnode_is_empty(r->right)) if (s->size > 0)
r = r->right; hash += vnode_hash(&max->key, max->key_type);
hash = vnode_hash(l->key, l->key_type) + vnode_hash(l->value, l->val_type);
if (l != r) hash += vnode_hash(r->key, r->key_type) + vnode_hash(r->value, r->val_type);
return (hash ^ s->size) + VTYPE_DICT; return (hash ^ s->size) + VTYPE_DICT;
} }
void dict_init(dict_t* x) { void dict_init(dict_t* x) {
memset(x, 0, sizeof(*x)); memset(x, 0, sizeof(*x));
} }
/*#####################################################################################################################*/
void dict_free(dict_t* x) { void dict_free(dict_t* x) {
for (size_t i = 0; i < x->capacity; ++i)
rbtree_free(x->nodes[i], (void*)dnode_free, nullptr); while (x->capacity--) {
while (!is_null(x->nodes[x->capacity])) {
vnode_free(&x->nodes[x->capacity]->key, x->nodes[x->capacity]->key_type);
vnode_free(&x->nodes[x->capacity]->value, x->nodes[x->capacity]->value_type);
x->nodes[x->capacity] = x->nodes[x->capacity]->prev;
}
}
free(x->nodes); free(x->nodes);
memset(x, 0, sizeof(*x)); memset(x, 0, sizeof(*x));
} }
void libcdcb_dnode_free(dnode_t* x, void* not_used) {
vnode_free(&x->key, x->key_type);
vnode_free(&x->value, x->val_type);
}
/*#####################################################################################################################*/ /*#####################################################################################################################*/
size_t dict_size(const dict_t* x) { size_t dict_size(const dict_t* x) {
@ -152,6 +71,9 @@ size_t dict_capacity(const dict_t* x) {
/*#####################################################################################################################*/ /*#####################################################################################################################*/
int dict_compare(const dict_t* s0, const dict_t* s1) { int dict_compare(const dict_t* s0, const dict_t* s1) {
dnode_t *c0, *c1;
size_t i;
int cmp;
if (s0 == s1) if (s0 == s1)
return 0; return 0;
@ -159,48 +81,31 @@ int dict_compare(const dict_t* s0, const dict_t* s1) {
if (s0->size != s1->size) if (s0->size != s1->size)
return s0->size < s1->size ? -1 : 1; return s0->size < s1->size ? -1 : 1;
if (s0->capacity == s1->capacity) i = s0->capacity;
return dict_compare_equal_capacity(s0, s1);
return dict_compare_unequal_capacity(s0, s1); while (i--) {
} c0 = s0->nodes[i];
/*#####################################################################################################################*/ while (!is_null(c0)) {
dict_t dict_copy(const dict_t* s) { c1 = s1->nodes[vnode_hash(&c0->key, c0->key_type) % s1->capacity];
dict_t x; cmp = -1;
x.capacity = s->capacity; while (!is_null(c1)) {
x.size = s->size; if ((cmp = vnode_compare(&c0->key, c0->key_type, &c1->key, c1->key_type) == 0)) {
x.nodes = malloc(x.size * sizeof(*x.nodes));
for (size_t i = 0; i < x.capacity; ++i) { cmp = vnode_compare(&c0->value, c0->value_type, &c1->value, c1->value_type);
x.nodes[i] = dtree_duplicate(s->nodes[i]); break;
}
c1 = c1->prev;
}
if (cmp) return cmp;
c0 = c0->prev;
}
} }
return x; return 0;
}
dict_t* dict_duplicate(const dict_t* s) {
dict_t *x = malloc(sizeof(*x));
x->capacity = s->capacity;
x->size = s->size;
x->nodes = malloc(x->size * sizeof(*x->nodes));
for (size_t i = 0; i < x->capacity; ++i) {
x->nodes[i] = dtree_duplicate(s->nodes[i]);
}
return x;
}
void dict_copy_init(dict_t* x, const dict_t* s) {
x->capacity = s->capacity;
x->size = s->size;
x->nodes = malloc(x->size * sizeof(*x->nodes));
for (size_t i = 0; i < x->capacity; ++i) {
x->nodes[i] = dtree_duplicate(s->nodes[i]);
}
} }

82
src/dict/copy.c Normal file
View File

@ -0,0 +1,82 @@
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2022 Gregory Lirent */
#include "include.h"
/*#####################################################################################################################*/
static inline dnode_t* dnode_duplicate(const dnode_t* s, dnode_t* p) {
dnode_t* x = malloc(sizeof(*x));
x->prev = p;
x->key = vnode_duplicate(&s->key, s->key_type);
x->value = vnode_duplicate(&s->value, s->value_type);
x->key_type = s->key_type;
x->value_type = s->value_type;
return x;
}
/*#####################################################################################################################*/
dict_t dict_copy(const dict_t* s) {
dict_t x;
size_t i;
dnode_t *n;
x.capacity = i = s->capacity;
x.size = s->size;
x.nodes = calloc(x.capacity, sizeof(*x.nodes));
while (i--) {
n = s->nodes[i];
while (!is_null(n)) {
x.nodes[i] = dnode_duplicate(n, x.nodes[i]);
n = n->prev;
}
}
return x;
}
dict_t* dict_duplicate(const dict_t* s) {
dict_t *x = malloc(sizeof(*x));
size_t i;
dnode_t *n;
x->capacity = i = s->capacity;
x->size = s->size;
x->nodes = calloc(x->capacity, sizeof(*x->nodes));
while (i--) {
n = s->nodes[i];
while (!is_null(n)) {
x->nodes[i] = dnode_duplicate(n, x->nodes[i]);
n = n->prev;
}
}
return x;
}
void dict_copy_init(dict_t* x, const dict_t* s) {
size_t i;
dnode_t *n;
x->capacity = i = s->capacity;
x->size = s->size;
x->nodes = calloc(x->capacity, sizeof(*x->nodes));
while (i--) {
n = s->nodes[i];
while (!is_null(n)) {
x->nodes[i] = dnode_duplicate(n, x->nodes[i]);
n = n->prev;
}
}
}

View File

@ -6,72 +6,28 @@
/*#####################################################################################################################*/ /*#####################################################################################################################*/
static void dict_rehash(dict_t* s, size_t capacity) { static void dict_rehash(dict_t* s, size_t capacity) {
stack_t z; dnode_t **nodes, *c, *n, **p;
int cmp; size_t i;
size_t index;
dnode_t *c, *p, *n;
dnode_t **nodes = calloc(capacity, sizeof(*nodes)); i = s->capacity;
nodes = calloc(sizeof(*nodes), capacity);
z.prev = 0; while (i--) {
z.value = 0; c = s->nodes[i];
index = s->capacity;
while (index--) { while (!is_null(c)) {
if (!dnode_is_empty(s->nodes[index])) p = nodes + (vnode_hash(&c->key, c->key_type) % capacity);
stack_push(&z, s->nodes[index]); n = c->prev;
} c->prev = *p;
while ((c = stack_pop(&z))) { *p = c;
c = n;
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;
}
index = vnode_hash(&c->key, c->key_type) % capacity;
n = nodes[index];
if (!is_null(nodes[index])) {
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(nodes + index, n);
} else {
nodes[index] = c;
c->colored = 0;
c->parent = dnode_empty;
} }
} }
free(s->nodes); free(s->nodes);
s->nodes = nodes; s->nodes = nodes;
s->capacity = capacity;
if (capacity > s->capacity) {
s->capacity = capacity;
while (capacity--) {
if (is_null(*nodes))
*nodes = dnode_empty;
++nodes;
}
} else s->capacity = capacity;
} }
/*#####################################################################################################################*/ /*#####################################################################################################################*/
@ -96,86 +52,62 @@ bool libcdsb_dict_shrink_to_fit(dict_t* s) {
bool libcdsb_dict_update(dict_t* x, const void* k, vtype kt, const void* v, vtype vt) { bool libcdsb_dict_update(dict_t* x, const void* k, vtype kt, const void* v, vtype vt) {
dnode_t *c, **p;
dnode_t *n, *p;
vnode_t kn, vn;
int cmp;
size_t index;
if (!x->capacity || (double)x->size / x->capacity > REBUILD_POINT_MAX) if (!x->capacity || (double)x->size / x->capacity > REBUILD_POINT_MAX)
dict_rehash(x, x->capacity + CAPACITY_BLOCK); dict_rehash(x, x->capacity + CAPACITY_BLOCK);
index = vtype_hash(k, kt) % x->capacity; c = *(p = x->nodes + (vtype_hash(k, kt) % x->capacity));
n = x->nodes[index];
kn = vnode_create(k, kt);
vn = vnode_create(v, vt);
if (!dnode_is_empty(n)) { while (!is_null(c)) {
do { if (vtype_compare(k, kt, vnode_peek(&c->key, c->key_type), c->key_type) == 0) {
p = n; vnode_free(&c->value, c->value_type);
cmp = vtype_compare(k, kt, vnode_peek(&n->key, n->key_type), n->key_type);
if (cmp == 0) { c->value = vnode_create(v, vt);
dnode_free(n, nullptr); c->value_type = vt;
n->key = kn; return true;
n->value = vn; } else c = c->prev;
n->key_type = kt; }
n->val_type = vt;
return true; c = malloc(sizeof(*c));
}
n = (cmp < 0) ? n->left : n->right; c->prev = *p;
} while (!dnode_is_empty(n)); c->key = vnode_create(k, kt);
c->value = vnode_create(v, vt);
n = dnode_create(kn, p, 1); c->key_type = kt;
c->value_type = vt;
if (cmp < 0) p->left = n;
else p->right = n;
if (!dnode_is_root(p))
dnode_fixup(x->nodes + index, n);
} else x->nodes[index] = n = dnode_create(kn, dnode_empty, 0);
n->value = vn;
n->key_type = kt;
n->val_type = vt;
*p = c;
++x->size; ++x->size;
return false; return false;
} }
int libcdsb_dict_find(dict_t* x, const void* k, vtype t, void* _, dict_access_callback callback, bool cut) { int libcdsb_dict_find(dict_t* x, const void* k, vtype t, void* dt, dict_access_callback callback, bool cut) {
dnode_t *c, **p;
dnode_t *c; int r;
void* key; void* key;
int cmp;
size_t index;
if (x->capacity) { if (x->capacity) {
index = vtype_hash(k, t) % x->capacity; c = *(p = x->nodes + (vtype_hash(k, t) % x->capacity));
c = x->nodes[index];
while (!dnode_is_empty(c)) { while (!is_null(c)) {
key = vnode_peek(&c->key, c->key_type); key = vnode_peek(&c->key, c->key_type);
cmp = vtype_compare(k, t, 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 (cmp == 0) {
cmp = (callback) ? callback(key, c->key_type, vnode_peek(&c->value, c->val_type), c->val_type, _) : 0;
if (cut) { if (cut) {
c = dnode_delete(x->nodes + index, c); *p = c->prev;
dnode_free(c, nullptr); vnode_free(&c->key, c->key_type);
vnode_free(&c->value, c->value_type);
free(c); free(c);
--x->size; --x->size;
} }
return cmp; return r;
} else c = (cmp < 0) ? c->left : c->right; } else c = *(p = &c->prev);
} }
} }
@ -184,49 +116,54 @@ int libcdsb_dict_find(dict_t* x, const void* k, vtype t, void* _, dict_access_ca
int libcdsb_dict_foreach(dict_t* x, void* dt, dict_access_callback callback, bool flush) { int libcdsb_dict_foreach(dict_t* x, void* dt, dict_access_callback callback, bool flush) {
stack_t z; dnode_t *c;
int r; ssize_t i;
dnode_t* c; int r;
r = 0; r = 0;
z.prev = 0; i = x->capacity;
z.value = 0;
for (size_t i = 0; i < x->capacity; ++i) { while (i) {
if (!dnode_is_empty(x->nodes[i])) c = x->nodes[--i];
stack_push(&z, x->nodes[i]);
}
while ((c = stack_pop(&z))) { while (!is_null(c)) {
void* k = vnode_peek(&c->key, c->key_type); r = callback(vnode_peek(&c->key, c->key_type), c->key_type,
void* v = vnode_peek(&c->value, c->val_type); vnode_peek(&c->value, c->value_type), c->value_type, dt);
if ((r = callback(k, c->key_type, v, c->val_type, dt))) c = c->prev;
break;
if (!dnode_is_empty(c->right)) stack_push(&z, c->right); if (r) {
if (!dnode_is_empty(c->left)) stack_push(&z, c->left); 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]);
if (flush) { x->nodes[i] = c;
dnode_free(c, nullptr); }
free(c);
} }
} }
if (flush) { if (flush) {
while (c) { while (i) {
if (!dnode_is_empty(c->right)) stack_push(&z, c->right); --i;
if (!dnode_is_empty(c->left)) stack_push(&z, c->left);
dnode_free(c, nullptr); while (!is_null(x->nodes[i])) { flush_loop_:
free(c); vnode_free(&x->nodes[i]->key, x->nodes[i]->key_type);
vnode_free(&x->nodes[i]->value, x->nodes[i]->value_type);
c = stack_pop(&z); c = x->nodes[i]->prev;
free(x->nodes[i]);
x->nodes[i] = c;
}
} }
free(x->nodes); free(x->nodes);
memset(x, 0, sizeof(*x)); memset(x, 0, sizeof(*x));
} else stack_flush(&z); }
end_:
return r; return r;
} }

View File

@ -15,34 +15,16 @@
#endif #endif
#define REBUILD_POINT_MAX 0.65 #define REBUILD_POINT_MAX 0.65
typedef struct libcdsb_dict_node { typedef struct libcdsb_dict_node {
struct libcdsb_dict_node* left; struct libcdsb_dict_node* prev;
struct libcdsb_dict_node* right;
struct libcdsb_dict_node* parent;
vnode_t key; vnode_t key;
short colored;
u8_t key_type;
u8_t val_type;
vnode_t value; vnode_t value;
u16_t key_type;
u16_t value_type;
} dnode_t; } dnode_t;
static_assert(offsetof(struct libcdsb_rbtree_node, left) == offsetof(struct libcdsb_dict_node, left), "Implementation assert");
static_assert(offsetof(struct libcdsb_rbtree_node, right) == offsetof(struct libcdsb_dict_node, right), "Implementation assert");
static_assert(offsetof(struct libcdsb_rbtree_node, parent) == offsetof(struct libcdsb_dict_node, parent), "Implementation assert");
static_assert(offsetof(struct libcdsb_rbtree_node, colored) == offsetof(struct libcdsb_dict_node, colored), "Implementation assert");
static_assert(offsetof(struct libcdsb_rbtree_node, value) == offsetof(struct libcdsb_dict_node, key), "Implementation assert");
#define dnode_empty ((dnode_t*)LIBCDSB_RBTREE_NODE_EMPTY) #endif /* LIBCDSB_SRC_DICT_INCLUDE_H */
#define dnode_create(k, p, c) ((dnode_t*)libcdsb_rbtree_node_create(k, (rbnode_t*)p, c, sizeof(dnode_t)))
#define dnode_fixup(r, n) libcdsb_rbtree_node_fixup((rbnode_t**)(r), (rbnode_t*)(n))
#define dnode_delete(r, n) (dnode_t*)libcdsb_rbtree_node_delete((rbnode_t**)(r), (rbnode_t*)(n))
#define dnode_is_empty(n) ((n) == dnode_empty)
#define dnode_is_root(n) dnode_is_empty((n)->parent)
extern void libcdcb_dnode_free(dnode_t* x, void* not_used);
#define dnode_free libcdcb_dnode_free
#endif /* LIBCDSB_SRC_MAP_INCLUDE_H */