diff --git a/include/extra/list.h b/include/extra/list.h index 6fc62e5..d62b3eb 100644 --- a/include/extra/list.h +++ b/include/extra/list.h @@ -18,4 +18,6 @@ extern size_t libcdsb_list_count(const vtype_list* s, const void* value, vtype extern ssize_t libcdsb_list_get(vtype_value* x, vtype_list* s, ssize_t index, _Bool cut); +extern int list_foreach(const vtype_list* x, int (*callback)(void* value, ssize_t index, vtype type)); + #endif /* LIBCDSB_EXTRA_LIST_H */ diff --git a/src/__internal/include.h b/src/__internal/include.h index 25d00e9..285e510 100644 --- a/src/__internal/include.h +++ b/src/__internal/include.h @@ -1,6 +1,8 @@ /* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ +#include +#include #include #include @@ -32,6 +34,8 @@ #define true ((_Bool)1) #define false ((_Bool)0) +#define abs(v) _Generic((v), ldbl_t: fabsl, dbl_t: fabs, fl_t: fabsf)(v) + #include "__attributes.h" typedef vtype_uint8 u8_t; diff --git a/src/list/base.c b/src/list/base.c index 90adb5e..16260f1 100644 --- a/src/list/base.c +++ b/src/list/base.c @@ -17,7 +17,7 @@ void list_free(list_t* x) { while (!is_null(c)) { next = c->next; - vnode_free(c->node, c->type); + vnode_free(&c->node, c->type); free(c); c = next; } diff --git a/src/list/extra.c b/src/list/extra.c index 6514860..a9941ac 100644 --- a/src/list/extra.c +++ b/src/list/extra.c @@ -28,7 +28,6 @@ ssize_t libcdsb_list_get(val_t* x, list_t* s, ssize_t i, _Bool cut) { ldir_t dir; lnode_t* c; size_t n; - int cmp; if (i < 0) { n = (i = ~i); @@ -137,18 +136,18 @@ _Bool libcdsb_list_update(list_t* x, ssize_t i, const void* v, vtype t, int ins) if (is_null(c)) { x->first = x->last = c = calloc(sizeof(*c), 1); } else if (ins) { - lnode_t *x = malloc(sizeof(*x)); + lnode_t *v = malloc(sizeof(*v)); dir = (ins < 0) ? LD_PREV : LD_NEXT; - ldir_dir(x, dir) = ldir_dir(c, dir); - ldir_inv(x, dir) = c; + ldir_dir(v, dir) = ldir_dir(c, dir); + ldir_inv(v, dir) = c; - c = x; + c = v; if (!is_null(ldir_dir(c, dir))) { ldir_inv(ldir_dir(c, dir), dir) = c; - } + } else ldir_inv((lnode_t*)x, dir) = c; ldir_dir(ldir_inv(c, dir), dir) = c; @@ -159,3 +158,26 @@ _Bool libcdsb_list_update(list_t* x, ssize_t i, const void* v, vtype t, int ins) return true; } + + +/*#####################################################################################################################*/ + + +int list_foreach(const vtype_list* x, int (*callback)(void* value, ssize_t index, vtype type)) { + + lnode_t* c; + size_t n; + int r; + + c = x->first; + n = 0; + + while (!is_null(c)) { + if ((r = callback(vnode_peek(&c->node, c->type), n, c->type)) != 0) + return r; + c = c->next; + ++n; + } + + return 0; +} diff --git a/src/list/include.h b/src/list/include.h index e88d623..402b952 100644 --- a/src/list/include.h +++ b/src/list/include.h @@ -23,6 +23,6 @@ typedef struct libcdsb_list_node { #define ldir_dir(cur, d) (&((cur)->prev))[(d)>>1] #define ldir_inv(cur, d) (&((cur)->prev))[(d)&1] -#define lnode_compare(s0, s1) vnode_compare((s0)->node, (s0)->type, (s1)->node, (s1)->type) +#define lnode_compare(s0, s1) vnode_compare(&(s0)->node, (s0)->type, &(s1)->node, (s1)->type) #endif /* LIBCDSB_SRC_LIST_INCLUDE_H */ diff --git a/src/list/sort.c b/src/list/sort.c index b4623d9..9162654 100644 --- a/src/list/sort.c +++ b/src/list/sort.c @@ -16,78 +16,38 @@ static inline void lnode_swap(lnode_t* s0, lnode_t* s1) { s1->type = t; } -static inline lnode_t* mid(lnode_t* l, lnode_t *r) { - while (l != r) { - if ((r = r->prev) == l) - break; - l = l->next; - } - - return l; -} - static inline lnode_t* pivot(lnode_t *l, lnode_t *r) { - lnode_t *m = mid(l, r); + lnode_t *c = l->prev; - if (lnode_compare(m, l) < 0) - lnode_swap(m, l); - - if (lnode_compare(m, r) > 0) { - lnode_swap(m, r); - - if (lnode_compare(m, l) < 0) - lnode_swap(m, l); + for (lnode_t* i = l; i != r; i = i->next) { + if (lnode_compare(i, r) < 0) { + c = (is_null(c)) ? l : c->next; + lnode_swap(c, i); + } } - return m; + c = (is_null(c)) ? l : c->next; + lnode_swap(c, r); + + return c; } -/*#####################################################################################################################*/ +static void quick_sort(lnode_t* l, lnode_t* r) { + lnode_t* p; -static void quick_sort(lnode_t *l, lnode_t *r) { + if (!is_null(r) && l != r && l != r->next) { + p = pivot(l, r); - lnode_t *c; - lnode_t *m = pivot(l, r); - lnode_t *n = l; - lnode_t *p = r; - int f = 0; - - for (;;) { - while (lnode_compare(l, m) < 0) { - l = l->next; - if (p == l) /* l >= p */ - f |= 0x01; - } - - c = l->prev; - - while (lnode_compare(r, m) > 0) { - r = r->prev; - if (n == r) /* n >= r */ - f |= 0x02; - if (c == r) /* l > r */ - f |= 0x04; - } - - if (!(f&0x04)) { /* l <= r */ - lnode_swap(l, r); - l = l->next; - r = r->prev;; - } else break; + quick_sort(l, p->prev); + quick_sort(p->next, r); } - - if (!(f&0x02)) /* n < r */ - quick_sort(n, r); - if (!(f&0x01)) /* l < p */ - quick_sort(l, p); } /*#####################################################################################################################*/ void list_sort(list_t* x) { - if (x->first != x->last) - return quick_sort(x->first, x->last);; + return quick_sort(x->first, x->last); } diff --git a/src/vtype-extra.c b/src/vtype-extra.c index 94d827d..8f86f91 100644 --- a/src/vtype-extra.c +++ b/src/vtype-extra.c @@ -1,7 +1,6 @@ /* This software is licensed by the MIT License, see LICENSE file */ /* Copyright © 2022 Gregory Lirent */ -#include #include #include "__internal/include.h" @@ -16,9 +15,9 @@ unsigned int: "%u", signed int: "%d",\ unsigned long: "%lu", signed long: "%ld",\ unsigned long long: "%llu", signed long long: "%lld",\ - float: "%."s__(FLT_DECIMAL_DIG)"g",\ + float: "%."s__(FLT_DIG)"g",\ double: "%."s__(DBL_DIG)"lg",\ - long double: "%."s__(DBL_DECIMAL_DIG)"Lg") + long double: "%."s__(LDBL_DIG)"Lg") #define stringify(v) sprintf(STRINGIFY_BUFFER, fstring(v), (v)) @@ -78,10 +77,21 @@ const char* libcdsb_vtype_stringify(const void* v, vtype t) { case VTYPE_UINT16: stringify(*( u16_t*)v); break; case VTYPE_UINT32: stringify(*( u32_t*)v); break; case VTYPE_UINT64: stringify(*( u64_t*)v); break; - case VTYPE_FLOAT: stringify(*( fl_t*)v); break; - case VTYPE_DOUBLE: stringify(*( dbl_t*)v); break; - case VTYPE_LDOUBLE: stringify(*(ldbl_t*)v); break; - + case VTYPE_FLOAT: if (abs(*(fl_t*)v) <= FLT_EPSILON) { + STRINGIFY_BUFFER[0] = 0x30; + STRINGIFY_BUFFER[1] = 0x00; + } else stringify(*(fl_t*)v); + break; + case VTYPE_DOUBLE: if (abs(*(dbl_t*)v) <= DBL_EPSILON) { + STRINGIFY_BUFFER[0] = 0x30; + STRINGIFY_BUFFER[1] = 0x00; + } else stringify(*(dbl_t*)v); + break; + case VTYPE_LDOUBLE: if (abs(*(ldbl_t*)v) <= LDBL_EPSILON) { + STRINGIFY_BUFFER[0] = 0x30; + STRINGIFY_BUFFER[1] = 0x00; + } else stringify(*(ldbl_t*)v); + break; case VTYPE_POINTER: sprintf(STRINGIFY_BUFFER, (sizeof(void*) == 8) ? "0x%016lx" : "0x%08x", (uintptr_t)*(void**)v); break; default: sprintf(STRINGIFY_BUFFER, "<%s>", libcdsb_vtype_name(t)); diff --git a/src/vtype.c b/src/vtype.c index d7b6a9f..266ecda 100644 --- a/src/vtype.c +++ b/src/vtype.c @@ -4,73 +4,45 @@ #include "__internal/assert.h" #include "__internal/include.h" -#define max_align _Alignof(max_align_t) -#define max_size ((sizeof(ldbl_t) >= 8) ? sizeof(ldbl_t) : 8) - /*#####################################################################################################################*/ -static vtype normalize_value(u64_t* d, const void* v, vtype t) { +static ldbl_t normalize_value(const void* v, vtype t) { if (t == VTYPE_BOOLEAN || t == VTYPE_UINT8) { - *d = *(u8_t*)v; - t = VTYPE_UINT64; + return *(u8_t*)v; } else if (t == VTYPE_UINT16) { - *d = *(u16_t*)v; - t = VTYPE_UINT64; + return *(u16_t*)v; } else if (t == VTYPE_UINT32 || (sizeof(void*) == 4 && t == VTYPE_POINTER)) { - *d = *(u32_t*)v; - t = VTYPE_UINT64; + return *(u32_t*)v; } else if (t == VTYPE_UINT64 || (sizeof(void*) == 8 && t == VTYPE_POINTER)) { - *d = *(u64_t*)v; - t = VTYPE_UINT64; + return *(u64_t*)v; } else if (t == VTYPE_INT8) { - *d = *(s8_t*)v; - t = (*(s8_t*)v >= 0) ? VTYPE_UINT64 : VTYPE_INT64; + return *(s8_t*)v; } else if (t == VTYPE_INT16) { - *d = *(s16_t*)v; - t = (*(s16_t*)v >= 0) ? VTYPE_UINT64 : VTYPE_INT64; + return *(s16_t*)v; } else if (t == VTYPE_INT32) { - *d = *(s32_t*)v; - t = (*(s32_t*)v >= 0) ? VTYPE_UINT64 : VTYPE_INT64; + return *(s32_t*)v; } else if (t == VTYPE_INT64) { - *d = *(s64_t*)v; - t = (*(s64_t*)v >= 0) ? VTYPE_UINT64 : VTYPE_INT64; - } - - return t; + return *(s64_t*)v; + } else if (t == VTYPE_FLOAT) { + return abs(*(fl_t*)v) <= FLT_EPSILON ? 0 : *(fl_t*)v; + } else if (t == VTYPE_DOUBLE) { + return abs(*(dbl_t*)v) <= DBL_EPSILON ? 0 : *(dbl_t*)v; + } else return abs(*(ldbl_t*)v) <= LDBL_EPSILON ? 0 : *(ldbl_t*)v; } int libcdsb_vtype_compare_values(const void* s0, vtype t0, const void* s1, vtype t1) { if (t0 == t1) return libcdsb_vtype_compare_values_eq(s0, s1, t0); - if (is_integer(t0) && is_integer(t1)) { - u64_t v0, v1; + if (t0 <= VTYPE_LDOUBLE && t1 <= VTYPE_LDOUBLE) { + ldbl_t d0, d1; - t0 = normalize_value(&v0, s0, t0); - t1 = normalize_value(&v1, s1, t1); + d0 = normalize_value(s0, t0); + d1 = normalize_value(s1, t1); - if (t0 == t1) { - if (t0 > VTYPE_UINT64) - return (s64_t)v0 - (s64_t)v1; - return v0 - v1; - } + return (abs(d0 - d1) <= LDBL_EPSILON) ? 0 : (d0 < d1 ? -1 : 1); + } - return t1 - t0; - - } else if (is_float(t0) && is_float(t1)) { - ldbl_t v; - - if (t0 == VTYPE_FLOAT) v = *(fl_t*)s0; - else if (t0 == VTYPE_DOUBLE) v = *(dbl_t*)s0; - else v = *(ldbl_t*)s0; - - if (t1 == VTYPE_FLOAT) v -= *(fl_t*)s1; - else if (t1 == VTYPE_DOUBLE) v -= *(dbl_t*)s1; - else v -= *(ldbl_t*)s1; - - if (v < 0) return -1; - - return (v > 0) ? 1 : 0; - } else return t0 - t1; + return t0 - t1; } /*#####################################################################################################################*/ @@ -78,45 +50,30 @@ int libcdsb_vtype_compare_values(const void* s0, vtype t0, const void* s1, vtype int libcdsb_vtype_compare_values_eq(const void* s0, const void* s1, vtype t) { - ldbl_t v[1]; + #define compare(T, s0, s1) *(T*)s0 == *(T*)s1 ? 0 : (*(T*)s0 < *(T*)s1 ? -1 : 1) if (s0 == s1) return 0; switch (t) { default: abort(); - case VTYPE_INT8: return *(s8_t*)s0 - *(s8_t*)s1; - case VTYPE_INT16: return *(s16_t*)s0 - *(s16_t*)s1; - case VTYPE_INT32: return *(s32_t*)s0 - *(s32_t*)s1; - case VTYPE_INT64: return *(s64_t*)s0 - *(s64_t*)s1; + case VTYPE_INT8: return compare( s8_t, s0, s1); + case VTYPE_INT16: return compare(s16_t, s0, s1); + case VTYPE_INT32: return compare(s32_t, s0, s1); + case VTYPE_INT64: return compare(s64_t, s0, s1); case VTYPE_BOOLEAN: - case VTYPE_UINT8: return *(u8_t*)s0 - *(u8_t*)s1; - - case VTYPE_UINT16: return *(u16_t*)s0 - *(u16_t*)s1; + case VTYPE_UINT8: return compare( u8_t, s0, s1); + case VTYPE_UINT16: return compare(u16_t, s0, s1); case VTYPE_UINT32: - u32_: return *(u32_t*)s0 - *(u32_t*)s1; + u32_: return compare(u32_t, s0, s1); case VTYPE_POINTER: if (sizeof(void*) != 8) goto u32_; - case VTYPE_UINT64: return *(u64_t*)s0 - *(u64_t*)s1; + case VTYPE_UINT64: return compare(u64_t, s0, s1); - case VTYPE_LDOUBLE: *(ldbl_t*)v = *(ldbl_t*)s0 - *(ldbl_t*)s1; - - if (!*(ldbl_t*)v) - return 0; - return *(ldbl_t*)v < 0 ? -1 : 1; - - case VTYPE_DOUBLE: *(dbl_t*)v = *(dbl_t*)s0 - *(dbl_t*)s1; - - if (!*(dbl_t*)v) - return 0; - return *(dbl_t*)v < 0 ? -1 : 1; - - case VTYPE_FLOAT: *(fl_t*)v = *(fl_t*)s0 - *(fl_t*)s1; - - if (!*(fl_t*)v) - return 0; - return *(fl_t*)v < 0 ? -1 : 1; + case VTYPE_LDOUBLE: return (abs(*(ldbl_t*)s0 - *(ldbl_t*)s1) <= LDBL_EPSILON) ? 0 : (*(ldbl_t*)s0 < *(ldbl_t*)s1 ? -1 : 1); + case VTYPE_DOUBLE: return (abs(*( dbl_t*)s0 - *( dbl_t*)s1) <= DBL_EPSILON) ? 0 : (*( dbl_t*)s0 < *( dbl_t*)s1 ? -1 : 1); + case VTYPE_FLOAT: return (abs(*( fl_t*)s0 - *( fl_t*)s1) <= FLT_EPSILON) ? 0 : (*( fl_t*)s0 < *( fl_t*)s1 ? -1 : 1); case VTYPE_STRING: return string_compare(s0, s1); case VTYPE_ARRAY: return array_compare(s0, s1); @@ -124,4 +81,6 @@ int libcdsb_vtype_compare_values_eq(const void* s0, const void* s1, vtype t) { case VTYPE_MAP: return map_compare(s0, s1); case VTYPE_SET: return vset_compare(s0, s1); } + + #undef compare }