aboutsummaryrefslogtreecommitdiff
path: root/stdlib
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-03-05 18:20:54 -0500
committerBruce Hill <bruce@bruce-hill.com>2025-03-05 18:20:54 -0500
commit147e0f0269440fce15d6b88a8a90627f3a3b2df2 (patch)
treebc33522ba71b5a2996fae22e102cce5046cf1333 /stdlib
parent2c4324670ff569ede360d13875c5e4b5720a626d (diff)
Overhaul of constructors, making it more consistent and correct. Also
changed T(), T, T_t, T_s type names to T(), T$$info, T$$type, T$$struct for unambiguity
Diffstat (limited to 'stdlib')
-rw-r--r--stdlib/arrays.c17
-rw-r--r--stdlib/arrays.h2
-rw-r--r--stdlib/bools.h7
-rw-r--r--stdlib/bytes.c23
-rw-r--r--stdlib/bytes.h18
-rw-r--r--stdlib/datatypes.h10
-rw-r--r--stdlib/integers.c27
-rw-r--r--stdlib/integers.h154
-rw-r--r--stdlib/moments.c17
-rw-r--r--stdlib/nums.c8
-rw-r--r--stdlib/nums.h81
-rw-r--r--stdlib/optionals.c1
-rw-r--r--stdlib/paths.c2
-rw-r--r--stdlib/patterns.c6
-rw-r--r--stdlib/rng.c2
-rw-r--r--stdlib/stdlib.c1
-rw-r--r--stdlib/text.c10
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)