diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-07-11 07:18:37 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-07-11 15:49:14 +0200 |
commit | d5b25f942147b09511d77d5470cd38a1e1643fb9 (patch) | |
tree | 40542b06a966366e2e8a3a0118e756874a838ce6 /types.c | |
parent | cc4ce8dfd13e833702c949e56049443cd01c0dfb (diff) |
treewide: harmonize function naming
- Ensure that most functions follow the subject_verb naming schema
- Move type related function from value.c to types.c
- Rename value.c to vallist.c
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'types.c')
-rw-r--r-- | types.c | 294 |
1 files changed, 291 insertions, 3 deletions
@@ -20,6 +20,7 @@ #include <endian.h> #include <errno.h> #include <math.h> +#include <ctype.h> #include "ucode/types.h" #include "ucode/util.h" @@ -1658,8 +1659,80 @@ ucv_to_jsonstring_formatted(uc_vm_t *vm, uc_value_t *uv, char pad_char, size_t p return ucv_to_string_any(vm, uv, pad_char ? pad_char : '\1', pad_size); } +uc_type_t +ucv_cast_number(uc_value_t *v, int64_t *n, double *d) +{ + bool is_double = false; + const char *s; + char *e; + + *d = 0.0; + *n = 0; + + switch (ucv_type(v)) { + case UC_INTEGER: + *n = ucv_int64_get(v); + + return UC_INTEGER; + + case UC_DOUBLE: + *d = ucv_double_get(v); + + return UC_DOUBLE; + + case UC_NULL: + return UC_INTEGER; + + case UC_BOOLEAN: + *n = ucv_boolean_get(v); + + return UC_INTEGER; + + case UC_STRING: + s = ucv_string_get(v); + + while (isspace(*s)) + s++; + + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X') && isxdigit(s[2])) { + *n = strtoll(s, &e, 16); + } + else if (s[0] == '0' && isdigit(s[2])) { + *n = strtoll(s, &e, 8); + } + else { + *n = strtoll(s, &e, 10); + + if (*e == '.') { + *d = strtod(s, &e); + is_double = (e > s); + } + } + + while (isspace(*e)) + e++; + + if (*e) { + *d = NAN; + + return UC_DOUBLE; + } + + if (is_double) + return UC_DOUBLE; + + return UC_INTEGER; + + default: + *d = NAN; + + return UC_DOUBLE; + } +} + + bool -ucv_equal(uc_value_t *uv1, uc_value_t *uv2) +ucv_is_equal(uc_value_t *uv1, uc_value_t *uv2) { uc_type_t t1 = ucv_type(uv1); uc_type_t t2 = ucv_type(uv2); @@ -1724,7 +1797,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2) return false; for (u1 = 0; u1 < u2; u1++) - if (!ucv_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1))) + if (!ucv_is_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1))) return false; return true; @@ -1737,7 +1810,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2) return false; ucv_object_foreach(uv1, key, val) { - if (!ucv_equal(val, ucv_object_get(uv2, key, NULL))) + if (!ucv_is_equal(val, ucv_object_get(uv2, key, NULL))) return false; } @@ -1756,6 +1829,221 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2) } } +bool +ucv_is_truish(uc_value_t *val) +{ + double d; + + switch (ucv_type(val)) { + case UC_INTEGER: + if (ucv_is_u64(val)) + return (ucv_uint64_get(val) != 0); + + return (ucv_int64_get(val) != 0); + + case UC_DOUBLE: + d = ucv_double_get(val); + + return (d != 0 && !isnan(d)); + + case UC_BOOLEAN: + return ucv_boolean_get(val); + + case UC_STRING: + return (ucv_string_length(val) > 0); + + case UC_NULL: + return false; + + default: + return true; + } +} + + +bool +ucv_compare(int how, uc_value_t *v1, uc_value_t *v2) +{ + uc_type_t t1 = ucv_type(v1); + uc_type_t t2 = ucv_type(v2); + int64_t n1, n2, delta; + double d1, d2; + + if (t1 == UC_STRING && t2 == UC_STRING) { + delta = strcmp(ucv_string_get(v1), ucv_string_get(v2)); + } + else { + if (t1 == t2 && !ucv_is_scalar(v1)) { + delta = (intptr_t)v1 - (intptr_t)v2; + } + else { + t1 = ucv_cast_number(v1, &n1, &d1); + t2 = ucv_cast_number(v2, &n2, &d2); + + if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) { + d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1; + d2 = (t2 == UC_DOUBLE) ? d2 : (double)n2; + + /* all comparison results except `!=` involving NaN are false */ + if (isnan(d1) || isnan(d2)) + return (how == I_NE); + + if (d1 == d2) + delta = 0; + else if (d1 < d2) + delta = -1; + else + delta = 1; + } + else { + delta = n1 - n2; + } + } + } + + switch (how) { + case I_LT: + return (delta < 0); + + case I_LE: + return (delta <= 0); + + case I_GT: + return (delta > 0); + + case I_GE: + return (delta >= 0); + + case I_EQ: + return (delta == 0); + + case I_NE: + return (delta != 0); + + default: + return false; + } +} + + +static char * +ucv_key_to_string(uc_vm_t *vm, uc_value_t *val) +{ + if (ucv_type(val) != UC_STRING) + return ucv_to_string(vm, val); + + return NULL; +} + +static int64_t +ucv_key_to_index(uc_value_t *val) +{ + const char *k; + int64_t idx; + double d; + char *e; + + /* only consider doubles with integer values as array keys */ + if (ucv_type(val) == UC_DOUBLE) { + d = ucv_double_get(val); + + if ((double)(int64_t)(d) != d) + return -1; + + return (int64_t)d; + } + else if (ucv_type(val) == UC_INTEGER) { + return ucv_int64_get(val); + } + else if (ucv_type(val) == UC_STRING) { + errno = 0; + k = ucv_string_get(val); + idx = strtoll(k, &e, 0); + + if (errno != 0 || e == k || *e != 0) + return -1; + + return idx; + } + + return -1; +} + +uc_value_t * +ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key) +{ + uc_value_t *o, *v = NULL; + int64_t idx; + bool found; + char *k; + + if (ucv_type(scope) == UC_ARRAY) { + idx = ucv_key_to_index(key); + + if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) + return ucv_get(ucv_array_get(scope, idx)); + } + + k = ucv_key_to_string(vm, key); + + for (o = scope; o; o = ucv_prototype_get(o)) { + if (ucv_type(o) != UC_OBJECT) + continue; + + v = ucv_object_get(o, k ? k : ucv_string_get(key), &found); + + if (found) + break; + } + + free(k); + + return ucv_get(v); +} + +uc_value_t * +ucv_key_set(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key, uc_value_t *val) +{ + int64_t idx; + char *s; + bool rv; + + if (!key) + return NULL; + + if (ucv_type(scope) == UC_ARRAY) { + idx = ucv_key_to_index(key); + + if (idx < 0 || !ucv_array_set(scope, idx, val)) + return NULL; + + return ucv_get(val); + } + + s = ucv_key_to_string(vm, key); + rv = ucv_object_add(scope, s ? s : ucv_string_get(key), val); + free(s); + + return rv ? ucv_get(val) : NULL; +} + +bool +ucv_key_delete(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key) +{ + char *s; + bool rv; + + if (!key) + return NULL; + + s = ucv_key_to_string(vm, key); + rv = ucv_object_delete(scope, s ? s : ucv_string_get(key)); + free(s); + + return rv; +} + + static void ucv_gc_common(uc_vm_t *vm, bool final) { |