diff --git a/include/extra/set.h b/include/extra/set.h new file mode 100644 index 0000000..80fabf9 --- /dev/null +++ b/include/extra/set.h @@ -0,0 +1,16 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../set.h" + +#ifndef LIBCDSB_EXTRA_SET_H +#define LIBCDSB_EXTRA_SET_H + +#define vset_foreach libcdsb_vset_foreach + +extern _Bool libcdsb_vset_find (vtype_value* x, vtype_set* s, const void* value, vtype type, _Bool cut); +extern _Bool libcdsb_vset_insert(vtype_set* x, const void* value, vtype type); + +extern int libcdsb_vset_foreach(const vtype_set* x, int (*callback)(const void* value, vtype type)) LIBCDSB_nt__ LIBCDSB_nn12__; + +#endif /* LIBCDSB_EXTRA_SET_H */ diff --git a/include/set.h b/include/set.h new file mode 100644 index 0000000..cb0202e --- /dev/null +++ b/include/set.h @@ -0,0 +1,57 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "__generics.h" +#include "vtype.h" + +#ifndef LIBCDSB_SET_H +#define LIBCDSB_SET_H + +extern void vset_init(vtype_set* x, vtype type); + +#define vset_remove(x, value) _LIBCDSB_Generic (libcdsb_vset, touch, key)(x, value, 1) +#define vset_push(x, value) _LIBCDSB_Generic (libcdsb_vset, push, key)(x, value) + +#define in_vset(x, value) _LIBCDSB_Generic (libcdsb_vset, touch, key)(x, value, 0) + +extern _Bool libcdsb_vset_push_pointer(vtype_set* x, const void* value); +extern _Bool libcdsb_vset_push_cstring(vtype_set* x, const char* value); +extern _Bool libcdsb_vset_push_string (vtype_set* x, const vtype_string* value); +extern _Bool libcdsb_vset_push_array (vtype_set* x, const vtype_array* value); +extern _Bool libcdsb_vset_push_list (vtype_set* x, const vtype_list* value); +extern _Bool libcdsb_vset_push_map (vtype_set* x, const vtype_map* value); +extern _Bool libcdsb_vset_push_vset (vtype_set* x, const vtype_set* value); +extern _Bool libcdsb_vset_push_boolean(vtype_set* x, vtype_bool value); +extern _Bool libcdsb_vset_push_uint8 (vtype_set* x, vtype_uint8 value); +extern _Bool libcdsb_vset_push_uint16 (vtype_set* x, vtype_uint16 value); +extern _Bool libcdsb_vset_push_uint32 (vtype_set* x, vtype_uint32 value); +extern _Bool libcdsb_vset_push_uint64 (vtype_set* x, vtype_uint64 value); +extern _Bool libcdsb_vset_push_int8 (vtype_set* x, vtype_int8 value); +extern _Bool libcdsb_vset_push_int16 (vtype_set* x, vtype_int16 value); +extern _Bool libcdsb_vset_push_int32 (vtype_set* x, vtype_int32 value); +extern _Bool libcdsb_vset_push_int64 (vtype_set* x, vtype_int64 value); +extern _Bool libcdsb_vset_push_float (vtype_set* x, vtype_float value); +extern _Bool libcdsb_vset_push_double (vtype_set* x, vtype_double value); +extern _Bool libcdsb_vset_push_ldouble(vtype_set* x, vtype_ldouble value); + +extern _Bool libcdsb_vset_touch_pointer(vtype_set* x, const void* value, _Bool cut); +extern _Bool libcdsb_vset_touch_cstring(vtype_set* x, const char* value, _Bool cut); +extern _Bool libcdsb_vset_touch_string (vtype_set* x, const vtype_string* value, _Bool cut); +extern _Bool libcdsb_vset_touch_array (vtype_set* x, const vtype_array* value, _Bool cut); +extern _Bool libcdsb_vset_touch_list (vtype_set* x, const vtype_list* value, _Bool cut); +extern _Bool libcdsb_vset_touch_map (vtype_set* x, const vtype_map* value, _Bool cut); +extern _Bool libcdsb_vset_touch_vset (vtype_set* x, const vtype_set* value, _Bool cut); +extern _Bool libcdsb_vset_touch_boolean(vtype_set* x, vtype_bool value, _Bool cut); +extern _Bool libcdsb_vset_touch_uint8 (vtype_set* x, vtype_uint8 value, _Bool cut); +extern _Bool libcdsb_vset_touch_uint16 (vtype_set* x, vtype_uint16 value, _Bool cut); +extern _Bool libcdsb_vset_touch_uint32 (vtype_set* x, vtype_uint32 value, _Bool cut); +extern _Bool libcdsb_vset_touch_uint64 (vtype_set* x, vtype_uint64 value, _Bool cut); +extern _Bool libcdsb_vset_touch_int8 (vtype_set* x, vtype_int8 value, _Bool cut); +extern _Bool libcdsb_vset_touch_int16 (vtype_set* x, vtype_int16 value, _Bool cut); +extern _Bool libcdsb_vset_touch_int32 (vtype_set* x, vtype_int32 value, _Bool cut); +extern _Bool libcdsb_vset_touch_int64 (vtype_set* x, vtype_int64 value, _Bool cut); +extern _Bool libcdsb_vset_touch_float (vtype_set* x, vtype_float value, _Bool cut); +extern _Bool libcdsb_vset_touch_double (vtype_set* x, vtype_double value, _Bool cut); +extern _Bool libcdsb_vset_touch_ldouble(vtype_set* x, vtype_ldouble value, _Bool cut); + +#endif /* LIBCDSB_SET_H */ diff --git a/src/__internal/rbtree.h b/src/__internal/rbtree.h index f0eb203..33d4fb5 100644 --- a/src/__internal/rbtree.h +++ b/src/__internal/rbtree.h @@ -43,6 +43,10 @@ extern void libcdsb_rbtree_iter_reset(rbiter_t* iter); #define rbnode_fixup libcdsb_rbtree_node_fixup #define rbnode_delete libcdsb_rbtree_node_delete +#define rbiter_init libcdsb_rbtree_iter_init +#define rbiter_next libcdsb_rbtree_iter_next +#define rbiter_reset libcdsb_rbtree_iter_reset + #define rbnode_is_empty(n) ((n) == rbnode_empty) #define rbnode_is_root(n) rbnode_is_empty((n)->parent) diff --git a/src/set/base.c b/src/set/base.c new file mode 100644 index 0000000..0b93fbb --- /dev/null +++ b/src/set/base.c @@ -0,0 +1,98 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../../include/set.h" +#include "../__internal/rbtree.h" + +/*#####################################################################################################################*/ + + +static int tree_compare(rbiter_t* s0, rbiter_t* s1, vtype t) { + rbnode_t* p0; + rbnode_t* p1; + int cmp; + + for(;;) { + p0 = rbiter_next(s0); + p1 = rbiter_next(s1); + + if (rbnode_is_empty(p0) || rbnode_is_empty(p1)) { + goto end_; + } else cmp = vnode_compare(&p0->value, t, &p1->value, t); + + if (cmp != 0) break; + } + + for(;;) { + p0 = rbiter_next(s0); + p1 = rbiter_next(s1); + + if (rbnode_is_empty(p0) || rbnode_is_empty(p1)) { + end_: + if (p0 == p1) return cmp; + return (rbnode_is_empty(p0)) ? -1 : 1; + } + } +} + +/*#####################################################################################################################*/ + + +void vset_init(vtype_set* x, vtype t) { + x->root = rbnode_empty; + x->type = t; +} + +void vset_free(vtype_set* x) { + rbnode_t* t; + rbnode_t* c; + + 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->type = 0; +} + +size_t vset_size(const vtype_set* x) { + size_t n; + rbiter_t i; + + n = 0; + + if (rbiter_init(&i, &x->root, 0)) { + while (!rbnode_is_empty(rbiter_next(&i))) + ++n; + } + + return n; +} + +int vset_compare(const vtype_set* s0, const vtype_set* s1) { + rbiter_t iter[2]; + + if (s0 == s1) return 0; + if (s0->type == s1->type) { + rbiter_init(iter+0, &s0->root, RBI_INORDER); + rbiter_init(iter+1, &s1->root, RBI_INORDER); + + return tree_compare(iter+0, iter+1, s0->type); + } else return s0->type < s1->type ? -1 : 1; +} diff --git a/src/set/copy.c b/src/set/copy.c new file mode 100644 index 0000000..ac75e6a --- /dev/null +++ b/src/set/copy.c @@ -0,0 +1,59 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../../include/set.h" +#include "../__internal/rbtree.h" + +/*#####################################################################################################################*/ + +static void copy_child(rbnode_t* x, vtype t, const rbnode_t* l, const rbnode_t* r) { + + if (!rbnode_is_empty(l)) { + x->left = rbnode_create(vnode_duplicate(&l->value, t), x, l->colored); + copy_child(x->left, t, l->left, l->right); + } else x->left = rbnode_empty; + + if (!rbnode_is_empty(r)) { + x->left = rbnode_create(vnode_duplicate(&r->value, t), x, r->colored); + copy_child(x->right, t, r->right, r->right); + } else x->right = rbnode_empty; +} + +/*#####################################################################################################################*/ + +vtype_set vset_copy(const vtype_set* s) { + + set_t x = { .type = s->type }; + + if (!rbnode_is_empty(s->root)) { + x.root = rbnode_create(vnode_duplicate(&s->root->value, s->type), rbnode_empty, 0); + + copy_child(x.root, s->type, s->root->left, s->root->right); + } else x.root = rbnode_empty; + + return x; +} + +vtype_set* vset_duplicate(const vtype_set* s) { + set_t* x = malloc(sizeof(*x)); + + x->type = s->type; + + if (!rbnode_is_empty(s->root)) { + x->root = rbnode_create(vnode_duplicate(&s->root->value, s->type), rbnode_empty, 0); + + copy_child(x->root, s->type, s->root->left, s->root->right); + } else x->root = rbnode_empty; + + return x; +} + +void vset_copy_init(vtype_set* x, const vtype_set* s) { + x->type = s->type; + + if (!rbnode_is_empty(s->root)) { + x->root = rbnode_create(vnode_duplicate(&s->root->value, s->type), rbnode_empty, 0); + + copy_child(x->root, s->type, s->root->left, s->root->right); + } else x->root = rbnode_empty; +} diff --git a/src/set/extra.c b/src/set/extra.c new file mode 100644 index 0000000..0c68389 --- /dev/null +++ b/src/set/extra.c @@ -0,0 +1,86 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../../include/extra/set.h" +#include "../__internal/rbtree.h" + +/*#####################################################################################################################*/ + + +_Bool libcdsb_vset_find(val_t* x, set_t* s, const void* v, vtype t, _Bool cut) { + rbnode_t* c; + int cmp; + + c = s->root; + + while (!rbnode_is_empty(c)) { + + cmp = vtype_compare(vnode_peek(&c->value, s->type), s->type, v, t); + + if (cmp == 0) { + if (cut) { + c = rbnode_delete(&s->root, c); + if (!is_null(x)) { + value_set(x, c->value, s->type, VF_WRITEABLE|VF_REMOVABLE); + } else vnode_free(&c->value, s->type); + free(c); + } else if (!is_null(x)) value_set(x, c->value, s->type, VF_UNDEFINED); + + return true; + } + + c = (cmp < 0) ? c->right : c->left; + } + return rbnode_empty; +} + + +_Bool libcdsb_vset_insert(set_t* x, const void* v, vtype t) { + int cmp; + rbnode_t* n; + rbnode_t* p; + + n = x->root; + + if (!rbnode_is_empty(n)) { + do { + p = n; + cmp = vtype_compare(vnode_peek(&n->value, x->type), x->type, v, t); + + if (cmp == 0) return false; + + n = (cmp > 0) ? n->left : n->right; + } while (!rbnode_is_empty(n)); + + n = rbnode_create(0, p, 1); + + if (cmp > 0) p->left = n; + else p->right = n; + + if (!rbnode_is_root(n->parent)) + rbnode_fixup(&x->root, n); + + } else n = x->root = rbnode_create(0, p, 1); + + n->value = vnode_tcreate(x->type, v, t); + + return true; +} + + +/*#####################################################################################################################*/ + + +int libcdsb_vset_foreach(const vtype_set* x, int (*callback)(const void* value, vtype type)) { + rbiter_t i; + int r; + + if (rbiter_init(&i, &x->root, 0)) { + while (!rbnode_is_empty(rbiter_next(&i))) { + if ((r = callback(vnode_peek(&i.cursor->value, x->type), x->type))) + return r; + } + } + + return 0; +} diff --git a/src/set/generics.c b/src/set/generics.c new file mode 100644 index 0000000..946ea80 --- /dev/null +++ b/src/set/generics.c @@ -0,0 +1,45 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../../include/extra/set.h" +#include "../__internal/include.h" + +_Bool libcdsb_vset_touch_pointer(set_t* x, const void* k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_cstring(set_t* x, const char* k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_string (set_t* x, const str_t* k, _Bool f) { return libcdsb_vset_find(0, x, k, vtypeof( k), f); } +_Bool libcdsb_vset_touch_array (set_t* x, const arr_t* k, _Bool f) { return libcdsb_vset_find(0, x, k, vtypeof( k), f); } +_Bool libcdsb_vset_touch_list (set_t* x, const list_t* k, _Bool f) { return libcdsb_vset_find(0, x, k, vtypeof( k), f); } +_Bool libcdsb_vset_touch_map (set_t* x, const map_t* k, _Bool f) { return libcdsb_vset_find(0, x, k, vtypeof( k), f); } +_Bool libcdsb_vset_touch_vset (set_t* x, const set_t* k, _Bool f) { return libcdsb_vset_find(0, x, k, vtypeof( k), f); } +_Bool libcdsb_vset_touch_boolean(set_t* x, _Bool k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_int8 (set_t* x, s8_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_int16 (set_t* x, s16_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_int32 (set_t* x, s32_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_int64 (set_t* x, s64_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_uint8 (set_t* x, u8_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_uint16 (set_t* x, u16_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_uint32 (set_t* x, u32_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_uint64 (set_t* x, u64_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_float (set_t* x, fl_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_double (set_t* x, dbl_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } +_Bool libcdsb_vset_touch_ldouble(set_t* x, ldbl_t k, _Bool f) { return libcdsb_vset_find(0, x, &k, vtypeof(&k), f); } + +_Bool libcdsb_vset_push_pointer(set_t* x, const void* v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_cstring(set_t* x, const char* v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_string (set_t* x, const str_t* v) { return libcdsb_vset_insert(x, v, vtypeof( v)); } +_Bool libcdsb_vset_push_array (set_t* x, const arr_t* v) { return libcdsb_vset_insert(x, v, vtypeof( v)); } +_Bool libcdsb_vset_push_list (set_t* x, const list_t* v) { return libcdsb_vset_insert(x, v, vtypeof( v)); } +_Bool libcdsb_vset_push_map (set_t* x, const map_t* v) { return libcdsb_vset_insert(x, v, vtypeof( v)); } +_Bool libcdsb_vset_push_vset (set_t* x, const set_t* v) { return libcdsb_vset_insert(x, v, vtypeof( v)); } +_Bool libcdsb_vset_push_boolean(set_t* x, _Bool v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_int8 (set_t* x, s8_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_int16 (set_t* x, s16_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_int32 (set_t* x, s32_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_int64 (set_t* x, s64_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_uint8 (set_t* x, u8_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_uint16 (set_t* x, u16_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_uint32 (set_t* x, u32_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_uint64 (set_t* x, u64_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_float (set_t* x, fl_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_double (set_t* x, dbl_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); } +_Bool libcdsb_vset_push_ldouble(set_t* x, ldbl_t v) { return libcdsb_vset_insert(x, &v, vtypeof(&v)); }