Rollback excess abstractions for rbtree's types
This commit is contained in:
parent
3cbf7a6fdf
commit
72770c3561
@ -29,17 +29,4 @@ extern rbnode_t* libcdsb_rbtree_node_delete(rbnode_t** root, rbnode_t* node)
|
||||
#define rbnode_is_empty(n) ((n) == rbnode_empty)
|
||||
#define rbnode_is_root(n) rbnode_is_empty((n)->parent)
|
||||
|
||||
extern void* libcdsb_rbtree_duplicate(const rbnode_t* s, void* (*node_duplicate)(void* src, void* parent, void* info), void* info) wur__ Nonnull__(1);
|
||||
extern int libcdsb_rbtree_compare (const rbnode_t* s0, const rbnode_t* s1, int (*node_compare)(const rbnode_t* s0, const rbnode_t* s1, void* info), void* info) pure__ wur__ Nonnull__(1,2);
|
||||
|
||||
extern hash_t libcdsb_rbtree_hash(const void* s, hash_t (*node_hash)(const void* s, void* info), void* info) pure__ wur__ Nonnull__(1);
|
||||
extern size_t libcdsb_rbtree_size(const void* s) pure__ wur__ Nonnull__(1);
|
||||
extern void libcdsb_rbtree_free(void* x, void (*node_free)(void* x, void* info), void* info) Nonnull__(1);
|
||||
|
||||
#define rbtree_duplicate libcdsb_rbtree_duplicate
|
||||
#define rbtree_compare libcdsb_rbtree_compare
|
||||
#define rbtree_hash libcdsb_rbtree_hash
|
||||
#define rbtree_size libcdsb_rbtree_size
|
||||
#define rbtree_free libcdsb_rbtree_free
|
||||
|
||||
#endif /* LIBCDSB_SRC_INTERNAL_RBTREE_H */
|
||||
|
177
src/map/base.c
177
src/map/base.c
@ -3,89 +3,158 @@
|
||||
|
||||
#include "include.h"
|
||||
|
||||
#define mtree_duplicate(s, t) rbtree_duplicate((rbnode_t*)s, (void*)mnode_duplicate, t)
|
||||
#define mtree_compare(s0, s1, t) rbtree_compare((void*)s0, (void*)s1, (void*)mnode_compare, (void*)t)
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
static mnode_t* mnode_duplicate(const mnode_t* s, mnode_t* p, const vtype* t) {
|
||||
mnode_t* x;
|
||||
|
||||
x = mnode_create(vnode_duplicate(&s->key, *t), p, s->colored);
|
||||
x->type = s->type;
|
||||
x->value = vnode_duplicate(&s->value, s->type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static int mnode_compare(const mnode_t* s0, const mnode_t* s1, vtype* t) {
|
||||
int c = vnode_compare_eq(&s0->key, &s1->key, *t);
|
||||
static inline int mnode_compare(const mnode_t* s0, const mnode_t* s1, vtype t) {
|
||||
int c = vnode_compare_eq(&s0->key, &s1->key, t);
|
||||
|
||||
return !c ? vnode_compare(&s0->value, s0->type, &s1->value, s1->type) : c;
|
||||
}
|
||||
|
||||
static hash_t mnode_hash(const mnode_t* s, vtype* tp) {
|
||||
vtype t = (!is_null(tp)) ? *tp : VTYPE_POINTER;
|
||||
return vnode_hash(s->key, t) + vnode_hash(s->value, s->type) + t;
|
||||
}
|
||||
|
||||
void libcdsb_mnode_free(mnode_t* x, vtype* t) {
|
||||
vnode_free(&x->key, *t);
|
||||
vnode_free(&x->value, x->type);
|
||||
static inline hash_t mnode_hash(const mnode_t* s, vtype t) {
|
||||
return vnode_hash(&s->key, t) + vnode_hash(&s->value, s->type) + t;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
hash_t map_hash(const map_t* s) {
|
||||
return rbtree_hash(s->root, (void*)mnode_hash, (void*)&s->type) + VTYPE_MAP;
|
||||
|
||||
mnode_t *c0, *c1;
|
||||
hash_t hash, v;
|
||||
stack_t z;
|
||||
|
||||
if (mnode_is_empty(s->root)) return 0;
|
||||
|
||||
z.prev = 0;
|
||||
hash = 1;
|
||||
c1 = s->root;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->left)) {
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
|
||||
if (!mnode_is_empty(c0->right)) stack_push(&z, c1 = c0->right);
|
||||
if (!mnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left);
|
||||
} while (!is_null(z.value));
|
||||
}
|
||||
|
||||
v = mnode_hash(c1, s->type);
|
||||
c1 = s->root;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->right)) {
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
|
||||
if (!mnode_is_empty(c0->right)) stack_push(&z, c1 = c0->right);
|
||||
if (!mnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left);
|
||||
} while (!is_null(z.value));
|
||||
}
|
||||
|
||||
v += mnode_hash(c1, s->type);
|
||||
|
||||
return (hash ^ v) + VTYPE_MAP;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
void map_init(map_t* x, vtype t) {
|
||||
x->root = mnode_empty;
|
||||
x->type = t;
|
||||
}
|
||||
|
||||
void map_free(map_t* x) {
|
||||
rbtree_free(x->root, (void*)mnode_free, &x->type);
|
||||
mnode_t *t, *c;
|
||||
|
||||
c = x->root;
|
||||
|
||||
while (!mnode_is_empty(x->root)) {
|
||||
if (!mnode_is_empty(c->left)) {
|
||||
c = c->left;
|
||||
} else if (!mnode_is_empty(c->right)) {
|
||||
c = c->right;
|
||||
} else if (!mnode_is_root(c)) {
|
||||
vnode_free(&c->key, x->type);
|
||||
vnode_free(&c->value, c->type);
|
||||
|
||||
t = c;
|
||||
c = c->parent;
|
||||
|
||||
if (t == c->left) c->left = mnode_empty;
|
||||
else c->right = mnode_empty;
|
||||
|
||||
free(t);
|
||||
} else {
|
||||
vnode_free(&c->key, x->type);
|
||||
vnode_free(&c->value, c->type);
|
||||
x->root = mnode_empty;
|
||||
}
|
||||
}
|
||||
|
||||
x->root = mnode_empty;
|
||||
x->type = 0;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
size_t map_size(const map_t* x) {
|
||||
return rbtree_size(x->root);
|
||||
stack_t z = { .prev = 0, .value = x->root };
|
||||
size_t n = 0;
|
||||
rbnode_t* c;
|
||||
|
||||
if (!mnode_is_empty(x->root)) {
|
||||
while ((c = stack_pop(&z))) {
|
||||
++n;
|
||||
if (!rbnode_is_empty(c->right)) stack_push(&z, c->right);
|
||||
if (!rbnode_is_empty(c->left)) stack_push(&z, c->left);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
int map_compare(const map_t* s0, const map_t* s1) {
|
||||
if (s0 == s1) return 0;
|
||||
if (s0->type != s1->type) return s0->type - s1->type;
|
||||
mnode_t *c0, *c1;
|
||||
stack_t z;
|
||||
int c = 0;
|
||||
|
||||
return mtree_compare(s0->root, s1->root, &s0->type);
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
map_t map_copy(const map_t* s) {
|
||||
map_t x;
|
||||
|
||||
x.type = s->type;
|
||||
x.root = mtree_duplicate(s->root, &x.type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
map_t* map_duplicate(const map_t* s) {
|
||||
map_t *x = malloc(sizeof(*x));
|
||||
|
||||
x->type = s->type;
|
||||
x->root = mtree_duplicate(s->root, &x->type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void map_copy_init(map_t* x, const map_t* s) {
|
||||
x->type = s->type;
|
||||
x->root = mtree_duplicate(s->root, &x->type);
|
||||
if (s0 == s1 || s0->root == s1->root)
|
||||
return 0;
|
||||
if (s0->type != s1->type)
|
||||
return s0->type - s1->type;
|
||||
|
||||
z.prev = 0;
|
||||
z.value = 0;
|
||||
|
||||
stack_push_many(&z, 2, (void*)s1, (void*)s0);
|
||||
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
c1 = stack_pop(&z);
|
||||
|
||||
if (mnode_is_empty(c0) || mnode_is_empty(c1)) {
|
||||
if (c0 != c1) {
|
||||
stack_flush(&z);
|
||||
return mnode_is_empty(c0) ? -1 : 1;
|
||||
}
|
||||
} else if ((c = mnode_compare(c0, c1, s0->type))) {
|
||||
if (c0->left == c1->right) { // == mnode_empty
|
||||
c = mnode_compare(c0->right, c1, s0->type);
|
||||
if (!c) c = mnode_compare(c0, c1->left, s0->type);
|
||||
} else if (c0->right == c1->left) { // == mnode_empty
|
||||
c = mnode_compare(c0, c1->right, s0->type);
|
||||
if (!c) c = mnode_compare(c0->left, c1, s0->type);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
stack_flush(&z);
|
||||
return c;
|
||||
}
|
||||
} else stack_push_many(&z, 4, c1->right, c0->right, c1->left, c0->left);
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
113
src/map/copy.c
Normal file
113
src/map/copy.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* This software is licensed by the MIT License, see LICENSE file */
|
||||
/* Copyright © 2022 Gregory Lirent */
|
||||
|
||||
#include "include.h"
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
static inline mnode_t* mnode_duplicate(const mnode_t* s, mnode_t* p, const vtype t) {
|
||||
mnode_t* x;
|
||||
|
||||
x = mnode_create(vnode_duplicate(&s->key, t), p, s->colored);
|
||||
x->type = s->type;
|
||||
x->value = vnode_duplicate(&s->value, s->type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
map_t map_copy(const map_t* s) {
|
||||
|
||||
map_t x;
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
|
||||
x.type = s->type;
|
||||
|
||||
if (!mnode_is_empty(s->root)) {
|
||||
x.root = mnode_duplicate(s->root, mnode_empty, s->type);
|
||||
stack_push(&z, x.root);
|
||||
|
||||
do {
|
||||
mnode_t *p0 = stack_pop(&z);
|
||||
mnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!mnode_is_empty(p1->left)) {
|
||||
p0->left = mnode_duplicate(p1->left, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!mnode_is_empty(p1->right)) {
|
||||
p0->right = mnode_duplicate(p1->right, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x.root = mnode_empty;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
map_t* map_duplicate(const map_t* s) {
|
||||
|
||||
map_t* x = malloc(sizeof(*x));
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
|
||||
x->type = s->type;
|
||||
|
||||
if (!mnode_is_empty(s->root)) {
|
||||
x->root = mnode_duplicate(s->root, mnode_empty, s->type);
|
||||
stack_push(&z, x->root);
|
||||
|
||||
do {
|
||||
mnode_t *p0 = stack_pop(&z);
|
||||
mnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!mnode_is_empty(p1->left)) {
|
||||
p0->left = mnode_duplicate(p1->left, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!mnode_is_empty(p1->right)) {
|
||||
p0->right = mnode_duplicate(p1->right, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x->root = mnode_empty;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void map_copy_init(map_t* x, const map_t* s) {
|
||||
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
|
||||
x->type = s->type;
|
||||
|
||||
if (!mnode_is_empty(s->root)) {
|
||||
x->root = mnode_duplicate(s->root, mnode_empty, s->type);
|
||||
stack_push(&z, x->root);
|
||||
|
||||
do {
|
||||
mnode_t *p0 = stack_pop(&z);
|
||||
mnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!mnode_is_empty(p1->left)) {
|
||||
p0->left = mnode_duplicate(p1->left, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!mnode_is_empty(p1->right)) {
|
||||
p0->right = mnode_duplicate(p1->right, p0, s->type);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x->root = mnode_empty;
|
||||
}
|
@ -20,7 +20,8 @@ bool libcdsb_map_update(map_t* x, const void* k, vtype kt, const void* v, vtype
|
||||
cmp = vtype_compare(k, kt, vnode_peek(&n->key, kt), kt);
|
||||
|
||||
if (cmp == 0) {
|
||||
mnode_free(n, &kt);
|
||||
vnode_free(&n->key, x->type);
|
||||
vnode_free(&n->value, n->type);
|
||||
|
||||
n->key = kn;
|
||||
n->value = vnode_create(v, vt);
|
||||
@ -65,7 +66,8 @@ int libcdsb_map_find(map_t* x, const void* k, vtype t, void* _, map_access_callb
|
||||
|
||||
if (cut) {
|
||||
c = mnode_delete(&x->root, c);
|
||||
mnode_free(c, &x->type);
|
||||
vnode_free(&c->key, x->type);
|
||||
vnode_free(&c->value, c->type);
|
||||
free(c);
|
||||
}
|
||||
|
||||
@ -92,7 +94,8 @@ int libcdsb_map_foreach(map_t* x, void* dt, map_access_callback callback, bool f
|
||||
if (!mnode_is_empty(c->left)) stack_push(&z, c->left);
|
||||
|
||||
if (flush) {
|
||||
mnode_free(c, &x->type);
|
||||
vnode_free(&c->key, x->type);
|
||||
vnode_free(&c->value, c->type);
|
||||
free(c);
|
||||
}
|
||||
}
|
||||
@ -102,7 +105,8 @@ int libcdsb_map_foreach(map_t* x, void* dt, map_access_callback callback, bool f
|
||||
if (!mnode_is_empty(c->right)) stack_push(&z, c->right);
|
||||
if (!mnode_is_empty(c->left)) stack_push(&z, c->left);
|
||||
|
||||
mnode_free(c, &x->type);
|
||||
vnode_free(&c->key, x->type);
|
||||
vnode_free(&c->value, c->type);
|
||||
free(c);
|
||||
|
||||
c = stack_pop(&z);
|
||||
|
@ -28,8 +28,6 @@ static_assert(offsetof(struct libcdsb_rbtree_node, value) == offsetof(struct lib
|
||||
static_assert(offsetof(struct libcdsb_set, root) == offsetof(struct libcdsb_map, root), "Implementation assert");
|
||||
static_assert(offsetof(struct libcdsb_set, type) == offsetof(struct libcdsb_map, type), "Implementation assert");
|
||||
|
||||
extern void libcdsb_mnode_free(mnode_t* x, vtype* t);
|
||||
|
||||
#define mnode_empty ((mnode_t*)LIBCDSB_RBTREE_NODE_EMPTY)
|
||||
#define mnode_create(k, p, c) ((mnode_t*)libcdsb_rbtree_node_create(k, (rbnode_t*)p, c, sizeof(mnode_t)))
|
||||
#define mnode_fixup(r, n) libcdsb_rbtree_node_fixup((rbnode_t**)(r), (rbnode_t*)(n))
|
||||
@ -38,6 +36,4 @@ extern void libcdsb_mnode_free(mnode_t* x, vtype* t);
|
||||
#define mnode_is_empty(n) ((n) == mnode_empty)
|
||||
#define mnode_is_root(n) mnode_is_empty((n)->parent)
|
||||
|
||||
#define mnode_free libcdsb_mnode_free
|
||||
|
||||
#endif /* LIBCDSB_SRC_MAP_INCLUDE_H */
|
||||
|
@ -1,206 +0,0 @@
|
||||
/* This software is licensed by the MIT License, see LICENSE file */
|
||||
/* Copyright © 2022 Gregory Lirent */
|
||||
|
||||
#include "__internal/rbtree.h"
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
static rbnode_t* rbnode_duplicate(const rbnode_t* s, rbnode_t* p, const vtype* info) {
|
||||
return rbnode_create(vnode_duplicate(&s->value, (info) ? *info : VTYPE_POINTER), p, s->colored);
|
||||
}
|
||||
|
||||
static int rbnode_compare(const rbnode_t* s0, const rbnode_t* s1, vtype* tp) {
|
||||
vtype t = !is_null(tp) ? *tp : VTYPE_POINTER;
|
||||
return vnode_compare(s0->value, t, s1->value, t);
|
||||
}
|
||||
|
||||
static hash_t rbnode_hash(const rbnode_t* s, vtype* tp) {
|
||||
vtype t = (!is_null(tp)) ? *tp : VTYPE_POINTER;
|
||||
return vnode_hash(s->value, t);
|
||||
}
|
||||
|
||||
static void rbnode_free(rbnode_t* x, vtype *t) {
|
||||
if (!is_null(t)) vnode_free(&x->value, *t);
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
hash_t libcdsb_rbtree_hash(const void* s, hash_t (*node_hash)(const void* s, void* info), void* info) {
|
||||
|
||||
rbnode_t *c0, *c1;
|
||||
hash_t hash, v;
|
||||
stack_t z;
|
||||
|
||||
if (rbnode_is_empty(s)) return 0;
|
||||
if (is_null(node_hash)) node_hash = (void*)rbnode_hash;
|
||||
|
||||
z.prev = 0;
|
||||
hash = 1;
|
||||
c1 = (void*)s;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->left)) do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
if (!rbnode_is_empty(c0->left))
|
||||
stack_push(&z, c1 = c0->left);
|
||||
if (!rbnode_is_empty(c0->right))
|
||||
stack_push(&z, c0->right);
|
||||
} while (!is_null(z.value));
|
||||
|
||||
v = node_hash(c1, info);
|
||||
c1 = (void*)s;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->right)) do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
if (!rbnode_is_empty(c0->left))
|
||||
stack_push(&z, c1 = c0->left);
|
||||
if (!rbnode_is_empty(c0->right))
|
||||
stack_push(&z, c0->right);
|
||||
} while (!is_null(z.value));
|
||||
|
||||
v += node_hash(c1, info);
|
||||
|
||||
return hash ^ v;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
void* libcdsb_rbtree_duplicate(const rbnode_t* s, void* (*node_duplicate)(void* src, void* parent, void* info), void* info) {
|
||||
rbnode_t *p0, *p1, *x;
|
||||
stack_t z;
|
||||
|
||||
z.prev = 0;
|
||||
z.value = (void*)s;
|
||||
|
||||
if (is_null(node_duplicate)) {
|
||||
node_duplicate = (void*)rbnode_duplicate;
|
||||
}
|
||||
|
||||
if (!rbnode_is_empty(s)) {
|
||||
x = node_duplicate(z.value, rbnode_empty, info);
|
||||
stack_push(&z, x);
|
||||
|
||||
do {
|
||||
p0 = stack_pop(&z);
|
||||
p1 = stack_pop(&z);
|
||||
|
||||
if (!rbnode_is_empty(p1->left)) {
|
||||
p0->left = node_duplicate(p1->left, p0, info);
|
||||
|
||||
stack_push(&z, p1->left);
|
||||
stack_push(&z, p0->left);
|
||||
}
|
||||
|
||||
if (!rbnode_is_empty(p1->right)) {
|
||||
p0->right = node_duplicate(p1->right, p0, info);
|
||||
|
||||
stack_push(&z, p1->right);
|
||||
stack_push(&z, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x = rbnode_empty;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
int libcdsb_rbtree_compare(const rbnode_t* s0, const rbnode_t* s1, int (*node_compare)(const rbnode_t* s0, const rbnode_t* s1, void* info), void* info) {
|
||||
|
||||
rbnode_t *c0, *c1;
|
||||
stack_t z;
|
||||
int c = 0;
|
||||
|
||||
if (s0 == s1) return 0;
|
||||
if (is_null(node_compare)) node_compare = (void*)rbnode_compare;
|
||||
|
||||
z.prev = 0;
|
||||
z.value = 0;
|
||||
|
||||
stack_push(&z, (void*)s1);
|
||||
stack_push(&z, (void*)s0);
|
||||
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
c1 = stack_pop(&z);
|
||||
|
||||
if (rbnode_is_empty(c0) || rbnode_is_empty(c1)) {
|
||||
if (c0 != c1) {
|
||||
stack_flush(&z);
|
||||
return rbnode_is_empty(c0) ? -1 : 1;
|
||||
}
|
||||
} else if ((c = node_compare(c0, c1, info))) {
|
||||
if (c0->left == c1->right) { // <-- rbnode_empty
|
||||
c = node_compare(c0->right, c1, info);
|
||||
if (!c) c = node_compare(c0, c1->left, info);
|
||||
} else if (c0->right == c1->left) { // <-- rbnode_empty
|
||||
c = node_compare(c0, c1->right, info);
|
||||
if (!c) c = node_compare(c0->left, c1, info);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
stack_flush(&z);
|
||||
return c;
|
||||
}
|
||||
} else {
|
||||
stack_push(&z, c1->right);
|
||||
stack_push(&z, c0->right);
|
||||
stack_push(&z, c1->left);
|
||||
stack_push(&z, c0->left);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t libcdsb_rbtree_size(const void* s) {
|
||||
stack_t z = { .prev = 0, .value = (void*)s };
|
||||
size_t n = 0;
|
||||
rbnode_t* c;
|
||||
|
||||
if (!rbnode_is_empty(s)) {
|
||||
while ((c = stack_pop(&z))) {
|
||||
++n;
|
||||
if (!rbnode_is_empty(c->left))
|
||||
stack_push(&z, c->left);
|
||||
if (!rbnode_is_empty(c->right))
|
||||
stack_push(&z, c->right);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void libcdsb_rbtree_free(void* x, void (*node_free)(void* x, void* info), void* info) {
|
||||
rbnode_t *t, *c;
|
||||
|
||||
c = x;
|
||||
if (is_null(node_free)) node_free = (void*)rbnode_free;
|
||||
|
||||
while (!rbnode_is_empty(x)) {
|
||||
if (!rbnode_is_empty(c->left)) {
|
||||
c = c->left;
|
||||
} else if (!rbnode_is_empty(c->right)) {
|
||||
c = c->right;
|
||||
} else if (!rbnode_is_root(c)) {
|
||||
node_free(c, info);
|
||||
|
||||
t = c;
|
||||
c = c->parent;
|
||||
|
||||
if (t == c->left) c->left = rbnode_empty;
|
||||
else c->right = rbnode_empty;
|
||||
|
||||
free(t);
|
||||
} else {
|
||||
node_free(c, info);
|
||||
x = rbnode_empty;
|
||||
}
|
||||
}
|
||||
}
|
160
src/set/base.c
160
src/set/base.c
@ -6,10 +6,58 @@
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
hash_t vset_hash(const set_t* s) {
|
||||
return rbtree_hash(s->root, nullptr, (void*)&s->type) + VTYPE_SET;
|
||||
static inline int rbnode_compare(const rbnode_t* s0, const rbnode_t* s1, vtype t) {
|
||||
return vnode_compare(s0->value, t, s1->value, t);
|
||||
}
|
||||
|
||||
static inline hash_t rbnode_hash(const rbnode_t* s, vtype t) {
|
||||
return vnode_hash(&s->value, t);
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
hash_t vset_hash(const set_t* s) {
|
||||
|
||||
rbnode_t *c0, *c1;
|
||||
hash_t hash, v;
|
||||
stack_t z;
|
||||
|
||||
if (rbnode_is_empty(s->root)) return 0;
|
||||
|
||||
z.prev = 0;
|
||||
hash = 1;
|
||||
c1 = s->root;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->left)) {
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
|
||||
if (!rbnode_is_empty(c0->right)) stack_push(&z, c1 = c0->right);
|
||||
if (!rbnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left);
|
||||
} while (!is_null(z.value));
|
||||
}
|
||||
|
||||
v = rbnode_hash(c1, s->type);
|
||||
c1 = s->root;
|
||||
|
||||
if (!rbnode_is_empty(z.value = c1->right)) {
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
++hash;
|
||||
|
||||
if (!rbnode_is_empty(c0->right)) stack_push(&z, c1 = c0->right);
|
||||
if (!rbnode_is_empty(c0->left)) stack_push(&z, c1 = c0->left);
|
||||
} while (!is_null(z.value));
|
||||
}
|
||||
|
||||
v += rbnode_hash(c1, s->type);
|
||||
|
||||
return (hash ^ v) + VTYPE_SET;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
void vset_init(set_t* x, vtype t) {
|
||||
x->root = rbnode_empty;
|
||||
x->type = t;
|
||||
@ -17,48 +65,94 @@ void vset_init(set_t* x, vtype t) {
|
||||
|
||||
|
||||
void vset_free(set_t* x) {
|
||||
rbtree_free(x->root, nullptr, &x->type);
|
||||
rbnode_t *t, *c;
|
||||
|
||||
c = x->root;
|
||||
|
||||
while (!rbnode_is_empty(x->root)) {
|
||||
if (!rbnode_is_empty(c->left)) {
|
||||
c = c->left;
|
||||
} else if (!rbnode_is_empty(c->right)) {
|
||||
c = c->right;
|
||||
} else if (!rbnode_is_root(c)) {
|
||||
vnode_free(&c->value, x->type);
|
||||
|
||||
t = c;
|
||||
c = c->parent;
|
||||
|
||||
if (t == c->left) c->left = rbnode_empty;
|
||||
else c->right = rbnode_empty;
|
||||
|
||||
free(t);
|
||||
} else {
|
||||
vnode_free(&c->value, x->type);
|
||||
x->root = rbnode_empty;
|
||||
}
|
||||
}
|
||||
|
||||
x->root = rbnode_empty;
|
||||
x->type = 0;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
size_t vset_size(const set_t* x) {
|
||||
return rbtree_size(x->root);
|
||||
stack_t z = { .prev = 0, .value = x->root };
|
||||
size_t n = 0;
|
||||
rbnode_t* c;
|
||||
|
||||
if (!rbnode_is_empty(x->root)) {
|
||||
while ((c = stack_pop(&z))) {
|
||||
++n;
|
||||
if (!rbnode_is_empty(c->right)) stack_push(&z, c->right);
|
||||
if (!rbnode_is_empty(c->left)) stack_push(&z, c->left);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
int vset_compare(const set_t* s0, const set_t* s1) {
|
||||
if (s0 == s1) return 0;
|
||||
if (s0->type != s1->type) return s0->type - s1->type;
|
||||
rbnode_t *c0, *c1;
|
||||
stack_t z;
|
||||
int c = 0;
|
||||
|
||||
return rbtree_compare(s0->root, s1->root, nullptr, (void*)&s0->type);
|
||||
}
|
||||
|
||||
/*#####################################################################################################################*/
|
||||
|
||||
set_t vset_copy(const set_t* s) {
|
||||
set_t x;
|
||||
|
||||
x.type = s->type;
|
||||
x.root = rbtree_duplicate(s->root, nullptr, &x.type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
set_t* vset_duplicate(const set_t* s) {
|
||||
set_t *x = malloc(sizeof(*x));
|
||||
|
||||
x->type = s->type;
|
||||
x->root = rbtree_duplicate(s->root, nullptr, &x->type);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void vset_copy_init(set_t* x, const set_t* s) {
|
||||
x->type = s->type;
|
||||
x->root = rbtree_duplicate(s->root, nullptr, &x->type);
|
||||
if (s0 == s1 || s0->root == s1->root)
|
||||
return 0;
|
||||
if (s0->type != s1->type)
|
||||
return s0->type - s1->type;
|
||||
|
||||
z.prev = 0;
|
||||
z.value = 0;
|
||||
|
||||
stack_push_many(&z, 2, (void*)s1, (void*)s0);
|
||||
|
||||
do {
|
||||
c0 = stack_pop(&z);
|
||||
c1 = stack_pop(&z);
|
||||
|
||||
if (rbnode_is_empty(c0) || rbnode_is_empty(c1)) {
|
||||
if (c0 != c1) {
|
||||
stack_flush(&z);
|
||||
return rbnode_is_empty(c0) ? -1 : 1;
|
||||
}
|
||||
} else if ((c = rbnode_compare(c0, c1, s0->type))) {
|
||||
if (c0->left == c1->right) { // == rbnode_empty
|
||||
c = rbnode_compare(c0->right, c1, s0->type);
|
||||
if (!c) c = rbnode_compare(c0, c1->left, s0->type);
|
||||
} else if (c0->right == c1->left) { // == rbnode_empty
|
||||
c = rbnode_compare(c0, c1->right, s0->type);
|
||||
if (!c) c = rbnode_compare(c0->left, c1, s0->type);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
stack_flush(&z);
|
||||
return c;
|
||||
}
|
||||
} else stack_push_many(&z, 4, c1->right, c0->right, c1->left, c0->left);
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
97
src/set/copy.c
Normal file
97
src/set/copy.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* This software is licensed by the MIT License, see LICENSE file */
|
||||
/* Copyright © 2022 Gregory Lirent */
|
||||
|
||||
#include "../../include/set.h"
|
||||
#include "../__internal/rbtree.h"
|
||||
|
||||
set_t vset_copy(const set_t* s) {
|
||||
|
||||
set_t x = { .type = s->type };
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
vtype t = s->type;
|
||||
|
||||
if (!rbnode_is_empty(s->root)) {
|
||||
x.root = rbnode_create(vnode_duplicate(&s->root->value, t), rbnode_empty, 0);
|
||||
stack_push(&z, x.root);
|
||||
|
||||
do {
|
||||
rbnode_t *p0 = stack_pop(&z);
|
||||
rbnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!rbnode_is_empty(p1->left)) {
|
||||
p0->left = rbnode_create(vnode_duplicate(&p1->left->value, t), p0, p1->left->colored);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!rbnode_is_empty(p1->right)) {
|
||||
p0->right = rbnode_create(vnode_duplicate(&p1->right->value, t), p0, p1->right->colored);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x.root = rbnode_empty;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
set_t* vset_duplicate(const set_t* s) {
|
||||
|
||||
set_t* x = malloc(sizeof(*x));
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
vtype t = x->type = s->type;
|
||||
|
||||
if (!rbnode_is_empty(s->root)) {
|
||||
x->root = rbnode_create(vnode_duplicate(&s->root->value, t), rbnode_empty, 0);
|
||||
stack_push(&z, x->root);
|
||||
|
||||
do {
|
||||
rbnode_t *p0 = stack_pop(&z);
|
||||
rbnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!rbnode_is_empty(p1->left)) {
|
||||
p0->left = rbnode_create(vnode_duplicate(&p1->left->value, t), p0, p1->left->colored);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!rbnode_is_empty(p1->right)) {
|
||||
p0->right = rbnode_create(vnode_duplicate(&p1->right->value, t), p0, p1->right->colored);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x->root = rbnode_empty;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
void vset_copy_init(set_t* x, const set_t* s) {
|
||||
|
||||
stack_t z = { .prev = 0, .value = s->root };
|
||||
vtype t = x->type = s->type;
|
||||
|
||||
if (!rbnode_is_empty(s->root)) {
|
||||
x->root = rbnode_create(vnode_duplicate(&s->root->value, t), rbnode_empty, 0);
|
||||
stack_push(&z, x->root);
|
||||
|
||||
do {
|
||||
rbnode_t *p0 = stack_pop(&z);
|
||||
rbnode_t *p1 = stack_pop(&z);
|
||||
|
||||
if (!rbnode_is_empty(p1->left)) {
|
||||
p0->left = rbnode_create(vnode_duplicate(&p1->left->value, t), p0, p1->left->colored);
|
||||
stack_push_many(&z, 2, p1->left, p0->left);
|
||||
}
|
||||
|
||||
if (!rbnode_is_empty(p1->right)) {
|
||||
p0->right = rbnode_create(vnode_duplicate(&p1->right->value, t), p0, p1->right->colored);
|
||||
stack_push_many(&z, 2, p1->right, p0->right);
|
||||
}
|
||||
|
||||
} while (!is_null(z.value));
|
||||
|
||||
} else x->root = rbnode_empty;
|
||||
}
|
Loading…
Reference in New Issue
Block a user