// 0x7 f f 8 | 7
// <01111111 1111 12-bit nan header> <1-bit silent flag, 0 on most cpus> <3-bit tag> <48-bit payload>
// 000 - variable - pointer to variable name
// 001 - atom
// 010 - small integer
// 011 - large integer
// 100 - pair - <3-bit type> <21-bit unused> <24-bit index to first>
// 000 - fraction
// 001 - power
// 010 - unused
// 011 - unused
// 100 - equals
// 101 - not equals
// 110 - less than
// 111 - greater than
// 101 - list - <1-bit type> <23-bit count> <24-bit index to first>
// 0 - sum
// 1 - product
// 110 - unused
// 111 - unused
//
// new integer encoding
// 0x0000800000000000 == flag mask
// 800000000000 == both - negative flag
// 7FFFFFFFFFFF == small - uint44_t
// 7FFFFF000000 == large - 21-bit count
// FFFFFF == large - 24-bit index
#define NAN_MASK 0xFFF0000000000000ull
#define NAN_BITS 0x7FF0000000000000ull
#define QUEIT_BITS 0x7FF0000000000000ull
#define SIGNALING_BITS 0x7FF8000000000000ull
#define TAG_MASK 0xFFF7000000000000ull
#define TAG_VARIABLE_BITS 0x7FF0000000000000ull
#define TAG_ATOM_BITS 0x7FF1000000000000ull
#define TAG_SMALLINT_BITS 0x7FF2000000000000ull
#define TAG_LARGEINT_BITS 0x7FF3000000000000ull
#define TAG_PAIR_BITS 0x7FF4000000000000ull
#define TAG_LIST_BITS 0x7FF5000000000000ull
#define TAG_UNUSED6_BITS 0x7FF6000000000000ull
#define TAG_UNUSED7_BITS 0x7FF7000000000000ull
#define PAIR_MASK 0xFFF7e00000000000ull
#define PAIR_FRACTION_BITS 0x7FF4000000000000ull
#define PAIR_POWER_BITS 0x7FF4200000000000ull
#define PAIR_UNUSED1_BITS 0x7FF4400000000000ull
#define PAIR_UNUSED2_BITS 0x7FF4600000000000ull
#define PAIR_EQUAL_BITS 0x7FF4800000000000ull
#define PAIR_NOT_EQUAL_BITS 0x7FF4a00000000000ull
#define PAIR_LESS_THAN_BITS 0x7FF4c00000000000ull
#define PAIR_GREATER_THAN_BITS 0x7FF4e00000000000ull
#define LIST_MASK 0xFFF7800000000000ull
#define LIST_SUM_BITS 0x7FF5000000000000ull
#define LIST_PRODUCT_BITS 0x7FF5800000000000ull
#define PAYLOAD_MASK 0x0000FFFFFFFFFFFFull
#define PAIR_INDEX_MASK 0x0000000000FFFFFFull // 24-bits
#define LIST_COUNT_MASK 0x00007FFFFF000000ull // 23-bits
#define LIST_INDEX_MASK 0x0000000000FFFFFFull // 24-bits
#define INTEGER_MASK 0xFFFE000000000000ull // mask ignores small or large integer descriminating bit
#define INTEGER_BITS 0x7FF2000000000000ull
#define INTEGER_NEG_FLAG_BIT 0x0000800000000000ull
#define INTEGER_COUNT_MASK 0x00007FFFFF000000ull // 23-bits
#define INTEGER_INDEX_MASK 0x0000000000FFFFFFull // 24-bits
#define INTEGER_SMALL_MASK 0x00007FFFFFFFFFFFull // 47-bits
#define LITERAL_FALSE (TAG_ATOM_BITS | 0)
#define LITERAL_TRUE (TAG_ATOM_BITS | 1)
#define LITERAL_UNDEFINED (TAG_ATOM_BITS | 2)
#define LITERAL_ZERO (TAG_SMALLINT_BITS | 0)
#define LITERAL_ONE (TAG_SMALLINT_BITS | 1)
#define LITERAL_TWO (TAG_SMALLINT_BITS | 2)
#define LITERAL_NEGATIVE_ONE (TAG_SMALLINT_BITS | INTEGER_NEG_FLAG_BIT | 1)
static uint32_t get_pair_index(uint64_t expr) {
assert((expr & TAG_MASK) == TAG_PAIR_BITS);
return expr & LIST_INDEX_MASK;
}
static uint32_t get_list_count(uint64_t expr) {
assert((expr & TAG_MASK) == TAG_LIST_BITS);
return (expr & LIST_COUNT_MASK) >> 24;
}
static uint32_t get_list_index(uint64_t expr) {
assert((expr & TAG_MASK) == TAG_LIST_BITS);
return expr & LIST_INDEX_MASK;
}
static uint32_t get_integer_count(uint64_t expr) {
assert((expr & TAG_MASK) == TAG_LARGEINT_BITS);
return (expr & INTEGER_COUNT_MASK) >> 24;
}
static uint32_t get_integer_index(uint64_t expr) {
assert((expr & TAG_MASK) == TAG_LARGEINT_BITS);
return (expr & INTEGER_INDEX_MASK);
}
struct EncodedList {
uint32_t count;
uint32_t index;
};
// --------------------------------------------------------------------------------------------------------------------
#define DEFINE_ENCODING(TYPE, CTYPE, IS_FN, PACK_FN, UNPACK_FN) \
static inline bool is_##TYPE(uint64_t packed) IS_FN \
static inline uint64_t pack_##TYPE(CTYPE unpacked) PACK_FN \
static inline CTYPE unpack_##TYPE(uint64_t packed) { assert(is_##TYPE(packed)); UNPACK_FN }
union DoubleBits {
uint64_t u;
double d;
};
DEFINE_ENCODING(
real, double,
{ return (packed & NAN_MASK) != NAN_BITS; },
{
union DoubleBits _;
_.d = unpacked;
return _.u;
},
{
union DoubleBits _;
_.u = packed;
return _.d;
}
)
DEFINE_ENCODING(
variable, const char *,
{ return (packed & TAG_MASK) == TAG_VARIABLE_BITS; },
{ return TAG_VARIABLE_BITS | ((uint64_t)unpacked & PAYLOAD_MASK); },
{ return (const char *)(packed & PAYLOAD_MASK); }
)
DEFINE_ENCODING(
boolean, bool,
{ return (packed & TAG_MASK) == TAG_ATOM_BITS && (packed & (PAYLOAD_MASK ^ 1)) == 0; },
{ return TAG_ATOM_BITS | !!unpacked; },
{ return packed ^ 1; }
)
static inline bool is_undefined(uint64_t packed) { return packed == (TAG_ATOM_BITS | 2); }
static inline uint64_t pack_undefined() { return TAG_ATOM_BITS | 2; }
static inline void unpack_undefined(uint64_t packed) { assert(is_undefined(packed)); }
static inline bool is_smallint(uint64_t packed) {
return (packed & TAG_MASK) == TAG_SMALLINT_BITS;
}
static inline uint64_t pack_smallint(int64_t value) {
uint64_t result = TAG_SMALLINT_BITS;
if(value < 0) {
result |= INTEGER_NEG_FLAG_BIT;
value *= -1;
}
assert((value & ~INTEGER_SMALL_MASK) == 0);
return result | value;
}
static inline int64_t unpack_smallint(uint64_t expr) {
assert(is_smallint(expr));
return (((expr & INTEGER_NEG_FLAG_BIT) == INTEGER_NEG_FLAG_BIT) ? -1 : 1) * ((int64_t)(expr & INTEGER_SMALL_MASK));
}
static inline bool is_largeint(uint64_t packed) {
return (packed & TAG_MASK) == TAG_LARGEINT_BITS;
}
static inline uint64_t pack_largeint(uint64_t flags, uint32_t count, uint32_t index) {
return TAG_LARGEINT_BITS | flags | (count << 24) | index;
}
static inline struct EncodedList unpack_largeint(uint64_t packed) {
struct EncodedList _;
_.count = (packed & INTEGER_COUNT_MASK) >> 24;
_.index = (packed & INTEGER_INDEX_MASK);
return _;
}
#define DEFINE_PAIR_ENCODING(TYPE, BITS) \
DEFINE_ENCODING( \
TYPE, uint32_t, \
{ return (packed & PAIR_MASK) == BITS; }, \
{ return BITS | (unpacked & PAIR_INDEX_MASK); }, \
{ return packed & PAIR_INDEX_MASK; } \
)
DEFINE_PAIR_ENCODING(fraction, PAIR_FRACTION_BITS)
DEFINE_PAIR_ENCODING(power, PAIR_POWER_BITS)
#define DEFINE_LIST_ENCODING(TYPE, BITS) \
DEFINE_ENCODING( \
TYPE, struct EncodedList, \
{ return (packed & LIST_MASK) == BITS; }, \
{ return BITS | (unpacked.count << 24) | unpacked.index; }, \
{ struct EncodedList _; _.count = (packed & LIST_COUNT_MASK) >> 24; _.index = (packed & LIST_INDEX_MASK); return _; } \
)
DEFINE_LIST_ENCODING(sum, LIST_SUM_BITS)
DEFINE_LIST_ENCODING(product, LIST_PRODUCT_BITS)
DEFINE_PAIR_ENCODING(equals, PAIR_EQUAL_BITS)
DEFINE_PAIR_ENCODING(not_equals, PAIR_NOT_EQUAL_BITS)
DEFINE_PAIR_ENCODING(less_than, PAIR_LESS_THAN_BITS)
DEFINE_PAIR_ENCODING(greater_than, PAIR_GREATER_THAN_BITS)
enum Tag {
Tag_Real,
Tag_Variable,
Tag_Boolean, // atom 0 and 1
Tag_Undefined, // atom 2
Tag_SmallInt,
Tag_LargeInt,
Tag_Fraction,
Tag_Power,
Tag_Sum,
Tag_Product,
Tag_Equals,
Tag_NotEquals,
Tag_LessThan,
Tag_GreaterThan,
Tag_Invalid
};
static enum Tag get_tag(uint64_t bits) {
if(is_real(bits)) {
return Tag_Real;
} else if(is_variable(bits)) {
return Tag_Variable;
} else if(is_boolean(bits)) {
return Tag_Boolean;
} else if(is_undefined(bits)) {
return Tag_Undefined;
} else if(is_smallint(bits)) {
return Tag_SmallInt;
} else if(is_fraction(bits)) {
return Tag_Fraction;
} else if(is_power(bits)) {
return Tag_Power;
} else if(is_equals(bits)) {
return Tag_Equals;
} else if(is_not_equals(bits)) {
return Tag_NotEquals;
} else if(is_less_than(bits)) {
return Tag_LessThan;
} else if(is_greater_than(bits)) {
return Tag_GreaterThan;
} else if(is_sum(bits)) {
return Tag_Sum;
} else if(is_product(bits)) {
return Tag_Product;
} else {
return Tag_Invalid;
}
}
#undef DEFINE_LIST_ENCODING
#undef DEFINE_PAIR_ENCODING
#undef DEFINE_ENCODING