From 9f83f595029d67794952d29b1faa10db09918b90 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:20:04 +0300 Subject: [PATCH 1/9] Update headers --- include/dict.h | 6 ++++++ include/extra/dict.h | 2 +- include/extra/memory.h | 3 +++ include/extra/string.h | 12 ++++++------ include/extra/vtype.h | 2 -- include/list.h | 4 ++-- include/map.h | 6 ++++++ include/set.h | 7 ++++++- include/string.h | 4 ++-- include/vtype.h | 2 -- src/__internal/include.h | 2 ++ 11 files changed, 34 insertions(+), 16 deletions(-) diff --git a/include/dict.h b/include/dict.h index 8ff850c..d6f9963 100644 --- a/include/dict.h +++ b/include/dict.h @@ -7,6 +7,8 @@ #ifndef LIBCDSB_DICT_H #define LIBCDSB_DICT_H +/*#####################################################################################################################*/ + typedef int (*dict_access_callback)(const void* key, vtype key_type, void* value, vtype value_type, void* data); extern void dict_init(vtype_dict* x) Nonnull__(1); @@ -16,6 +18,10 @@ extern void dict_init(vtype_dict* x) Nonnull__(1); #define dict_update(x, key, value) _LIBCDSB_Generic2(libcdsb_dict, update, key, value)(x, key, value) #define dict_remove(x, key) dict_pop(x, key, 0, 0) +#define in_dict(x, key) (dict_get(&x, key, 0, 0) == 0) + +/*#####################################################################################################################*/ + extern int libcdsb_dict_get_by_pointer(vtype_dict* x, const void* key, void* data, dict_access_callback, bool cut) Nonnull__(1); extern int libcdsb_dict_get_by_cstring(vtype_dict* x, const char* key, void* data, dict_access_callback, bool cut) Nonnull__(1,2); extern int libcdsb_dict_get_by_string (vtype_dict* x, const vtype_string* key, void* data, dict_access_callback, bool cut) Nonnull__(1,2); diff --git a/include/extra/dict.h b/include/extra/dict.h index 47bc976..972b77b 100644 --- a/include/extra/dict.h +++ b/include/extra/dict.h @@ -9,7 +9,7 @@ #define dict_foreach(x, data, callback) libcdsb_dict_foreach(x, data, callback, 0) extern bool libcdsb_dict_update (vtype_dict* x, const void* key, vtype key_type, const void* value, vtype value_type) Nonnull__(1); -extern int libcdsb_dict_get (vtype_dict* x, const void* key, vtype key_type, void* data, dict_access_callback, bool cut) Nonnull__(1); +extern int libcdsb_dict_find (vtype_dict* x, const void* key, vtype key_type, void* data, dict_access_callback, bool cut) Nonnull__(1); extern int libcdsb_dict_foreach (vtype_dict* x, void* data, dict_access_callback, bool flush) Nonnull__(1,3); extern bool libcdsb_dict_shrink_to_fit(vtype_dict* x) Nonnull__(1); diff --git a/include/extra/memory.h b/include/extra/memory.h index b21b43e..e27f73b 100644 --- a/include/extra/memory.h +++ b/include/extra/memory.h @@ -22,10 +22,13 @@ extern void* libcdsb_malloc (size_t n) Warn_unused_result__; extern void* libcdsb_calloc (size_t n, size_t c) Warn_unused_result__; extern void* libcdsb_realloc(void *p, size_t n) Warn_unused_result__; +extern void libcdsb_free(void* s); + #define aligned_alloc libcdsb_aalloc #define malloc libcdsb_malloc #define calloc libcdsb_calloc #define realloc libcdsb_realloc +#define free libcdsb_free #define stack_init libcdsb_stack_init #define stack_push libcdsb_stack_push diff --git a/include/extra/string.h b/include/extra/string.h index 64490ef..283df4b 100644 --- a/include/extra/string.h +++ b/include/extra/string.h @@ -8,7 +8,7 @@ /*#####################################################################################################################*/ -#define string_split(x, sep, maxn) _LIBCDSB_GenericS(libcdsb_string, split, sep)(x, sep, maxn) +#define string_split(s, sep, maxn) _LIBCDSB_GenericS(libcdsb_string, split, sep)(s, sep, maxn) #define string_case_compare string_compare_case_insensitive #define string_replace_r(x, src, dest, maxn) _LIBCDSB_GenericS2(libcdsb_string, replace_r, src, dest)(x, src, dest, maxn) @@ -27,15 +27,15 @@ extern size_t string_align_center(vtype_string* x, size_t padsize, int padchr) N extern size_t string_align_right (vtype_string* x, size_t padsize, int padchr) Nonnull__(1); extern size_t string_align_left (vtype_string* x, size_t padsize, int padchr) Nonnull__(1); -extern int string_compare_case_insensitive(const vtype_string* s0, const vtype_string* s1) Pure__ Warn_unused_result__ Nonnull__(1,2); - extern void libcdsb_string_replace(vtype_string* x, char* dest, size_t dest_nmemb, const char* src, size_t nmemb) Nonnull__(1,2); /*#####################################################################################################################*/ -inline vtype_array libcdsb_string_split_string (const vtype_string* x, const vtype_string* sep, size_t maxn) Nonnull__(1) Always_inline__; -extern vtype_array libcdsb_string_split_cstring(const vtype_string* string, const char* sep, size_t maxn) Nonnull__(1); -extern vtype_array libcdsb_string_split_char (const vtype_string* string, int chr, size_t maxn) Nonnull__(1); +extern int string_compare_case_insensitive(const vtype_string* s0, const vtype_string* s1) Pure__ Warn_unused_result__ Nonnull__(1,2); + +inline vtype_array libcdsb_string_split_string (const vtype_string* s, const vtype_string* sep, size_t maxn) Nonnull__(1) Always_inline__; +extern vtype_array libcdsb_string_split_cstring(const vtype_string* s, const char* sep, size_t maxn) Nonnull__(1); +extern vtype_array libcdsb_string_split_char (const vtype_string* s, int chr, size_t maxn) Nonnull__(1); inline void libcdsb_string_trim_string (vtype_string* x, const vtype_string* s, int direction) Nonnull__(1) Always_inline__; extern void libcdsb_string_trim_cstring(vtype_string* x, const char* s, int direction) Nonnull__(1); diff --git a/include/extra/vtype.h b/include/extra/vtype.h index 7c5aec9..af4307d 100644 --- a/include/extra/vtype.h +++ b/include/extra/vtype.h @@ -6,8 +6,6 @@ #ifndef LIBCDSB_EXTRA_VTYPE_H #define LIBCDSB_EXTRA_VTYPE_H -extern const size_t LIBCDSB_VTYPE_SIZES[18]; - extern const char* libcdsb_vtype_name(vtype t) Warn_unused_result__; extern const char* libcdsb_vtype_stringify(const void* value, vtype t) Warn_unused_result__; diff --git a/include/list.h b/include/list.h index 219e04e..2cde5b4 100644 --- a/include/list.h +++ b/include/list.h @@ -11,8 +11,8 @@ typedef int (*list_access_callback)(void* value, ssize_t index, vtype type, void* data); -extern void list_init (vtype_list* x) Nonnull__(1); -extern void list_extend(vtype_list* x, const vtype_list* s) Nonnull__(1,2); +extern void list_init (vtype_list* x) Nonnull__(1); +extern void list_extend (vtype_list* x, const vtype_list* s) Nonnull__(1,2); extern size_t list_slice (vtype_list* x, vtype_list* src, ssize_t index, size_t count, bool cut) Nonnull__(1,2); extern void list_sort (vtype_list* x) Nonnull__(1); extern void list_reverse(vtype_list* x) Nonnull__(1); diff --git a/include/map.h b/include/map.h index 4248050..85755bf 100644 --- a/include/map.h +++ b/include/map.h @@ -7,6 +7,8 @@ #ifndef LIBCDSB_MAP_H #define LIBCDSB_MAP_H +/*#####################################################################################################################*/ + typedef int (*map_access_callback)(const void* key, vtype key_type, void* value, vtype value_type, void* data); extern void map_init(vtype_map* x, vtype key_type) Nonnull__(1); @@ -16,6 +18,10 @@ extern void map_init(vtype_map* x, vtype key_type) Nonnull__(1); #define map_update(x, key, value) _LIBCDSB_Generic2(libcdsb_map, update, key, value)(x, key, value) #define map_remove(x, key) map_pop(x, key, 0, 0) +#define in_map(x, key) (map_get(&x, key, 0, 0) == 0) + +/*#####################################################################################################################*/ + extern int libcdsb_map_find_pointer(vtype_map* x, const void* key, void* data, map_access_callback, bool cut) Nonnull__(1); extern int libcdsb_map_find_cstring(vtype_map* x, const char* key, void* data, map_access_callback, bool cut) Nonnull__(1,2); extern int libcdsb_map_find_string (vtype_map* x, const vtype_string* key, void* data, map_access_callback, bool cut) Nonnull__(1,2); diff --git a/include/set.h b/include/set.h index 238c910..d679c98 100644 --- a/include/set.h +++ b/include/set.h @@ -7,6 +7,8 @@ #ifndef LIBCDSB_SET_H #define LIBCDSB_SET_H +/*#####################################################################################################################*/ + typedef int (*vset_access_callback)(const void* value, vtype type, void* data); extern void vset_init(vtype_set* x, vtype type) Nonnull__(1); @@ -14,8 +16,11 @@ extern void vset_init(vtype_set* x, vtype type) Nonnull__(1); #define vset_pop(x, value, data, callback) _LIBCDSB_Generic (libcdsb_vset, find, value)(x, value, data, callback, 1) #define vset_get(x, value, data, callback) _LIBCDSB_Generic (libcdsb_vset, find, value)(x, value, data, callback, 0) #define vset_push(x, value) _LIBCDSB_Generic (libcdsb_vset, push, value)(x, value) +#define vset_remove(x, value) vset_pop(x, value, 0, 0) -#define in_vset(x, value) (vset_get(&x, value, 0, 0, 0) == 0) +#define in_vset(x, value) (vset_get(&x, value, 0, 0) == 0) + +/*#####################################################################################################################*/ extern bool libcdsb_vset_push_pointer(vtype_set* x, const void* value) Nonnull__(1); extern bool libcdsb_vset_push_cstring(vtype_set* x, const char* value) Nonnull__(1,2); diff --git a/include/string.h b/include/string.h index aeb51fd..b8e8474 100644 --- a/include/string.h +++ b/include/string.h @@ -13,11 +13,11 @@ extern void string_init(vtype_string* x, const char* value) Nonnull__(1); extern char* string_at(const vtype_string* s, ssize_t index) Nonnull__(1); -extern bool string_slice(vtype_string* x, vtype_string* s, ssize_t index, size_t nchars, bool cut) Nonnull__(1,2); +extern size_t string_slice(vtype_string* x, vtype_string* s, ssize_t index, size_t nchars, bool cut) Nonnull__(1,2); #define string_indexof(s, arg) _LIBCDSB_GenericS(libcdsb_string, indexof, arg)(s, arg) #define string_count(s, arg) _LIBCDSB_GenericS(libcdsb_string, count, arg)(s, arg) -#define string_concat(s, value) _LIBCDSB_GenericS(libcdsb_string, concat, value)(s, value) +#define string_concat(x, value) _LIBCDSB_GenericS(libcdsb_string, concat, value)(x, value) #define string_trim_spaces(x) libcdsb_string_trim_spaces(x, 0) #define string_ltrim_spaces(x) libcdsb_string_trim_spaces(x, -1) diff --git a/include/vtype.h b/include/vtype.h index 8238a19..4ec686c 100644 --- a/include/vtype.h +++ b/include/vtype.h @@ -31,8 +31,6 @@ typedef enum libcdsb_value_types { VTYPE_LIST = 16, VTYPE_SET = 17, VTYPE_DICT = 18, - - LIBCDSB_VTYPE_TERMINATION, /* It must be at the end of the enum. Never be used */ } vtype; diff --git a/src/__internal/include.h b/src/__internal/include.h index 76f096d..dbefa85 100644 --- a/src/__internal/include.h +++ b/src/__internal/include.h @@ -14,6 +14,8 @@ #ifndef LIBCDSB_SRC_INTERNAL_INCLUDE #define LIBCDSB_SRC_INTERNAL_INCLUDE +extern const size_t LIBCDSB_VTYPE_SIZES[19]; + #define is_x64 (sizeof(void*) == sizeof(vtype_uint64)) #define is_big_endian (*((unsigned int*)"\0\0\0\1") < (unsigned int)0xffff) #define is_little_endian (!is_big_endian) From 1b815613a42f57e0ea117968e2d954914864faf4 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:20:40 +0300 Subject: [PATCH 2/9] Refactor array base --- src/array/base.c | 31 ++++++++++++++--------- src/array/copy.c | 66 ++++++++++++++++++++---------------------------- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/src/array/base.c b/src/array/base.c index 49ee49f..f674b0c 100644 --- a/src/array/base.c +++ b/src/array/base.c @@ -4,6 +4,23 @@ #include "include.h" #include "../__internal/assert.h" +typedef void (*type_free)(void*); + +static inline type_free get_type_free(vtype type) { + switch (type) { + default: + #ifndef NDEBUG + abort(); + #endif + case VTYPE_STRING: return (void*)string_free; + case VTYPE_ARRAY: return (void*) array_free; + case VTYPE_LIST: return (void*) list_free; + case VTYPE_MAP: return (void*) map_free; + case VTYPE_SET: return (void*) vset_free; + case VTYPE_DICT: return (void*) dict_free; + } +} + /*#####################################################################################################################*/ hash_t array_hash(const arr_t* s) { @@ -29,21 +46,11 @@ void array_init(arr_t* x, vtype t) { void array_free(arr_t* x) { if (x->size && x->type >= VTYPE_STRING) { void* p = x->mem; - void (*free_)(void*); + type_free free_; assert(!is_null(p)); - switch (x->type) { - default: - #ifndef NDEBUG - abort(); - #endif - case VTYPE_STRING: free_ = (void*)string_free; break; - case VTYPE_ARRAY: free_ = (void*) array_free; break; - case VTYPE_LIST: free_ = (void*) list_free; break; - case VTYPE_MAP: free_ = (void*) map_free; break; - case VTYPE_SET: free_ = (void*) vset_free; break; - } + free_ = get_type_free(x->type); do { free_(p); diff --git a/src/array/copy.c b/src/array/copy.c index 967e74e..0100ce7 100644 --- a/src/array/copy.c +++ b/src/array/copy.c @@ -4,6 +4,22 @@ #include "include.h" #include "../__internal/assert.h" +typedef void (*type_initializer)(void*, const void*); + +static inline type_initializer get_type_initializer(vtype type) { + switch (type) { + default: + #ifndef NDEBUG + abort(); + #endif + case VTYPE_STRING: return (void*)string_copy_init; + case VTYPE_ARRAY: return (void*) array_copy_init; + case VTYPE_LIST: return (void*) list_copy_init; + case VTYPE_MAP: return (void*) map_copy_init; + case VTYPE_SET: return (void*) vset_copy_init; + case VTYPE_DICT: return (void*) dict_copy_init; + } +} arr_t array_copy(const arr_t* s) { arr_t x = { .mem = 0, .size = 0, .type = 0 }; @@ -14,19 +30,12 @@ arr_t array_copy(const arr_t* s) { if (s->type >= VTYPE_STRING) { void *p, *v, *e; - void (*init)(void*, const void*); + type_initializer init; x.mem = p = malloc(x.size*vtype_size(x.type)); v = s->mem; e = array_end(&x); - - switch (s->type) { default: abort(); - case VTYPE_STRING: init = (void*)string_copy_init; break; - case VTYPE_ARRAY: init = (void*) array_copy_init; break; - case VTYPE_LIST: init = (void*) list_copy_init; break; - case VTYPE_MAP: init = (void*) map_copy_init; break; - case VTYPE_SET: init = (void*) vset_copy_init; break; - } + init = get_type_initializer(s->type); do { init(p, v); @@ -50,19 +59,12 @@ arr_t* array_duplicate(const arr_t* s) { if (s->type >= VTYPE_STRING) { void *p, *v, *e; - void (*init)(void*, const void*); + type_initializer init; x->mem = p = malloc(x->size*vtype_size(x->type)); v = s->mem; e = array_end(x); - - switch (s->type) { default: abort(); - case VTYPE_STRING: init = (void*)string_copy_init; break; - case VTYPE_ARRAY: init = (void*) array_copy_init; break; - case VTYPE_LIST: init = (void*) list_copy_init; break; - case VTYPE_MAP: init = (void*) map_copy_init; break; - case VTYPE_SET: init = (void*) vset_copy_init; break; - } + init = get_type_initializer(s->type); do { init(p, v); @@ -84,19 +86,12 @@ void array_copy_init(arr_t* x, const arr_t* s) { if (s->type >= VTYPE_STRING) { void *p, *v, *e; - void (*init)(void*, const void*); + type_initializer init; x->mem = p = malloc(x->size*vtype_size(x->type)); v = s->mem; e = array_end(x); - - switch (s->type) { default: abort(); - case VTYPE_STRING: init = (void*)string_copy_init; break; - case VTYPE_ARRAY: init = (void*) array_copy_init; break; - case VTYPE_LIST: init = (void*) list_copy_init; break; - case VTYPE_MAP: init = (void*) map_copy_init; break; - case VTYPE_SET: init = (void*) vset_copy_init; break; - } + init = get_type_initializer(s->type); do { init(p, v); @@ -125,19 +120,12 @@ size_t array_slice(arr_t* x, arr_t* s, ssize_t i, size_t n, _Bool cut) { if (!cut && s->type >= VTYPE_STRING) { void *p, *v, *e; - void (*init)(void*, const void*); + type_initializer init; - p = x->mem; - v = array_internal_at(s, i); - e = array_internal_at(x, n); - - switch (s->type) { default: abort(); - case VTYPE_STRING: init = (void*)string_copy_init; break; - case VTYPE_ARRAY: init = (void*) array_copy_init; break; - case VTYPE_LIST: init = (void*) list_copy_init; break; - case VTYPE_MAP: init = (void*) map_copy_init; break; - case VTYPE_SET: init = (void*) vset_copy_init; break; - } + p = x->mem; + v = array_internal_at(s, i); + e = array_internal_at(x, n); + init = get_type_initializer(s->type); do { init(p, v); From ee987964a1223b5066dbd3b1ff66b9daf67ed2e9 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:21:01 +0300 Subject: [PATCH 3/9] Update dict symbols --- src/dict/extra.c | 2 +- src/dict/generics.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/dict/extra.c b/src/dict/extra.c index 5b4aba5..49b914a 100644 --- a/src/dict/extra.c +++ b/src/dict/extra.c @@ -149,7 +149,7 @@ bool libcdsb_dict_update(dict_t* x, const void* k, vtype kt, const void* v, vtyp } -int libcdsb_dict_get(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* _, dict_access_callback callback, bool cut) { dnode_t *c; void* key; diff --git a/src/dict/generics.c b/src/dict/generics.c index 1c8ea7d..41ab6b0 100644 --- a/src/dict/generics.c +++ b/src/dict/generics.c @@ -3,26 +3,26 @@ #include "include.h" -int libcdsb_dict_get_by_pointer(dict_t* x, const void* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_cstring(dict_t* x, const char* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_string (dict_t* x, const str_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_array (dict_t* x, const arr_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_list (dict_t* x, const list_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_map (dict_t* x, const map_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_vset (dict_t* x, const set_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_dict (dict_t* x, const dict_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, k, vtypeof( k), _, cb, cut); } -int libcdsb_dict_get_by_boolean(dict_t* x, bool k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_int8 (dict_t* x, s8_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_int16 (dict_t* x, s16_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_int32 (dict_t* x, s32_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_int64 (dict_t* x, s64_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_uint8 (dict_t* x, u8_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_uint16 (dict_t* x, u16_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_uint32 (dict_t* x, u32_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_uint64 (dict_t* x, u64_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_float (dict_t* x, fl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_double (dict_t* x, dbl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } -int libcdsb_dict_get_by_ldouble(dict_t* x, ldbl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_get(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_pointer(dict_t* x, const void* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_cstring(dict_t* x, const char* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_string (dict_t* x, const str_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_array (dict_t* x, const arr_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_list (dict_t* x, const list_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_map (dict_t* x, const map_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_vset (dict_t* x, const set_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_dict (dict_t* x, const dict_t* k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, k, vtypeof( k), _, cb, cut); } +int libcdsb_dict_find_by_boolean(dict_t* x, bool k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_int8 (dict_t* x, s8_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_int16 (dict_t* x, s16_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_int32 (dict_t* x, s32_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_int64 (dict_t* x, s64_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_uint8 (dict_t* x, u8_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_uint16 (dict_t* x, u16_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_uint32 (dict_t* x, u32_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_uint64 (dict_t* x, u64_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_float (dict_t* x, fl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_double (dict_t* x, dbl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } +int libcdsb_dict_find_by_ldouble(dict_t* x, ldbl_t k, void* _, dict_access_callback cb, bool cut) { return libcdsb_dict_find(x, &k, vtypeof(&k), _, cb, cut); } bool libcdsb_dict_update_pointer_pointer(dict_t* x, const void* k, const void* v) { return libcdsb_dict_update(x, &k, vtypeof(&k), &v, vtypeof(&v)); } bool libcdsb_dict_update_pointer_cstring(dict_t* x, const void* k, const char* v) { return libcdsb_dict_update(x, &k, vtypeof(&k), &v, vtypeof(&v)); } From 21e5c0fd8c8ed2177dc7f1ab5b716c668c9eee05 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:21:35 +0300 Subject: [PATCH 4/9] Fix string methods --- src/string/extra.c | 2 ++ src/string/get.c | 27 +++++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/string/extra.c b/src/string/extra.c index 50600f2..6a8d0f0 100644 --- a/src/string/extra.c +++ b/src/string/extra.c @@ -200,6 +200,8 @@ size_t string_reverse(str_t* x) { p = memcpy(p - cs, v, cs); v += cs; } else *(--p) = *(v++); + + ++n; } free(x->buffer); diff --git a/src/string/get.c b/src/string/get.c index 5493471..4f2cac5 100644 --- a/src/string/get.c +++ b/src/string/get.c @@ -32,31 +32,34 @@ char* string_at(const str_t* s, ssize_t i) { } -bool string_slice(str_t* x, str_t* s, ssize_t i, size_t c, bool cut) { +size_t string_slice(str_t* x, str_t* s, ssize_t i, size_t c, bool cut) { char *e, *p, *v; + size_t n = 0; memset(x, 0, sizeof(*x)); - if (!c) return true; + if (!c) return n; p = string_at(s, i); - if (is_null(p) || (e = p + strlen(p)) > p + c) - return false; + if (is_null(p)) + return n; + e = p + strlen(p); v = p; - do { v = next_char(v); } while (--c && v < e); + while (c-- && v < e) { + v = next_char(v); + ++n; + } - if (!c) { - x->buffer = strndup(p, v - p); + x->buffer = strndup(p, v - p); - if (cut) { - memmove(p, v, strlen(v) + 1); - } + if (cut) { + memmove(p, v, strlen(v) + 1); + } - return true; - } else return false; + return n; } From 209745f525d32b9e479ca3390111593b3055deb4 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:21:56 +0300 Subject: [PATCH 5/9] Update tests --- tests/src/dict/src/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/dict/src/random.c b/tests/src/dict/src/random.c index 0218398..1149260 100644 --- a/tests/src/dict/src/random.c +++ b/tests/src/dict/src/random.c @@ -9,7 +9,7 @@ static int remove_callback(const void* k, vtype kt, void* v, vtype vt, void* _) if (!d->n--) { print_container_value(0, k, kt, 0, d->hp); - if (libcdsb_dict_get(d->x, k, kt, 0, 0, 1) == 0) { + if (libcdsb_dict_find(d->x, k, kt, 0, 0, 1) == 0) { printf("\e[%dG\e[32;1mSUCCESS\e[m\n", d->hp+1); } else printf("\e[%dG\e[31;1mFAILURE\e[m\n", d->hp+1); From 862e85145c8e7b61b0125a2afe078c4c33a09fcc Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Wed, 17 Aug 2022 22:22:30 +0300 Subject: [PATCH 6/9] Minor project core fixes --- src/extra-memory.c | 5 +++++ src/extra-stack.c | 1 + src/vtype-extra.c | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/extra-memory.c b/src/extra-memory.c index 0ff5783..afeeb49 100644 --- a/src/extra-memory.c +++ b/src/extra-memory.c @@ -8,6 +8,7 @@ #undef malloc #undef realloc #undef calloc +#undef free void* libcdsb_aalloc(size_t a, size_t n) { void* x; @@ -73,3 +74,7 @@ char* libcdsb_strndup(const char* s, size_t n) { } abort(); } + +void libcdsb_free(void* s) { + free(s); +} diff --git a/src/extra-stack.c b/src/extra-stack.c index 3a32bdf..f78fdb0 100644 --- a/src/extra-stack.c +++ b/src/extra-stack.c @@ -4,6 +4,7 @@ #include #include "__internal/include.h" #undef malloc +#undef free void libcdsb_stack_init(stack_t* x) { memset(x, 0, sizeof(*x)); diff --git a/src/vtype-extra.c b/src/vtype-extra.c index 244f90b..80f1bfc 100644 --- a/src/vtype-extra.c +++ b/src/vtype-extra.c @@ -26,13 +26,13 @@ static _Thread_local char STRINGIFY_BUFFER[64]; /*#####################################################################################################################*/ -const size_t LIBCDSB_VTYPE_SIZES[18] = { +const size_t LIBCDSB_VTYPE_SIZES[19] = { sizeof(void*), sizeof(bool), sizeof(u8_t), sizeof(u16_t), sizeof(u32_t), sizeof(u64_t), sizeof(s8_t), sizeof(s16_t), sizeof(s32_t), sizeof(s64_t), sizeof(fl_t), sizeof(dbl_t), sizeof(ldbl_t), sizeof(str_t), sizeof(map_t), sizeof(arr_t), - sizeof(list_t), sizeof(set_t) + sizeof(list_t), sizeof(set_t), sizeof(dict_t) }; From 3cbf7a6fdff8f9a6e46f42e5edf8e3562ef459da Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Thu, 18 Aug 2022 00:08:10 +0300 Subject: [PATCH 7/9] Add stack_push_many method --- include/extra/memory.h | 18 ++++++++++-------- src/extra-stack.c | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/include/extra/memory.h b/include/extra/memory.h index e27f73b..e5a595e 100644 --- a/include/extra/memory.h +++ b/include/extra/memory.h @@ -12,10 +12,11 @@ typedef struct libcdsb_stack_node { void* value; } stack_t; -extern void libcdsb_stack_init (stack_t* stack) Nonnull__(1); -extern void libcdsb_stack_push (stack_t* stack, void* value) Nonnull__(1); -extern void* libcdsb_stack_pop (stack_t* stack) Nonnull__(1); -extern void libcdsb_stack_flush(stack_t* stack) Nonnull__(1); +extern void libcdsb_stack_init (stack_t* stack) Nonnull__(1); +extern void libcdsb_stack_push (stack_t* stack, void* value) Nonnull__(1); +extern void libcdsb_stack_push_many(stack_t* stack, size_t n, ...) Nonnull__(1); +extern void* libcdsb_stack_pop (stack_t* stack) Nonnull__(1); +extern void libcdsb_stack_flush (stack_t* stack) Nonnull__(1); extern void* libcdsb_aalloc (size_t a, size_t n) Warn_unused_result__; extern void* libcdsb_malloc (size_t n) Warn_unused_result__; @@ -30,9 +31,10 @@ extern void libcdsb_free(void* s); #define realloc libcdsb_realloc #define free libcdsb_free -#define stack_init libcdsb_stack_init -#define stack_push libcdsb_stack_push -#define stack_pop libcdsb_stack_pop -#define stack_flush libcdsb_stack_flush +#define stack_init libcdsb_stack_init +#define stack_push libcdsb_stack_push +#define stack_push_many libcdsb_stack_push_many +#define stack_pop libcdsb_stack_pop +#define stack_flush libcdsb_stack_flush #endif /* LIBCDSB_EXTRA_MEMORY_H */ diff --git a/src/extra-stack.c b/src/extra-stack.c index f78fdb0..563a177 100644 --- a/src/extra-stack.c +++ b/src/extra-stack.c @@ -1,6 +1,7 @@ /* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ +#include #include #include "__internal/include.h" #undef malloc @@ -26,6 +27,31 @@ void libcdsb_stack_push(stack_t* x, void* value) { x->value = value; } +void libcdsb_stack_push_many(stack_t* x, size_t c, ...) { + + va_list args; + stack_t* n; + va_start(args, c); + + if (c) { + if (!x->value) { + x->value = va_arg(args, void*); + --c; + } + + while (c--) { + if (!(n = malloc(sizeof(*n)))) + abort(); + + n->prev = x->prev; + n->value = x->value; + x->prev = n; + } + } + + va_end(args); +} + void* libcdsb_stack_pop(stack_t* x) { stack_t* n; From 72770c35612b91a99687a800b241c922d643197e Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Thu, 18 Aug 2022 00:15:54 +0300 Subject: [PATCH 8/9] Rollback excess abstractions for rbtree's types --- src/__internal/rbtree.h | 13 --- src/map/base.c | 177 +++++++++++++++++++++++----------- src/map/copy.c | 113 ++++++++++++++++++++++ src/map/extra.c | 12 ++- src/map/include.h | 4 - src/rbtree-extra.c | 206 ---------------------------------------- src/set/base.c | 160 ++++++++++++++++++++++++------- src/set/copy.c | 97 +++++++++++++++++++ 8 files changed, 468 insertions(+), 314 deletions(-) create mode 100644 src/map/copy.c delete mode 100644 src/rbtree-extra.c create mode 100644 src/set/copy.c diff --git a/src/__internal/rbtree.h b/src/__internal/rbtree.h index 8564bc1..01a5c10 100644 --- a/src/__internal/rbtree.h +++ b/src/__internal/rbtree.h @@ -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 */ diff --git a/src/map/base.c b/src/map/base.c index de82733..026f180 100644 --- a/src/map/base.c +++ b/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; } diff --git a/src/map/copy.c b/src/map/copy.c new file mode 100644 index 0000000..7a3948f --- /dev/null +++ b/src/map/copy.c @@ -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; +} diff --git a/src/map/extra.c b/src/map/extra.c index 5f28450..b587b17 100644 --- a/src/map/extra.c +++ b/src/map/extra.c @@ -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); diff --git a/src/map/include.h b/src/map/include.h index 59f1c5b..fe07b6b 100644 --- a/src/map/include.h +++ b/src/map/include.h @@ -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 */ diff --git a/src/rbtree-extra.c b/src/rbtree-extra.c deleted file mode 100644 index 40b2821..0000000 --- a/src/rbtree-extra.c +++ /dev/null @@ -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; - } - } -} diff --git a/src/set/base.c b/src/set/base.c index 17d5427..f10f02b 100644 --- a/src/set/base.c +++ b/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; } diff --git a/src/set/copy.c b/src/set/copy.c new file mode 100644 index 0000000..a074b0b --- /dev/null +++ b/src/set/copy.c @@ -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; +} From b2fa470bce98f4aa7106029cc623c63e35e0e195 Mon Sep 17 00:00:00 2001 From: Gregory Lirent Date: Thu, 18 Aug 2022 02:27:26 +0300 Subject: [PATCH 9/9] 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 */