207 lines
5.3 KiB
C
207 lines
5.3 KiB
C
|
/* This software is licensed by the MIT License, see LICENSE file */
|
||
|
/* Copyright © 2022 Gregory Lirent */
|
||
|
|
||
|
#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;
|
||
|
|
||
|
if (!s->size) return 0;
|
||
|
|
||
|
l = dnode_empty;
|
||
|
r = dnode_empty;
|
||
|
|
||
|
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];
|
||
|
}
|
||
|
|
||
|
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 (!dnode_is_empty(l->left))
|
||
|
l = l->left;
|
||
|
|
||
|
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);
|
||
|
|
||
|
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);
|
||
|
|
||
|
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) {
|
||
|
return x->size;
|
||
|
}
|
||
|
|
||
|
size_t dict_capacity(const dict_t* x) {
|
||
|
return x->capacity;
|
||
|
}
|
||
|
|
||
|
/*#####################################################################################################################*/
|
||
|
|
||
|
int dict_compare(const dict_t* s0, const dict_t* s1) {
|
||
|
|
||
|
if (s0 == s1)
|
||
|
return 0;
|
||
|
|
||
|
if (s0->size != s1->size)
|
||
|
return s0->size < s1->size ? -1 : 1;
|
||
|
|
||
|
if (s0->capacity == s1->capacity)
|
||
|
return dict_compare_equal_capacity(s0, s1);
|
||
|
|
||
|
return dict_compare_unequal_capacity(s0, s1);
|
||
|
}
|
||
|
|
||
|
/*#####################################################################################################################*/
|
||
|
|
||
|
dict_t dict_copy(const dict_t* s) {
|
||
|
dict_t 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;
|
||
|
}
|
||
|
|
||
|
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]);
|
||
|
}
|
||
|
}
|