aboutsummaryrefslogtreecommitdiff
path: root/builtins
diff options
context:
space:
mode:
Diffstat (limited to 'builtins')
-rw-r--r--builtins/array.c16
-rw-r--r--builtins/array.h4
-rw-r--r--builtins/channel.c2
-rw-r--r--builtins/integers.c44
-rw-r--r--builtins/integers.h109
-rw-r--r--builtins/nums.c8
-rw-r--r--builtins/text.c2
7 files changed, 128 insertions, 57 deletions
diff --git a/builtins/array.c b/builtins/array.c
index 96a218f5..a6e0dca2 100644
--- a/builtins/array.c
+++ b/builtins/array.c
@@ -50,7 +50,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$as_i64(int_index);
+ int64_t index = Int_to_Int64(int_index, false);
if (index <= 0) index = arr->length + index + 1;
if (index < 1) index = 1;
@@ -82,7 +82,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$as_i64(int_index);
+ int64_t index = Int_to_Int64(int_index, false);
if (to_insert.length == 0)
return;
@@ -154,10 +154,10 @@ public void Array$insert_all(array_t *arr, array_t to_insert, Int_t int_index, i
public void Array$remove(array_t *arr, Int_t int_index, Int_t int_count, int64_t padded_item_size)
{
- int64_t index = Int$as_i64(int_index);
+ int64_t index = Int_to_Int64(int_index, false);
if (index < 1) index = arr->length + index + 1;
- int64_t count = Int$as_i64(int_count);
+ int64_t count = Int_to_Int64(int_count, false);
if (index < 1 || index > (int64_t)arr->length || count < 1) return;
if (count > arr->length - index + 1)
@@ -240,7 +240,7 @@ public table_t Array$counts(array_t arr, const TypeInfo *type)
public array_t Array$sample(array_t arr, Int_t int_n, array_t weights, int64_t padded_item_size)
{
- int64_t n = Int$as_i64(int_n);
+ int64_t n = Int_to_Int64(int_n, false);
if (arr.length == 0 || n <= 0)
return (array_t){};
@@ -319,7 +319,7 @@ public array_t Array$sample(array_t arr, Int_t int_n, array_t weights, int64_t p
public array_t Array$from(array_t array, Int_t int_first)
{
- int64_t first = Int$as_i64(int_first);
+ int64_t first = Int_to_Int64(int_first, false);
if (first < 0)
first = array.length + first + 1;
@@ -337,7 +337,7 @@ public array_t Array$from(array_t array, Int_t int_first)
public array_t Array$to(array_t array, Int_t int_last)
{
- int64_t last = Int$as_i64(int_last);
+ int64_t last = Int_to_Int64(int_last, false);
if (last < 0)
last = array.length + last + 1;
@@ -358,7 +358,7 @@ public array_t Array$to(array_t array, Int_t int_last)
public array_t Array$by(array_t array, Int_t int_stride, int64_t padded_item_size)
{
- int64_t stride = Int$as_i64(int_stride);
+ int64_t stride = Int_to_Int64(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 (__builtin_expect(array.stride*stride < ARRAY_MIN_STRIDE || array.stride*stride > ARRAY_MAX_STRIDE, 0)) {
diff --git a/builtins/array.h b/builtins/array.h
index 6da84afd..a3305ca3 100644
--- a/builtins/array.h
+++ b/builtins/array.h
@@ -13,13 +13,13 @@
// Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1
#define Array_get(item_type, arr_expr, index_expr, filename, start, end) *({ \
- const array_t arr = arr_expr; int64_t index = Int$as_i64(index_expr); \
+ const array_t arr = arr_expr; int64_t index = Int_to_Int64(index_expr, false); \
int64_t off = index + (index < 0) * (arr.length + 1) - 1; \
if (__builtin_expect(off < 0 || off >= arr.length, 0)) \
fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64$as_text(&index, no, NULL), arr.length); \
(item_type*)(arr.data + arr.stride * off);})
#define Array_lvalue(item_type, arr_expr, index_expr, padded_item_size, filename, start, end) *({ \
- array_t *arr = arr_expr; int64_t index = Int$as_i64(index_expr); \
+ array_t *arr = arr_expr; int64_t index = Int_to_Int64(index_expr, false); \
int64_t off = index + (index < 0) * (arr->length + 1) - 1; \
if (__builtin_expect(off < 0 || off >= arr->length, 0)) \
fail_source(filename, start, end, "Invalid array index: %r (array has length %ld)\n", Int64$as_text(&index, no, NULL), arr->length); \
diff --git a/builtins/channel.c b/builtins/channel.c
index dba50115..dd49163c 100644
--- a/builtins/channel.c
+++ b/builtins/channel.c
@@ -26,7 +26,7 @@ public channel_t *Channel$new(Int_t max_size)
channel->items = (array_t){};
channel->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
channel->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
- channel->max_size = Int$as_i64(max_size);
+ channel->max_size = Int_to_Int64(max_size, false);
return channel;
}
diff --git a/builtins/integers.c b/builtins/integers.c
index 0783f16d..bb82fab6 100644
--- a/builtins/integers.c
+++ b/builtins/integers.c
@@ -21,30 +21,6 @@ public void Int$init_random(long seed)
gmp_randseed_ui(Int_rng, (unsigned long)seed);
}
-public Int_t Int$from_i64(int64_t i)
-{
- int64_t z = i<<2;
- if (z == (int32_t)z) return (Int_t){.small=z+1};
- mpz_t result;
- mpz_init_set_si(result, i);
- return Int$from_mpz(result);
-}
-
-public Int_t Int$from_num(double n)
-{
- mpz_t result;
- mpz_init_set_d(result, n);
- return Int$from_mpz(result);
-}
-
-public double Int$as_num(Int_t i)
-{
- if (__builtin_expect(i.small & 1, 1))
- return (double)(i.small >> 2);
-
- return mpz_get_d(*i.big);
-}
-
public CORD Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type) {
(void)type;
if (!i) return "Int";
@@ -93,7 +69,7 @@ public uint32_t Int$hash(const Int_t *x, const TypeInfo *type) {
public CORD Int$format(Int_t i, Int_t digits_int)
{
- int64_t digits = Int$as_i64(digits_int);
+ int64_t digits = Int_to_Int64(digits_int, false);
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf("%0.*ld", digits, (i.small)>>2);
} else {
@@ -110,7 +86,7 @@ public CORD Int$format(Int_t i, Int_t digits_int)
}
public CORD Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
- int64_t digits = Int$as_i64(digits_int);
+ int64_t digits = Int_to_Int64(digits_int, false);
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx");
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf(hex_fmt, digits, (i.small)>>2);
@@ -125,7 +101,7 @@ public CORD Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
}
public CORD Int$octal(Int_t i, Int_t digits_int, bool prefix) {
- int64_t digits = Int$as_i64(digits_int);
+ int64_t digits = Int_to_Int64(digits_int, false);
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo";
if (__builtin_expect(i.small & 1, 1)) {
return CORD_asprintf(octal_fmt, (int)digits, (uint64_t)(i.small >> 2));
@@ -213,7 +189,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$as_i64(y);
+ mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false);
mpz_t result;
mpz_init_set_int(result, x);
mpz_mul_2exp(result, result, bits);
@@ -222,7 +198,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$as_i64(y);
+ mp_bitcnt_t bits = (mp_bitcnt_t)Int_to_Int64(y, false);
mpz_t result;
mpz_init_set_int(result, x);
mpz_tdiv_q_2exp(result, result, bits);
@@ -292,7 +268,7 @@ public Int_t Int$abs(Int_t x)
public Int_t Int$power(Int_t base, Int_t exponent)
{
- int64_t exp = Int$as_i64(exponent);
+ int64_t exp = Int_to_Int64(exponent, false);
if (__builtin_expect(exp < 0, 0))
fail("Cannot take a negative power of an integer!");
mpz_t result;
@@ -382,16 +358,16 @@ public const TypeInfo $Int = {
return *x == *y; \
} \
public CORD KindOfInt ## $format(c_type i, Int_t digits_int) { \
- int64_t digits = Int$as_i64(digits_int); \
+ int64_t digits = Int_to_Int64(digits_int, false); \
return CORD_asprintf("%0*" fmt, (int)digits, i); \
} \
public CORD KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
- int64_t digits = Int$as_i64(digits_int); \
+ int64_t digits = Int_to_Int64(digits_int, false); \
const char *hex_fmt = uppercase ? (prefix ? "0x%0.*lX" : "%0.*lX") : (prefix ? "0x%0.*lx" : "%0.*lx"); \
return CORD_asprintf(hex_fmt, (int)digits, (uint64_t)i); \
} \
public CORD KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \
- int64_t digits = Int$as_i64(digits_int); \
+ int64_t digits = Int_to_Int64(digits_int, false); \
const char *octal_fmt = prefix ? "0o%0.*lo" : "%0.*lo"; \
return CORD_asprintf(octal_fmt, (int)digits, (uint64_t)i); \
} \
@@ -422,7 +398,7 @@ public const TypeInfo $Int = {
return (c_type)((uint64_t)min + (r % range)); \
} \
public Range_t KindOfInt ## $to(c_type from, c_type to) { \
- return (Range_t){Int$from_i64(from), Int$from_i64(to), to >= from ? (Int_t){.small=(1<<2)&1} : (Int_t){.small=(1<<2)&1}}; \
+ return (Range_t){Int64_to_Int(from), Int64_to_Int(to), to >= from ? (Int_t){.small=(1<<2)&1} : (Int_t){.small=(1<<2)&1}}; \
} \
public c_type KindOfInt ## $from_text(CORD text, CORD *the_rest) { \
const char *str = CORD_to_const_char_star(text); \
diff --git a/builtins/integers.h b/builtins/integers.h
index 98b58b0f..05085175 100644
--- a/builtins/integers.h
+++ b/builtins/integers.h
@@ -9,7 +9,10 @@
#include <gmp.h>
#include "datatypes.h"
+#include "functions.h"
+#include "nums.h"
#include "types.h"
+#include "util.h"
#define Int64_t int64_t
#define Int32_t int32_t
@@ -78,13 +81,7 @@ Int_t Int$sqrt(Int_t i);
else mpz_init_set(mpz, *(i).big); \
} while (0)
-#define Int$as_i64(i) (__builtin_expect((i).small & 1, 1) ? (int64_t)((i).small >> 2) : \
- ({ if (!__builtin_expect(mpz_fits_slong_p(*(i).big), 1)) fail("Integer is too big to fit in a 64-bit integer!"); \
- mpz_get_si(*(i).big); }))
-Int_t Int$from_i64(int64_t i);
-Int_t Int$from_num(double n);
-double Int$as_num(Int_t i);
-#define I(i) ((int64_t)(i) == (int32_t)(i) ? ((Int_t){.small=((uint64_t)(i)<<2)|1}) : Int$from_i64(i))
+#define I(i) ((int64_t)(i) == (int32_t)(i) ? ((Int_t){.small=((uint64_t)(i)<<2)|1}) : Int64_to_Int(i))
Int_t Int$slow_plus(Int_t x, Int_t y);
Int_t Int$slow_minus(Int_t x, Int_t y);
@@ -207,4 +204,102 @@ static inline Int_t Int$negative(Int_t x)
return Int$slow_negative(x);
}
+// Conversion functions:
+
+static inline Int_t Int64_to_Int(int64_t i)
+{
+ int64_t z = i<<2;
+ if (__builtin_expect(z == (int32_t)z, 1))
+ return (Int_t){.small=z+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)
+
+static inline Int64_t Int_to_Int64(Int_t i, bool truncate) {
+ if (__builtin_expect(i.small & 1, 1))
+ return (int64_t)(i.small >> 2);
+ if (__builtin_expect(!truncate && !mpz_fits_slong_p(*i.big), 0))
+ fail("Integer is too big to fit in a 64-bit integer!");
+ return mpz_get_si(*i.big);
+}
+
+static inline Int32_t Int_to_Int32(Int_t i, bool truncate) {
+ int64_t i64 = Int_to_Int64(i, truncate);
+ int32_t i32 = (int32_t)i64;
+ if (__builtin_expect(i64 != i32 && !truncate, 0))
+ fail("Integer is too big to fit in a 32-bit integer!");
+ return i32;
+}
+
+static inline Int16_t Int_to_Int16(Int_t i, bool truncate) {
+ int64_t i64 = Int_to_Int64(i, truncate);
+ int16_t i16 = (int16_t)i64;
+ if (__builtin_expect(i64 != i16 && !truncate, 0))
+ fail("Integer is too big to fit in a 16-bit integer!");
+ return i16;
+}
+
+static inline Int8_t Int_to_Int8(Int_t i, bool truncate) {
+ int64_t i64 = Int_to_Int64(i, truncate);
+ int8_t i8 = (int8_t)i64;
+ if (__builtin_expect(i64 != i8 && !truncate, 0))
+ fail("Integer is too big to fit in an 8-bit integer!");
+ return i8;
+}
+
+static inline Int_t Num_to_Int(double n)
+{
+ mpz_t result;
+ mpz_init_set_d(result, n);
+ return Int$from_mpz(result);
+}
+
+static inline double Int_to_Num(Int_t i)
+{
+ if (__builtin_expect(i.small & 1, 1))
+ return (double)(i.small >> 2);
+
+ return mpz_get_d(*i.big);
+}
+
+#define Int_to_Num32(i) (Num32_t)Int_to_Num(i)
+
+#define CONVERSION_FUNC(hi, lo) \
+ static inline int##lo##_t Int##hi##_to_Int##lo(int##hi##_t i, bool truncate) { \
+ if (__builtin_expect(!truncate && (i != (int##lo##_t)i), 0)) \
+ 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
+
+#define CONVERSION_FUNC(num, int_type) \
+ static inline int_type##_t num##_to_##int_type(num##_t n, bool truncate) { \
+ num##_t rounded = round(n); \
+ if (__builtin_expect(!truncate && (num##_t)(int_type##_t)rounded != rounded, 0)) \
+ fail("Cannot truncate the " #num " %g to an " #int_type, rounded); \
+ return (int_type##_t)rounded; \
+ }
+
+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)
+#undef CONVERSION_FUNC
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/nums.c b/builtins/nums.c
index f1635fd5..2efd4cbc 100644
--- a/builtins/nums.c
+++ b/builtins/nums.c
@@ -48,11 +48,11 @@ public bool Num$near(double a, double b, double ratio, double absolute) {
}
public CORD Num$format(double f, Int_t precision) {
- return CORD_asprintf("%.*f", (int)Int$as_i64(precision), f);
+ return CORD_asprintf("%.*f", (int)Int_to_Int64(precision, false), f);
}
public CORD Num$scientific(double f, Int_t precision) {
- return CORD_asprintf("%.*e", (int)Int$as_i64(precision), f);
+ return CORD_asprintf("%.*e", (int)Int_to_Int64(precision, false), f);
}
public double Num$mod(double num, double modulus) {
@@ -130,11 +130,11 @@ public bool Num32$near(float a, float b, float ratio, float absolute) {
}
public CORD Num32$format(float f, Int_t precision) {
- return CORD_asprintf("%.*f", (int)Int$as_i64(precision), f);
+ return CORD_asprintf("%.*f", (int)Int_to_Int64(precision, false), f);
}
public CORD Num32$scientific(float f, Int_t precision) {
- return CORD_asprintf("%.*e", (int)Int$as_i64(precision), f);
+ return CORD_asprintf("%.*e", (int)Int_to_Int64(precision, false), f);
}
public float Num32$mod(float num, float modulus) {
diff --git a/builtins/text.c b/builtins/text.c
index 754eef91..22784a34 100644
--- a/builtins/text.c
+++ b/builtins/text.c
@@ -255,7 +255,7 @@ public CORD Text$replace(CORD text, CORD pat, CORD replacement, Int_t int_limit)
if (!text || !pat) return text;
CORD ret = CORD_EMPTY;
size_t pos = 0, pat_len = CORD_len(pat);
- int64_t limit = Int$as_i64(int_limit);
+ int64_t limit = Int_to_Int64(int_limit, false);
for (size_t found; limit != 0 && (found=CORD_str(text, pos, pat)) != CORD_NOT_FOUND; --limit) {
ret = CORD_all(ret, CORD_substr(text, pos, found - pos), replacement);
pos = found + pat_len;