2024-02-17 16:32:30 -08:00
|
|
|
#pragma once
|
2024-03-18 09:57:49 -07:00
|
|
|
|
|
|
|
// Integer type infos and methods
|
|
|
|
|
2024-02-17 16:32:30 -08:00
|
|
|
#include <gc/cord.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2024-05-18 11:42:35 -07:00
|
|
|
#include <stdlib.h>
|
2024-08-12 22:30:25 -07:00
|
|
|
#include <gmp.h>
|
2024-02-17 16:32:30 -08:00
|
|
|
|
2024-03-03 10:37:05 -08:00
|
|
|
#include "datatypes.h"
|
2024-02-17 16:32:30 -08:00
|
|
|
#include "types.h"
|
|
|
|
|
2024-08-12 22:30:25 -07:00
|
|
|
#define Int64_t int64_t
|
2024-02-17 20:27:02 -08:00
|
|
|
#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)
|
|
|
|
#define I8(x) ((int8_t)x)
|
|
|
|
|
2024-02-17 16:52:37 -08:00
|
|
|
#define DEFINE_INT_TYPE(c_type, type_name) \
|
2024-03-29 09:54:31 -07:00
|
|
|
CORD type_name ## $as_text(const c_type *i, bool colorize, const TypeInfo *type); \
|
|
|
|
int32_t type_name ## $compare(const c_type *x, const c_type *y, const TypeInfo *type); \
|
|
|
|
bool type_name ## $equal(const c_type *x, const c_type *y, const TypeInfo *type); \
|
2024-08-12 23:20:48 -07:00
|
|
|
CORD type_name ## $format(c_type i, Int_t digits); \
|
|
|
|
CORD type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
|
|
|
|
CORD type_name ## $octal(c_type i, Int_t digits, bool prefix); \
|
2024-03-29 09:54:31 -07:00
|
|
|
array_t type_name ## $bits(c_type x); \
|
2024-08-03 13:23:28 -07:00
|
|
|
c_type type_name ## $random(c_type min, c_type max); \
|
2024-08-05 11:40:28 -07:00
|
|
|
Range_t type_name ## $to(c_type from, c_type to); \
|
2024-04-10 10:23:49 -07:00
|
|
|
c_type type_name ## $from_text(CORD text, CORD *the_rest); \
|
2024-03-29 09:54:31 -07:00
|
|
|
extern const c_type type_name ## $min, type_name##$max; \
|
|
|
|
extern const TypeInfo $ ## type_name;
|
|
|
|
|
2024-08-12 22:30:25 -07:00
|
|
|
DEFINE_INT_TYPE(int64_t, Int64);
|
2024-03-29 09:54:31 -07:00
|
|
|
DEFINE_INT_TYPE(int32_t, Int32);
|
|
|
|
DEFINE_INT_TYPE(int16_t, Int16);
|
|
|
|
DEFINE_INT_TYPE(int8_t, Int8);
|
2024-02-17 16:32:30 -08:00
|
|
|
#undef DEFINE_INT_TYPE
|
|
|
|
|
2024-08-12 22:30:25 -07:00
|
|
|
#define Int64$abs(...) I64(labs(__VA_ARGS__))
|
2024-03-29 09:54:31 -07:00
|
|
|
#define Int32$abs(...) I32(abs(__VA_ARGS__))
|
|
|
|
#define Int16$abs(...) I16(abs(__VA_ARGS__))
|
|
|
|
#define Int8$abs(...) I8(abs(__VA_ARGS__))
|
2024-02-27 10:39:12 -08:00
|
|
|
|
2024-08-12 22:30:25 -07:00
|
|
|
CORD Int$as_text(const Int_t *i, bool colorize, const TypeInfo *type);
|
2024-08-12 23:28:14 -07:00
|
|
|
uint32_t Int$hash(const Int_t *x, const TypeInfo *type);
|
2024-08-12 22:30:25 -07:00
|
|
|
int32_t Int$compare(const Int_t *x, const Int_t *y, const TypeInfo *type);
|
|
|
|
int32_t Int$compare_value(const Int_t x, const Int_t y);
|
|
|
|
bool Int$equal(const Int_t *x, const Int_t *y, const TypeInfo *type);
|
|
|
|
bool Int$equal_value(const Int_t x, const Int_t y);
|
2024-08-12 23:09:18 -07:00
|
|
|
CORD Int$format(Int_t i, Int_t digits);
|
|
|
|
CORD Int$hex(Int_t i, Int_t digits, bool uppercase, bool prefix);
|
|
|
|
CORD Int$octal(Int_t i, Int_t digits, bool prefix);
|
2024-08-12 22:30:25 -07:00
|
|
|
void Int$init_random(long seed);
|
|
|
|
Int_t Int$random(Int_t min, Int_t max);
|
|
|
|
Range_t Int$to(Int_t from, Int_t to);
|
|
|
|
Int_t Int$from_text(CORD text);
|
|
|
|
Int_t Int$abs(Int_t x);
|
|
|
|
|
2024-08-13 11:27:50 -07:00
|
|
|
#define BIGGEST_SMALL_INT ((1<<29)-1)
|
2024-08-12 22:30:25 -07:00
|
|
|
|
|
|
|
#define Int$from_mpz(mpz) (\
|
|
|
|
mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ({ \
|
|
|
|
(Int_t){.small=(mpz_get_si(mpz)<<2)|1}; \
|
|
|
|
}) : ({ \
|
|
|
|
mpz_t *result_obj = new(mpz_t); \
|
|
|
|
memcpy(result_obj, &mpz, sizeof(mpz_t)); \
|
|
|
|
(Int_t){.big=result_obj}; \
|
|
|
|
}))
|
|
|
|
|
|
|
|
#define mpz_init_set_int(mpz, i) do { \
|
|
|
|
if ((i).small & 1) mpz_init_set_si(mpz, (i).small >> 2); \
|
|
|
|
else mpz_init_set(mpz, *(i).big); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define Int$as_i64(i) (((i).small & 1) ? (int64_t)((i).small >> 2) : mpz_get_si(*(i).big))
|
|
|
|
Int_t Int$from_i64(int64_t i);
|
2024-08-12 23:20:48 -07:00
|
|
|
Int_t Int$from_num(double n);
|
2024-08-12 23:51:10 -07:00
|
|
|
double Int$as_num(Int_t i);
|
2024-08-12 22:30:25 -07:00
|
|
|
#define I(i) ((int64_t)(i) == (int32_t)(i) ? ((Int_t){.small=((uint64_t)(i)<<2)|1}) : Int$from_i64(i))
|
|
|
|
|
2024-08-13 10:50:19 -07:00
|
|
|
Int_t Int$slow_plus(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_minus(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_times(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_divided_by(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_modulo(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_modulo1(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_left_shifted(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_right_shifted(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_bit_and(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_bit_or(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_bit_xor(Int_t x, Int_t y);
|
|
|
|
Int_t Int$slow_negative(Int_t x);
|
|
|
|
Int_t Int$slow_negated(Int_t x);
|
2024-08-12 23:42:02 -07:00
|
|
|
Int_t Int$abs(Int_t x);
|
2024-08-12 22:30:25 -07:00
|
|
|
|
|
|
|
extern const TypeInfo $Int;
|
|
|
|
|
2024-08-13 10:50:19 -07:00
|
|
|
// Fast-path inline versions for the common case where integer arithmetic is
|
|
|
|
// between two small ints.
|
|
|
|
|
|
|
|
static inline Int_t Int$plus(Int_t x, Int_t y) {
|
|
|
|
const int64_t z = (int64_t)((uint64_t)x.small + (uint64_t)y.small);
|
|
|
|
if (__builtin_expect(((z|2) == (int32_t)z), 1))
|
|
|
|
return (Int_t){.small=(z-1)};
|
|
|
|
return Int$slow_plus(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$minus(Int_t x, Int_t y) {
|
|
|
|
const int64_t z = (int64_t)(((uint64_t)x.small ^ 3) - (uint64_t)y.small);
|
|
|
|
if (__builtin_expect(((z & ~2) == (int32_t)z), 1))
|
|
|
|
return (Int_t){.small=z};
|
|
|
|
return Int$slow_minus(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$times(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
const int64_t z = (x.small>>1) * (y.small>>1);
|
|
|
|
if (__builtin_expect(z == (int32_t)z, 1))
|
|
|
|
return (Int_t){.small=z+1};
|
|
|
|
}
|
|
|
|
return Int$slow_times(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$divided_by(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
const int64_t z = 4*(x.small>>1) / (y.small>>1);
|
|
|
|
if (__builtin_expect(z == (int32_t)z, 1))
|
|
|
|
return (Int_t){.small=z+1};
|
|
|
|
}
|
|
|
|
return Int$slow_divided_by(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$modulo(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
int64_t mod = (x.small>>2) % (y.small>>2);
|
|
|
|
if (mod < 0) mod += (y.small>>2);
|
|
|
|
return (Int_t){.small=(mod<<2)+1};
|
|
|
|
}
|
|
|
|
return Int$slow_modulo(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$modulo1(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
int64_t mod = ((x.small>>2)-1) % (y.small>>2);
|
|
|
|
if (mod < 0) mod += (y.small>>2);
|
|
|
|
return (Int_t){.small=((mod+1)<<2)+1};
|
|
|
|
}
|
|
|
|
return Int$slow_modulo1(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$left_shifted(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
const int64_t z = 4*((x.small>>2) << (y.small>>2));
|
|
|
|
if (__builtin_expect(z == (int32_t)z, 1))
|
|
|
|
return (Int_t){.small=z+1};
|
|
|
|
}
|
|
|
|
return Int$slow_left_shifted(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$right_shifted(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) != 0, 1)) {
|
|
|
|
const int64_t z = 4*((x.small>>2) >> (y.small>>2));
|
|
|
|
if (__builtin_expect(z == (int32_t)z, 1))
|
|
|
|
return (Int_t){.small=z+1};
|
|
|
|
}
|
|
|
|
return Int$slow_right_shifted(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$bit_and(Int_t x, Int_t y) {
|
|
|
|
const int64_t z = x.small & y.small;
|
|
|
|
if (__builtin_expect((z & 1) == 1, 1))
|
|
|
|
return (Int_t){.small=z};
|
|
|
|
return Int$slow_bit_and(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$bit_or(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) == 1, 1))
|
|
|
|
return (Int_t){.small=(x.small | y.small)};
|
|
|
|
return Int$slow_bit_or(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$bit_xor(Int_t x, Int_t y) {
|
|
|
|
if (__builtin_expect(((x.small & y.small) & 1) == 1, 1))
|
|
|
|
return (Int_t){.small=(x.small ^ y.small) | 1};
|
|
|
|
return Int$slow_bit_xor(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$negated(Int_t x)
|
|
|
|
{
|
|
|
|
if (__builtin_expect((x.small & 1), 1))
|
|
|
|
return (Int_t){.small=(~x.small) ^ 3};
|
|
|
|
return Int$slow_negated(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Int_t Int$negative(Int_t x)
|
|
|
|
{
|
|
|
|
if (__builtin_expect((x.small & 1), 1))
|
|
|
|
return (Int_t){.small=4*-((x.small)>>2) + 1};
|
|
|
|
return Int$slow_negative(x);
|
|
|
|
}
|
2024-08-12 22:30:25 -07:00
|
|
|
|
2024-02-17 16:32:30 -08:00
|
|
|
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|