From b2fa470bce98f4aa7106029cc623c63e35e0e195 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Thu, 18 Aug 2022 02:27:26 +0300 Subject: [PATCH] Simplify dnode_t excess logic --- src/dict/base.c | 199 +++++++++++------------------------------- src/dict/copy.c | 82 +++++++++++++++++ src/dict/extra.c | 213 ++++++++++++++++----------------------------- src/dict/include.h | 30 ++----- 4 files changed, 215 insertions(+), 309 deletions(-) create mode 100644 src/dict/copy.c diff --git a/src/dict/base.c b/src/dict/base.c index 35ec012..76f7632 100644 --- a/src/dict/base.c +++ b/src/dict/base.c @@ -3,142 +3,61 @@ #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) { - dnode_t *l, *r; - hash_t hash; + dnode_t *min, *max; + size_t i; + dnode_t *c; + hash_t hash; - if (!s->size) return 0; + if (!s->size) + return 0; - l = dnode_empty; - r = dnode_empty; + min = max = nullptr; + i = s->capacity; - for (size_t i = 0; i < s->capacity; ++i) { - if (!dnode_is_empty(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]; - } + while (i--) { + c = 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) { - r = s->nodes[i]; - } + while (!is_null(c)) { + 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)) - l = l->left; + hash = vnode_hash(&min->key, min->key_type); - while (!dnode_is_empty(r->right)) - r = r->right; - - 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); + if (s->size > 0) + hash += vnode_hash(&max->key, max->key_type); return (hash ^ s->size) + VTYPE_DICT; } + void dict_init(dict_t* x) { memset(x, 0, sizeof(*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); 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) { @@ -152,6 +71,9 @@ size_t dict_capacity(const dict_t* x) { /*#####################################################################################################################*/ int dict_compare(const dict_t* s0, const dict_t* s1) { + dnode_t *c0, *c1; + size_t i; + int cmp; if (s0 == s1) return 0; @@ -159,48 +81,31 @@ int dict_compare(const dict_t* s0, const dict_t* s1) { if (s0->size != s1->size) return s0->size < s1->size ? -1 : 1; - if (s0->capacity == s1->capacity) - return dict_compare_equal_capacity(s0, s1); + i = s0->capacity; - 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) { - dict_t x; + c1 = s1->nodes[vnode_hash(&c0->key, c0->key_type) % s1->capacity]; + cmp = -1; - x.capacity = s->capacity; - x.size = s->size; - x.nodes = malloc(x.size * sizeof(*x.nodes)); + while (!is_null(c1)) { + if ((cmp = vnode_compare(&c0->key, c0->key_type, &c1->key, c1->key_type) == 0)) { - for (size_t i = 0; i < x.capacity; ++i) { - x.nodes[i] = dtree_duplicate(s->nodes[i]); + cmp = vnode_compare(&c0->value, c0->value_type, &c1->value, c1->value_type); + break; + } + + c1 = c1->prev; + } + + if (cmp) return cmp; + + c0 = c0->prev; + } } - return x; -} - -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]); - } + return 0; } diff --git a/src/dict/copy.c b/src/dict/copy.c new file mode 100644 index 0000000..35931a7 --- /dev/null +++ b/src/dict/copy.c @@ -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; + } + } +} diff --git a/src/dict/extra.c b/src/dict/extra.c index 49b914a..81d645c 100644 --- a/src/dict/extra.c +++ b/src/dict/extra.c @@ -6,72 +6,28 @@ /*#####################################################################################################################*/ static void dict_rehash(dict_t* s, size_t capacity) { - stack_t z; - int cmp; - size_t index; - dnode_t *c, *p, *n; + dnode_t **nodes, *c, *n, **p; + size_t i; - dnode_t **nodes = calloc(capacity, sizeof(*nodes)); + i = s->capacity; + nodes = calloc(sizeof(*nodes), capacity); - z.prev = 0; - z.value = 0; - index = s->capacity; + while (i--) { + c = s->nodes[i]; - while (index--) { - if (!dnode_is_empty(s->nodes[index])) - stack_push(&z, s->nodes[index]); - } + while (!is_null(c)) { + p = nodes + (vnode_hash(&c->key, c->key_type) % capacity); + n = c->prev; + c->prev = *p; - 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; - } - - 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; + *p = c; + c = n; } } free(s->nodes); - s->nodes = nodes; - - if (capacity > s->capacity) { - s->capacity = capacity; - while (capacity--) { - if (is_null(*nodes)) - *nodes = dnode_empty; - ++nodes; - } - } else s->capacity = capacity; + 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) { - - dnode_t *n, *p; - vnode_t kn, vn; - int cmp; - size_t index; + dnode_t *c, **p; if (!x->capacity || (double)x->size / x->capacity > REBUILD_POINT_MAX) dict_rehash(x, x->capacity + CAPACITY_BLOCK); - index = vtype_hash(k, kt) % x->capacity; - n = x->nodes[index]; - kn = vnode_create(k, kt); - vn = vnode_create(v, vt); + c = *(p = x->nodes + (vtype_hash(k, kt) % x->capacity)); - if (!dnode_is_empty(n)) { - do { - p = n; - cmp = vtype_compare(k, kt, vnode_peek(&n->key, n->key_type), n->key_type); + 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); - if (cmp == 0) { - dnode_free(n, nullptr); + c->value = vnode_create(v, vt); + c->value_type = vt; - n->key = kn; - n->value = vn; - n->key_type = kt; - n->val_type = vt; + return true; + } else c = c->prev; + } - return true; - } + c = malloc(sizeof(*c)); - 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(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; + 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* _, dict_access_callback callback, bool cut) { - - dnode_t *c; - void* key; - int cmp; - size_t index; +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) { - index = vtype_hash(k, t) % x->capacity; - c = x->nodes[index]; + c = *(p = x->nodes + (vtype_hash(k, t) % x->capacity)); - while (!dnode_is_empty(c)) { + while (!is_null(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, c->key_type, vnode_peek(&c->value, c->val_type), c->val_type, _) : 0; + 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) { - c = dnode_delete(x->nodes + index, c); - dnode_free(c, nullptr); + *p = c->prev; + vnode_free(&c->key, c->key_type); + vnode_free(&c->value, c->value_type); free(c); --x->size; } - return cmp; - } else c = (cmp < 0) ? c->left : c->right; + return r; + } 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) { - stack_t z; - int r; - dnode_t* c; + dnode_t *c; + ssize_t i; + int r; - r = 0; - z.prev = 0; - z.value = 0; + r = 0; + i = x->capacity; - for (size_t i = 0; i < x->capacity; ++i) { - if (!dnode_is_empty(x->nodes[i])) - stack_push(&z, x->nodes[i]); - } + while (i) { + c = x->nodes[--i]; - while ((c = stack_pop(&z))) { - void* k = vnode_peek(&c->key, c->key_type); - void* v = vnode_peek(&c->value, c->val_type); + 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); - if ((r = callback(k, c->key_type, v, c->val_type, dt))) - break; + c = c->prev; - if (!dnode_is_empty(c->right)) stack_push(&z, c->right); - if (!dnode_is_empty(c->left)) stack_push(&z, c->left); + 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]); - if (flush) { - dnode_free(c, nullptr); - free(c); + x->nodes[i] = 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); + while (i) { + --i; - dnode_free(c, nullptr); - free(c); + 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 = stack_pop(&z); + c = x->nodes[i]->prev; + free(x->nodes[i]); + + x->nodes[i] = c; + } } free(x->nodes); memset(x, 0, sizeof(*x)); - } else stack_flush(&z); + } + end_: return r; } diff --git a/src/dict/include.h b/src/dict/include.h index 9926a72..dc726d1 100644 --- a/src/dict/include.h +++ b/src/dict/include.h @@ -15,34 +15,16 @@ #endif #define REBUILD_POINT_MAX 0.65 + typedef struct libcdsb_dict_node { - struct libcdsb_dict_node* left; - struct libcdsb_dict_node* right; - struct libcdsb_dict_node* parent; + struct libcdsb_dict_node* prev; vnode_t key; - short colored; - u8_t key_type; - u8_t val_type; vnode_t value; + + u16_t key_type; + u16_t value_type; } 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) -#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 */ +#endif /* LIBCDSB_SRC_DICT_INCLUDE_H */