diff options
Diffstat (limited to 'stdlib')
| -rw-r--r-- | stdlib/arrays.c | 17 | ||||
| -rw-r--r-- | stdlib/arrays.h | 2 | ||||
| -rw-r--r-- | stdlib/bools.h | 7 | ||||
| -rw-r--r-- | stdlib/bytes.c | 23 | ||||
| -rw-r--r-- | stdlib/bytes.h | 18 | ||||
| -rw-r--r-- | stdlib/datatypes.h | 10 | ||||
| -rw-r--r-- | stdlib/integers.c | 27 | ||||
| -rw-r--r-- | stdlib/integers.h | 154 | ||||
| -rw-r--r-- | stdlib/moments.c | 17 | ||||
| -rw-r--r-- | stdlib/nums.c | 8 | ||||
| -rw-r--r-- | stdlib/nums.h | 81 | ||||
| -rw-r--r-- | stdlib/optionals.c | 1 | ||||
| -rw-r--r-- | stdlib/paths.c | 2 | ||||
| -rw-r--r-- | stdlib/patterns.c | 6 | ||||
| -rw-r--r-- | stdlib/rng.c | 2 | ||||
| -rw-r--r-- | stdlib/stdlib.c | 1 | ||||
| -rw-r--r-- | stdlib/text.c | 10 |
17 files changed, 240 insertions, 146 deletions
diff --git a/stdlib/arrays.c b/stdlib/arrays.c index 1f4b8252..41d46741 100644 --- a/stdlib/arrays.c +++ b/stdlib/arrays.c @@ -7,6 +7,7 @@ #include "arrays.h" #include "integers.h" +#include "math.h" #include "metamethods.h" #include "optionals.h" #include "rng.h" @@ -51,7 +52,7 @@ public void Array$compact(Array_t *arr, int64_t padded_item_size) public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_t padded_item_size) { - int64_t index = Int_to_Int64(int_index, false); + int64_t index = Int64$from_int(int_index, false); if (index <= 0) index = arr->length + index + 1; if (index < 1) index = 1; @@ -90,7 +91,7 @@ public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_ public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, int64_t padded_item_size) { - int64_t index = Int_to_Int64(int_index, false); + int64_t index = Int64$from_int(int_index, false); if (to_insert.length == 0) return; @@ -163,10 +164,10 @@ public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, i public void Array$remove_at(Array_t *arr, Int_t int_index, Int_t int_count, int64_t padded_item_size) { - int64_t index = Int_to_Int64(int_index, false); + int64_t index = Int64$from_int(int_index, false); if (index < 1) index = arr->length + index + 1; - int64_t count = Int_to_Int64(int_count, false); + int64_t count = Int64$from_int(int_count, false); if (index < 1 || index > (int64_t)arr->length || count < 1) return; if (count > arr->length - index + 1) @@ -297,7 +298,7 @@ public Table_t Array$counts(Array_t arr, const TypeInfo_t *type) public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, RNG_t rng, int64_t padded_item_size) { - int64_t n = Int_to_Int64(int_n, false); + int64_t n = Int64$from_int(int_n, false); if (n < 0) fail("Cannot select a negative number of values"); @@ -399,7 +400,7 @@ public Array_t Array$to(Array_t array, Int_t last) public Array_t Array$by(Array_t array, Int_t int_stride, int64_t padded_item_size) { - int64_t stride = Int_to_Int64(int_stride, false); + int64_t stride = Int64$from_int(int_stride, false); // In the unlikely event that the stride value would be too large to fit in // a 15-bit integer, fall back to creating a copy of the array: if (unlikely(array.stride*stride < ARRAY_MIN_STRIDE || array.stride*stride > ARRAY_MAX_STRIDE)) { @@ -434,11 +435,11 @@ public Array_t Array$by(Array_t array, Int_t int_stride, int64_t padded_item_siz public Array_t Array$slice(Array_t array, Int_t int_first, Int_t int_last) { - int64_t first = Int_to_Int64(int_first, false); + int64_t first = Int64$from_int(int_first, false); if (first < 0) first = array.length + first + 1; - int64_t last = Int_to_Int64(int_last, false); + int64_t last = Int64$from_int(int_last, false); if (last < 0) last = array.length + last + 1; diff --git a/stdlib/arrays.h b/stdlib/arrays.h index 53681dc7..0e75f0e5 100644 --- a/stdlib/arrays.h +++ b/stdlib/arrays.h @@ -69,7 +69,7 @@ void Array$remove_item(Array_t *arr, void *item, Int_t max_removals, const TypeI #define Array$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr, padded_item_size) ({ \ Array_t *arr = arr_expr; \ Int_t index = index_expr; \ - int64_t index64 = Int_to_Int64(index, false); \ + int64_t index64 = Int64$from_int(index, false); \ int64_t off = index64 + (index64 < 0) * (arr->length + 1) - 1; \ (off >= 0 && off < arr->length) ? ({ \ item_type nonnone_var = *(item_type*)(arr->data + off*arr->stride); \ diff --git a/stdlib/bools.h b/stdlib/bools.h index c1b344b8..6d0300d5 100644 --- a/stdlib/bools.h +++ b/stdlib/bools.h @@ -9,12 +9,17 @@ #include "optionals.h" #include "util.h" -#define Bool_t bool #define yes (Bool_t)true #define no (Bool_t)false PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type); OptionalBool_t Bool$parse(Text_t text); +MACROLIKE Bool_t Bool$from_int(Int_t i) { return (i.small != 0); } +MACROLIKE Bool_t Bool$from_int64(Int64_t i) { return (i != 0); } +MACROLIKE Bool_t Bool$from_int32(Int32_t i) { return (i != 0); } +MACROLIKE Bool_t Bool$from_int16(Int16_t i) { return (i != 0); } +MACROLIKE Bool_t Bool$from_int8(Int8_t i) { return (i != 0); } +MACROLIKE Bool_t Bool$from_byte(uint8_t b) { return (b != 0); } extern const TypeInfo_t Bool$info; diff --git a/stdlib/bytes.c b/stdlib/bytes.c index 1e889f6d..b24a721b 100644 --- a/stdlib/bytes.c +++ b/stdlib/bytes.c @@ -30,6 +30,29 @@ public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) { return text; } +public PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) { + if unlikely (truncate && Int$compare_value(i, I_small(0xFF)) > 0) + fail("This value is too large to convert to a byte without truncation: %k", (Text_t[1]){Int$value_as_text(i)}); + else if unlikely (truncate && Int$compare_value(i, I_small(0)) < 0) + fail("Negative values can't be converted to bytes: %k", (Text_t[1]){Int$value_as_text(i)}); + return (i.small != 0); +} +public PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) { + if unlikely (truncate && i != (Int64_t)(Byte_t)i) + fail("This value can't be converted to a byte without truncation: %ld", i); + return (Byte_t)i; +} +public PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) { + if unlikely (truncate && i != (Int32_t)(Byte_t)i) + fail("This value can't be converted to a byte without truncation: %d", i); + return (Byte_t)i; +} +public PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) { + if unlikely (truncate && i != (Int16_t)(Byte_t)i) + fail("This value can't be converted to a byte without truncation: %d", i); + return (Byte_t)i; +} + public const TypeInfo_t Byte$info = { .size=sizeof(Byte_t), .align=__alignof__(Byte_t), diff --git a/stdlib/bytes.h b/stdlib/bytes.h index 9bd4e1c2..ac1b61a3 100644 --- a/stdlib/bytes.h +++ b/stdlib/bytes.h @@ -5,23 +5,21 @@ #include <stdbool.h> #include <stdint.h> +#include "datatypes.h" +#include "stdlib.h" #include "types.h" #include "util.h" -#define Byte_t uint8_t #define Byte(b) ((Byte_t)(b)) PUREFUNC Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *type); -#define Byte_to_Int64(b, _) ((Int64_t)(b)) -#define Byte_to_Int32(b, _) ((Int32_t)(b)) -#define Byte_to_Int16(b, _) ((Int16_t)(b)) -#define Byte_to_Int8(b, _) ((Int8_t)(b)) - -#define Int64_to_Byte(b, _) ((Byte_t)(b)) -#define Int32_to_Byte(b, _) ((Byte_t)(b)) -#define Int16_to_Byte(b, _) ((Byte_t)(b)) -#define Int8_to_Byte(b, _) ((Byte_t)(b)) +Byte_t Byte$from_int(Int_t i, bool truncate); +Byte_t Byte$from_int64(int64_t i, bool truncate); +Byte_t Byte$from_int32(int32_t i, bool truncate); +Byte_t Byte$from_int16(int16_t i, bool truncate); +MACROLIKE Byte_t Byte$from_int8(int8_t i) { return (Byte_t)i; } +MACROLIKE Byte_t Byte$from_bool(bool b) { return (Byte_t)b; } extern const Byte_t Byte$min; extern const Byte_t Byte$max; diff --git a/stdlib/datatypes.h b/stdlib/datatypes.h index af37446a..e131239b 100644 --- a/stdlib/datatypes.h +++ b/stdlib/datatypes.h @@ -19,6 +19,16 @@ #define ARRAY_MAX_DATA_REFCOUNT MAX_FOR_N_BITS(ARRAY_REFCOUNT_BITS) #define ARRAY_MAX_FREE_ENTRIES MAX_FOR_N_BITS(ARRAY_FREE_BITS) +#define Num_t double +#define Num32_t float + +#define Int64_t int64_t +#define Int32_t int32_t +#define Int16_t int16_t +#define Int8_t int8_t +#define Byte_t uint8_t +#define Bool_t bool + typedef union { int64_t small; mpz_t *big; diff --git a/stdlib/integers.c b/stdlib/integers.c index c60f237d..dbacda9b 100644 --- a/stdlib/integers.c +++ b/stdlib/integers.c @@ -74,7 +74,7 @@ public PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t*) { } public Text_t Int$format(Int_t i, Int_t digits_int) { - int64_t digits = Int_to_Int64(digits_int, false); + int64_t digits = Int64$from_int(digits_int, false); if (likely(i.small & 1)) { return Text$format("%0.*ld", digits, (i.small)>>2); } else { @@ -97,7 +97,7 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) { if (Int$is_negative(i)) return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix)); - int64_t digits = Int_to_Int64(digits_int, false); + int64_t digits = Int64$from_int(digits_int, false); if (likely(i.small & 1)) { const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx"); return Text$format(hex_fmt, digits, (i.small)>>2); @@ -124,7 +124,7 @@ public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) { if (Int$is_negative(i)) return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix)); - int64_t digits = Int_to_Int64(digits_int, false); + int64_t digits = Int64$from_int(digits_int, false); if (likely(i.small & 1)) { const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo"; return Text$format(octal_fmt, digits, (i.small)>>2); @@ -221,7 +221,7 @@ public Int_t Int$slow_modulo1(Int_t x, Int_t modulus) public Int_t Int$slow_left_shifted(Int_t x, Int_t y) { - mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false); + mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false); mpz_t result; mpz_init_set_int(result, x); mpz_mul_2exp(result, result, bits); @@ -230,7 +230,7 @@ public Int_t Int$slow_left_shifted(Int_t x, Int_t y) public Int_t Int$slow_right_shifted(Int_t x, Int_t y) { - mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false); + mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false); mpz_t result; mpz_init_set_int(result, x); mpz_tdiv_q_2exp(result, result, bits); @@ -300,7 +300,7 @@ public Int_t Int$abs(Int_t x) public Int_t Int$power(Int_t base, Int_t exponent) { - int64_t exp = Int_to_Int64(exponent, false); + int64_t exp = Int64$from_int(exponent, false); if (unlikely(exp < 0)) fail("Cannot take a negative power of an integer!"); mpz_t result; @@ -397,7 +397,7 @@ public bool Int$is_prime(Int_t x, Int_t reps) mpz_init_set_int(p, x); if (unlikely(Int$compare_value(reps, I(9999)) > 0)) fail("Number of prime-test repetitions should not be above 9999"); - int reps_int = Int_to_Int32(reps, false); + int reps_int = Int32$from_int(reps, false); return (mpz_probab_prime_p(p, reps_int) != 0); } @@ -426,7 +426,7 @@ public Int_t Int$choose(Int_t n, Int_t k) mpz_t ret; mpz_init(ret); - int64_t k_i64 = Int_to_Int64(k, false); + int64_t k_i64 = Int64$from_int(k, false); if unlikely (k_i64 < 0) fail("Negative inputs are not supported for choose()"); @@ -444,7 +444,7 @@ public Int_t Int$factorial(Int_t n) { mpz_t ret; mpz_init(ret); - int64_t n_i64 = Int_to_Int64(n, false); + int64_t n_i64 = Int64$from_int(n, false); if unlikely (n_i64 < 0) fail("Factorials are not defined for negative numbers"); mpz_fac_ui(ret, (unsigned long)n_i64); @@ -556,15 +556,14 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t return *(c_type*)x == *(c_type*)y; \ } \ public Text_t KindOfInt ## $format(c_type i, Int_t digits_int) { \ - Int_t as_int = KindOfInt##_to_Int(i); \ - return Int$format(as_int, digits_int); \ + return Text$format("%0*ld", Int32$from_int(digits_int, false), i); \ } \ public Text_t KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \ - Int_t as_int = KindOfInt##_to_Int(i); \ + Int_t as_int = Int$from_int64((int64_t)i); \ return Int$hex(as_int, digits_int, uppercase, prefix); \ } \ public Text_t KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \ - Int_t as_int = KindOfInt##_to_Int(i); \ + Int_t as_int = Int$from_int64((int64_t)i); \ return Int$octal(as_int, digits_int, prefix); \ } \ public Array_t KindOfInt ## $bits(c_type x) { \ @@ -615,7 +614,7 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t if (Int$compare_value(full_int, I(max_val)) > 0) { \ return (Optional ## KindOfInt ## _t){.is_none=true}; \ } \ - return (Optional ## KindOfInt ## _t){.i=Int_to_ ## KindOfInt(full_int, true)}; \ + return (Optional ## KindOfInt ## _t){.i=KindOfInt##$from_int(full_int, true)}; \ } \ public CONSTFUNC c_type KindOfInt ## $gcd(c_type x, c_type y) { \ if (x == 0 || y == 0) return 0; \ diff --git a/stdlib/integers.h b/stdlib/integers.h index 7bed4551..c78cabf0 100644 --- a/stdlib/integers.h +++ b/stdlib/integers.h @@ -8,15 +8,10 @@ #include <gmp.h> #include "datatypes.h" -#include "nums.h" #include "stdlib.h" #include "types.h" #include "util.h" -#define Int64_t int64_t -#define Int32_t int32_t -#define Int16_t int16_t -#define Int8_t int8_t #define I64(x) ((int64_t)x) #define I32(x) ((int32_t)x) #define I16(x) ((int16_t)x) @@ -40,6 +35,8 @@ MACROLIKE PUREFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max) { \ return x < min ? min : (x > max ? max : x); \ } \ + MACROLIKE CONSTFUNC c_type type_name ## $from_byte(Byte_t b) { return (c_type)b; } \ + MACROLIKE CONSTFUNC c_type type_name ## $from_bool(Bool_t b) { return (c_type)b; } \ CONSTFUNC c_type type_name ## $gcd(c_type x, c_type y); \ extern const c_type type_name ## $min, type_name##$max; \ extern const TypeInfo_t type_name ## $info; \ @@ -126,8 +123,8 @@ OptionalInt_t Int$sqrt(Int_t i); else mpz_init_set(mpz, *(i).big); \ } while (0) -#define I(i) ((i) >= SMALLEST_SMALL_INT && (i) <= BIGGEST_SMALL_INT ? ((Int_t){.small=(int64_t)((uint64_t)(i)<<2)|1}) : Int64_to_Int(i)) #define I_small(i) ((Int_t){.small=(int64_t)((uint64_t)(i)<<2)|1}) +#define I(i) _Generic(i, int8_t: I_small(i), int16_t: I_small(i), default: Int$from_int64(i)) #define I_is_zero(i) ((i).small == 1) Int_t Int$slow_plus(Int_t x, Int_t y); @@ -273,113 +270,104 @@ MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) { return Int$compare_value(x, I_small(0)) < 0; } -// Conversion functions: +// Constructors/conversion functions: -MACROLIKE Int_t Int64_to_Int(int64_t i) -{ +// Int constructors: +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +MACROLIKE PUREFUNC Int_t Int$from_num(double n, bool truncate) { + mpz_t result; + mpz_init_set_d(result, n); + if unlikely (!truncate && mpz_get_d(result) != n) + fail("Could not convert to an integer without truncation: %g", n); + return Int$from_mpz(result); +} +#pragma GCC diagnostic pop +MACROLIKE PUREFUNC Int_t Int$from_num32(float n, bool truncate) { return Int$from_num((double)n, truncate); } +MACROLIKE Int_t Int$from_int64(int64_t i) { if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT) return (Int_t){.small=(i<<2)|1}; mpz_t result; mpz_init_set_si(result, i); return Int$from_mpz(result); } - -#define Int32_to_Int(i, ...) Int64_to_Int(i) -#define Int16_to_Int(i, ...) Int64_to_Int(i) -#define Int8_to_Int(i, ...) Int64_to_Int(i) -#define Int32_to_Int64(i, ...) (Int64_t)(i) -#define Int16_to_Int64(i, ...) (Int64_t)(i) -#define Int8_to_Int64(i, ...) (Int64_t)(i) -#define Int16_to_Int32(i, ...) (Int32_t)(i) -#define Int8_to_Int32(i, ...) (Int32_t)(i) -#define Int8_to_Int16(i, ...) (Int16_t)(i) - -MACROLIKE PUREFUNC Int64_t Int_to_Int64(Int_t i, bool truncate) { +MACROLIKE CONSTFUNC Int_t Int$from_int32(Int32_t i) { return Int$from_int64((Int32_t)i); } +MACROLIKE CONSTFUNC Int_t Int$from_int16(Int16_t i) { return I_small(i); } +MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); } +MACROLIKE CONSTFUNC Int_t Int$from_byte(Byte_t b) { return I_small(b); } +MACROLIKE CONSTFUNC Int_t Int$from_bool(Bool_t b) { return I_small(b); } + +// Int64 constructors +MACROLIKE PUREFUNC Int64_t Int64$from_int(Int_t i, bool truncate) { if likely (i.small & 1) return (int64_t)(i.small >> 2); if (!truncate && unlikely(!mpz_fits_slong_p(*i.big))) - fail("Integer is too big to fit in a 64-bit integer!"); + fail("Integer is too big to fit in a 64-bit integer: %k", (Text_t[1]){Int$value_as_text(i)}); return mpz_get_si(*i.big); } +MACROLIKE CONSTFUNC Int64_t Int64$from_int32(Int32_t i) { return (Int64_t)i; } +MACROLIKE CONSTFUNC Int64_t Int64$from_int16(Int16_t i) { return (Int64_t)i; } +MACROLIKE CONSTFUNC Int64_t Int64$from_int8(Int8_t i) { return (Int64_t)i; } -MACROLIKE PUREFUNC Int32_t Int_to_Int32(Int_t i, bool truncate) { - int64_t i64 = Int_to_Int64(i, truncate); +// Int32 constructors +MACROLIKE PUREFUNC Int32_t Int32$from_int(Int_t i, bool truncate) { + int64_t i64 = Int64$from_int(i, truncate); int32_t i32 = (int32_t)i64; if (!truncate && unlikely(i64 != i32)) - fail("Integer is too big to fit in a 32-bit integer!"); + fail("Integer is too big to fit in a 32-bit integer: %k", (Text_t[1]){Int$value_as_text(i)}); return i32; } +MACROLIKE PUREFUNC Int32_t Int32$from_int64(Int64_t i, bool truncate) { + if (!truncate && unlikely(i != (Int64_t)(Int32_t)i)) + fail("Integer is too big to fit in a 32-bit integer: %ld", i); + return (Int32_t)i; +} +MACROLIKE CONSTFUNC Int32_t Int32$from_int16(Int16_t i) { return (Int32_t)i; } +MACROLIKE CONSTFUNC Int32_t Int32$from_int8(Int8_t i) { return (Int32_t)i; } -MACROLIKE PUREFUNC Int16_t Int_to_Int16(Int_t i, bool truncate) { - int64_t i64 = Int_to_Int64(i, truncate); +// Int16 constructors +MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) { + int64_t i64 = Int64$from_int(i, truncate); int16_t i16 = (int16_t)i64; if (!truncate && unlikely(i64 != i16)) fail("Integer is too big to fit in a 16-bit integer!"); return i16; } -MACROLIKE PUREFUNC Int8_t Int_to_Int8(Int_t i, bool truncate) { - int64_t i64 = Int_to_Int64(i, truncate); +MACROLIKE PUREFUNC Int16_t Int16$from_int64(Int64_t i, bool truncate) { + if (!truncate && unlikely(i != (Int64_t)(Int16_t)i)) + fail("Integer is too big to fit in a 16-bit integer: %ld", i); + return (Int16_t)i; +} +MACROLIKE PUREFUNC Int16_t Int16$from_int32(Int32_t i, bool truncate) { + if (!truncate && unlikely(i != (Int32_t)(Int16_t)i)) + fail("Integer is too big to fit in a 16-bit integer: %ld", i); + return (Int16_t)i; +} +MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; } + +// Int8 constructors +MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) { + int64_t i64 = Int64$from_int(i, truncate); int8_t i8 = (int8_t)i64; if (!truncate && unlikely(i64 != i8)) fail("Integer is too big to fit in an 8-bit integer!"); return i8; } - -MACROLIKE PUREFUNC Int_t Num_to_Int(double n) -{ - mpz_t result; - mpz_init_set_d(result, n); - return Int$from_mpz(result); +MACROLIKE PUREFUNC Int8_t Int8$from_int64(Int64_t i, bool truncate) { + if (!truncate && unlikely(i != (Int64_t)(Int8_t)i)) + fail("Integer is too big to fit in a 8-bit integer: %ld", i); + return (Int8_t)i; } - -MACROLIKE PUREFUNC double Int_to_Num(Int_t i) -{ - if likely (i.small & 1) - return (double)(i.small >> 2); - - return mpz_get_d(*i.big); +MACROLIKE PUREFUNC Int8_t Int8$from_int32(Int32_t i, bool truncate) { + if (!truncate && unlikely(i != (Int32_t)(Int8_t)i)) + fail("Integer is too big to fit in a 8-bit integer: %ld", i); + return (Int8_t)i; +} +MACROLIKE PUREFUNC Int8_t Int8$from_int16(Int16_t i, bool truncate) { + if (!truncate && unlikely(i != (Int16_t)(Int8_t)i)) + fail("Integer is too big to fit in a 8-bit integer: %ld", i); + return (Int8_t)i; } - -#define Int_to_Num32(i) (Num32_t)Int_to_Num(i) - -#define CONVERSION_FUNC(hi, lo) \ - MACROLIKE PUREFUNC int##lo##_t Int##hi##_to_Int##lo(int##hi##_t i, bool truncate) { \ - if (!truncate && unlikely(i != (int##lo##_t)i)) \ - fail("Cannot truncate the Int" #hi " %ld to an Int" #lo, (int64_t)i); \ - return (int##lo##_t)i; \ - } - -CONVERSION_FUNC(64, 32) -CONVERSION_FUNC(64, 16) -CONVERSION_FUNC(64, 8) -CONVERSION_FUNC(32, 16) -CONVERSION_FUNC(32, 8) -CONVERSION_FUNC(16, 8) -#undef CONVERSION_FUNC - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wfloat-equal" -#define CONVERSION_FUNC(num, int_type) \ - MACROLIKE PUREFUNC int_type##_t num##_to_##int_type(num##_t n, bool truncate) { \ - num##_t rounded = (num##_t)round((double)n); \ - if (!truncate && unlikely((num##_t)(int_type##_t)rounded != rounded)) \ - fail("Cannot truncate the " #num " %g to an " #int_type, (double)rounded); \ - return (int_type##_t)rounded; \ - } \ - MACROLIKE PUREFUNC num##_t int_type##_to_##num(int_type##_t n) { \ - return (num##_t)n; \ - } - -CONVERSION_FUNC(Num, Int64) -CONVERSION_FUNC(Num, Int32) -CONVERSION_FUNC(Num, Int16) -CONVERSION_FUNC(Num, Int8) -CONVERSION_FUNC(Num32, Int64) -CONVERSION_FUNC(Num32, Int32) -CONVERSION_FUNC(Num32, Int16) -CONVERSION_FUNC(Num32, Int8) -#pragma GCC diagnostic pop -#undef CONVERSION_FUNC // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/stdlib/moments.c b/stdlib/moments.c index e1f59606..1fadd2e8 100644 --- a/stdlib/moments.c +++ b/stdlib/moments.c @@ -8,6 +8,7 @@ #include <unistd.h> #include "datatypes.h" +#include "math.h" #include "moments.h" #include "optionals.h" #include "patterns.h" @@ -60,11 +61,11 @@ public Moment_t Moment$now(void) public Moment_t Moment$new(Int_t year, Int_t month, Int_t day, Int_t hour, Int_t minute, double second, OptionalText_t timezone) { struct tm info = { - .tm_min=Int_to_Int32(minute, false), - .tm_hour=Int_to_Int32(hour, false), - .tm_mday=Int_to_Int32(day, false), - .tm_mon=Int_to_Int32(month, false) - 1, - .tm_year=Int_to_Int32(year, false) - 1900, + .tm_min=Int32$from_int(minute, false), + .tm_hour=Int32$from_int(hour, false), + .tm_mday=Int32$from_int(day, false), + .tm_mon=Int32$from_int(month, false) - 1, + .tm_year=Int32$from_int(year, false) - 1900, .tm_isdst=-1, }; @@ -81,9 +82,9 @@ public Moment_t Moment$after(Moment_t moment, double seconds, double minutes, do struct tm info = {}; WITH_TIMEZONE(timezone, localtime_r(&moment.tv_sec, &info)); - info.tm_mday += Int_to_Int32(days, false) + 7*Int_to_Int32(weeks, false); - info.tm_mon += Int_to_Int32(months, false); - info.tm_year += Int_to_Int32(years, false); + info.tm_mday += Int32$from_int(days, false) + 7*Int32$from_int(weeks, false); + info.tm_mon += Int32$from_int(months, false); + info.tm_year += Int32$from_int(years, false); time_t t = mktime(&info); return (Moment_t){ diff --git a/stdlib/nums.c b/stdlib/nums.c index 47eb6851..b227ccb8 100644 --- a/stdlib/nums.c +++ b/stdlib/nums.c @@ -50,11 +50,11 @@ public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute } public Text_t Num$format(double f, Int_t precision) { - return Text$format("%.*f", (int)Int_to_Int64(precision, false), f); + return Text$format("%.*f", (int)Int64$from_int(precision, false), f); } public Text_t Num$scientific(double f, Int_t precision) { - return Text$format("%.*e", (int)Int_to_Int64(precision, false), f); + return Text$format("%.*e", (int)Int64$from_int(precision, false), f); } public CONSTFUNC double Num$mod(double num, double modulus) { @@ -125,11 +125,11 @@ public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) } public Text_t Num32$format(float f, Int_t precision) { - return Text$format("%.*f", (int)Int_to_Int64(precision, false), (double)f); + return Text$format("%.*f", (int)Int64$from_int(precision, false), (double)f); } public Text_t Num32$scientific(float f, Int_t precision) { - return Text$format("%.*e", (int)Int_to_Int64(precision, false), (double)f); + return Text$format("%.*e", (int)Int64$from_int(precision, false), (double)f); } public CONSTFUNC float Num32$mod(float num, float modulus) { diff --git a/stdlib/nums.h b/stdlib/nums.h index f000ca8b..0b4cdc1b 100644 --- a/stdlib/nums.h +++ b/stdlib/nums.h @@ -6,15 +6,16 @@ #include <stdbool.h> #include <stdint.h> +#include "datatypes.h" +#include "integers.h" +#include "stdlib.h" #include "types.h" #include "util.h" -#define Num_t double -#define Num32_t float #define OptionalNum_t double #define OptionalNum32_t float -#define N32(n) ((float)n) -#define N64(n) ((double)n) +#define N32(n) ((float)(n)) +#define N64(n) ((double)(n)) Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *type); PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *type); @@ -32,6 +33,38 @@ OptionalNum_t Num$parse(Text_t text); MACROLIKE CONSTFUNC double Num$clamped(double x, double low, double high) { return (x <= low) ? low : (x >= high ? high : x); } +MACROLIKE CONSTFUNC double Num$from_num32(Num32_t n) { return (double)n; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +MACROLIKE CONSTFUNC double Num$from_int(Int_t i, bool truncate) { + if likely (i.small & 0x1) { + double ret = (double)(i.small >> 2); + if unlikely (!truncate && (int64_t)ret != (i.small >> 2)) + fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i.small >> 2); + return ret; + } else { + double ret = mpz_get_d(*i.big); + if (!truncate) { + mpz_t roundtrip; + mpz_init_set_d(roundtrip, ret); + if unlikely (mpz_cmp(*i.big, roundtrip) != 0) + fail("Could not convert integer to 64-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)}); + } + return ret; + } +} +#pragma GCC diagnostic pop +MACROLIKE CONSTFUNC double Num$from_int64(Int64_t i, bool truncate) { + double n = (double)i; + if unlikely (!truncate && (Int64_t)n != i) + fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i); + return n; +} +MACROLIKE CONSTFUNC double Num$from_int32(Int32_t i) { return (double)i; } +MACROLIKE CONSTFUNC double Num$from_int16(Int16_t i) { return (double)i; } +MACROLIKE CONSTFUNC double Num$from_int8(Int8_t i) { return (double)i; } +MACROLIKE CONSTFUNC double Num$from_byte(Byte_t i) { return (double)i; } + extern const TypeInfo_t Num$info; Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *type); @@ -50,9 +83,43 @@ float Num32$nan(Text_t tag); MACROLIKE CONSTFUNC float Num32$clamped(float x, float low, float high) { return (x <= low) ? low : (x >= high ? high : x); } -extern const TypeInfo_t Num32$info; +MACROLIKE CONSTFUNC float Num32$from_num(Num_t n) { return (float)n; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +MACROLIKE CONSTFUNC float Num32$from_int(Int_t i, bool truncate) { + if likely (i.small & 0x1) { + float ret = (float)(i.small >> 2); + if unlikely (!truncate && (int64_t)ret != (i.small >> 2)) + fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i.small >> 2); + return ret; + } else { + float ret = (float)mpz_get_d(*i.big); + if (!truncate) { + mpz_t roundtrip; + mpz_init_set_d(roundtrip, ret); + if unlikely (mpz_cmp(*i.big, roundtrip) != 0) + fail("Could not convert integer to 32-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)}); + } + return ret; + } +} +#pragma GCC diagnostic pop +MACROLIKE CONSTFUNC float Num32$from_int64(Int64_t i, bool truncate) { + float n = (float)i; + if unlikely (!truncate && (Int64_t)n != i) + fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i); + return n; +} +MACROLIKE CONSTFUNC float Num32$from_int32(Int32_t i, bool truncate) { + float n = (float)i; + if unlikely (!truncate && (Int32_t)n != i) + fail("Could not convert integer to 32-bit floating point without losing precision: %d", i); + return n; +} +MACROLIKE CONSTFUNC float Num32$from_int16(Int16_t i) { return (float)i; } +MACROLIKE CONSTFUNC float Num32$from_int8(Int8_t i) { return (float)i; } +MACROLIKE CONSTFUNC float Num32$from_byte(Byte_t i) { return (float)i; } -#define Num_to_Num32(n) ((Num32_t)(n)) -#define Num32_to_Num(n) ((Num_t)(n)) +extern const TypeInfo_t Num32$info; // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/stdlib/optionals.c b/stdlib/optionals.c index 990ca138..d91ebffc 100644 --- a/stdlib/optionals.c +++ b/stdlib/optionals.c @@ -8,6 +8,7 @@ #include "integers.h" #include "metamethods.h" #include "moments.h" +#include "nums.h" #include "patterns.h" #include "text.h" #include "threads.h" diff --git a/stdlib/paths.c b/stdlib/paths.c index 98bcab56..a42dc5ad 100644 --- a/stdlib/paths.c +++ b/stdlib/paths.c @@ -277,7 +277,7 @@ public OptionalArray_t Path$read_bytes(Path_t path, OptionalInt_t count) if (fstat(fd, &sb) != 0) return NONE_ARRAY; - int64_t const target_count = count.small ? Int_to_Int64(count, false) : INT64_MAX; + int64_t const target_count = count.small ? Int64$from_int(count, false) : INT64_MAX; if (target_count < 0) fail("Cannot read a negative number of bytes!"); diff --git a/stdlib/patterns.c b/stdlib/patterns.c index ad6267f0..7d6ccd37 100644 --- a/stdlib/patterns.c +++ b/stdlib/patterns.c @@ -807,7 +807,7 @@ static int64_t _find(Text_t text, Pattern_t pattern, int64_t first, int64_t last public OptionalMatch_t Text$find(Text_t text, Pattern_t pattern, Int_t from_index) { - int64_t first = Int_to_Int64(from_index, false); + int64_t first = Int64$from_int(from_index, false); if (first == 0) fail("Invalid index: 0"); if (first < 0) first = text.length + first + 1; if (first > text.length || first < 1) @@ -874,7 +874,7 @@ public Array_t Text$find_all(Text_t text, Pattern_t pattern) OptionalMatch_t m = Text$find(text, pattern, I(i)); if (!m.index.small) break; - i = Int_to_Int64(m.index, false) + m.text.length; + i = Int64$from_int(m.index, false) + m.text.length; Array$insert(&matches, &m, I_small(0), sizeof(Match_t)); } return matches; @@ -888,7 +888,7 @@ typedef struct { static OptionalMatch_t next_match(match_iter_state_t *state) { - if (Int_to_Int64(state->i, false) > state->state.stack[0].text.length) + if (Int64$from_int(state->i, false) > state->state.stack[0].text.length) return NONE_MATCH; OptionalMatch_t m = Text$find(state->state.stack[0].text, state->pattern, state->i); diff --git a/stdlib/rng.c b/stdlib/rng.c index 8e98aa8e..07b2f36c 100644 --- a/stdlib/rng.c +++ b/stdlib/rng.c @@ -251,7 +251,7 @@ public Byte_t RNG$byte(RNG_t rng) public Array_t RNG$bytes(RNG_t rng, Int_t count) { - int64_t n = Int_to_Int64(count, false); + int64_t n = Int64$from_int(count, false); Byte_t *r = GC_MALLOC_ATOMIC(sizeof(Byte_t[n])); random_bytes(rng, r, sizeof(Byte_t[n])); return (Array_t){.data=r, .length=n, .stride=1, .atomic=1}; diff --git a/stdlib/stdlib.c b/stdlib/stdlib.c index 93b0d481..efee2a05 100644 --- a/stdlib/stdlib.c +++ b/stdlib/stdlib.c @@ -17,6 +17,7 @@ #include "integers.h" #include "optionals.h" #include "metamethods.h" +#include "nums.h" #include "patterns.h" #include "paths.h" #include "rng.h" diff --git a/stdlib/text.c b/stdlib/text.c index 3cb5de05..4ee21601 100644 --- a/stdlib/text.c +++ b/stdlib/text.c @@ -505,7 +505,7 @@ public Text_t Text$repeat(Text_t text, Int_t count) if (Int$compare_value(result_len, I(1l<<40)) > 0) fail("Text repeating would produce too big of an result!"); - int64_t count64 = Int_to_Int64(count, false); + int64_t count64 = Int64$from_int(count, false); Text_t ret = text; for (int64_t c = 1; c < count64; c++) ret = concat2(ret, text); @@ -514,8 +514,8 @@ public Text_t Text$repeat(Text_t text, Int_t count) public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) { - int64_t first = Int_to_Int64(first_int, false); - int64_t last = Int_to_Int64(last_int, false); + int64_t first = Int64$from_int(first_int, false); + int64_t last = Int64$from_int(last_int, false); if (first == 0) fail("Invalid index: 0"); if (last == 0) return EMPTY_TEXT; @@ -604,14 +604,14 @@ public Text_t Text$reversed(Text_t text) public PUREFUNC Text_t Text$cluster(Text_t text, Int_t index_int) { - int64_t index = Int_to_Int64(index_int, false); + int64_t index = Int64$from_int(index_int, false); if (index == 0) fail("Invalid index: 0"); if (index < 0) index = text.length + index + 1; if (index > text.length || index < 1) fail("Invalid index: %ld is beyond the length of the text (length = %ld)", - Int_to_Int64(index_int, false), text.length); + Int64$from_int(index_int, false), text.length); while (text.tag == TEXT_CONCAT) { if (index <= text.left->length) |
