root/software/fixed/int128.h @ b1d8e8c9
| 7fa2f28e | David Sorber | #ifndef __INT128_H_
|
||
#define __INT128_H_
|
||||
#include <cctype>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
// NOTE: These 128 bit types are GCC specific; see:
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html
|
||||
typedef __int128 int128_t;
|
||||
typedef unsigned __int128 uint128_t;
|
||||
| 495f615f | David Sorber | std::ostream& operator<<(std::ostream& dest, uint128_t value);
|
||
| 7fa2f28e | David Sorber | |||
| 495f615f | David Sorber | std::ostream& operator<<(std::ostream& dest, int128_t value);
|
||
| 7fa2f28e | David Sorber | |||
constexpr uint128_t max_tab[]
|
||||
{
|
||||
std::numeric_limits<uint128_t>::max() / 2,
|
||||
std::numeric_limits<uint128_t>::max() / 3,
|
||||
std::numeric_limits<uint128_t>::max() / 4,
|
||||
std::numeric_limits<uint128_t>::max() / 5,
|
||||
std::numeric_limits<uint128_t>::max() / 6,
|
||||
std::numeric_limits<uint128_t>::max() / 7,
|
||||
std::numeric_limits<uint128_t>::max() / 8,
|
||||
std::numeric_limits<uint128_t>::max() / 9,
|
||||
| c7e0510c | David Sorber | std::numeric_limits<uint128_t>::max() / 10,
|
||
| 7fa2f28e | David Sorber | std::numeric_limits<uint128_t>::max() / 11,
|
||
std::numeric_limits<uint128_t>::max() / 12,
|
||||
std::numeric_limits<uint128_t>::max() / 13,
|
||||
std::numeric_limits<uint128_t>::max() / 14,
|
||||
std::numeric_limits<uint128_t>::max() / 15,
|
||||
std::numeric_limits<uint128_t>::max() / 16,
|
||||
std::numeric_limits<uint128_t>::max() / 17,
|
||||
std::numeric_limits<uint128_t>::max() / 18,
|
||||
std::numeric_limits<uint128_t>::max() / 19,
|
||||
std::numeric_limits<uint128_t>::max() / 20,
|
||||
std::numeric_limits<uint128_t>::max() / 21,
|
||||
std::numeric_limits<uint128_t>::max() / 22,
|
||||
std::numeric_limits<uint128_t>::max() / 23,
|
||||
std::numeric_limits<uint128_t>::max() / 24,
|
||||
std::numeric_limits<uint128_t>::max() / 25,
|
||||
std::numeric_limits<uint128_t>::max() / 26,
|
||||
std::numeric_limits<uint128_t>::max() / 27,
|
||||
std::numeric_limits<uint128_t>::max() / 28,
|
||||
std::numeric_limits<uint128_t>::max() / 29,
|
||||
std::numeric_limits<uint128_t>::max() / 31,
|
||||
std::numeric_limits<uint128_t>::max() / 32,
|
||||
std::numeric_limits<uint128_t>::max() / 33,
|
||||
std::numeric_limits<uint128_t>::max() / 34,
|
||||
std::numeric_limits<uint128_t>::max() / 35,
|
||||
| 495f615f | David Sorber | std::numeric_limits<uint128_t>::max() / 36,
|
||
std::numeric_limits<uint128_t>::max() / 37,
|
||||
std::numeric_limits<uint128_t>::max() / 38
|
||||
| 7fa2f28e | David Sorber | };
|
||
constexpr uint32_t rem_tab[]
|
||||
{
|
||||
std::numeric_limits<uint128_t>::max() % 2,
|
||||
std::numeric_limits<uint128_t>::max() % 3,
|
||||
std::numeric_limits<uint128_t>::max() % 4,
|
||||
std::numeric_limits<uint128_t>::max() % 5,
|
||||
std::numeric_limits<uint128_t>::max() % 6,
|
||||
std::numeric_limits<uint128_t>::max() % 7,
|
||||
std::numeric_limits<uint128_t>::max() % 8,
|
||||
std::numeric_limits<uint128_t>::max() % 9,
|
||||
| c7e0510c | David Sorber | std::numeric_limits<uint128_t>::max() % 10,
|
||
| 7fa2f28e | David Sorber | std::numeric_limits<uint128_t>::max() % 11,
|
||
std::numeric_limits<uint128_t>::max() % 12,
|
||||
std::numeric_limits<uint128_t>::max() % 13,
|
||||
std::numeric_limits<uint128_t>::max() % 14,
|
||||
std::numeric_limits<uint128_t>::max() % 15,
|
||||
std::numeric_limits<uint128_t>::max() % 16,
|
||||
std::numeric_limits<uint128_t>::max() % 17,
|
||||
std::numeric_limits<uint128_t>::max() % 18,
|
||||
std::numeric_limits<uint128_t>::max() % 19,
|
||||
std::numeric_limits<uint128_t>::max() % 20,
|
||||
std::numeric_limits<uint128_t>::max() % 21,
|
||||
std::numeric_limits<uint128_t>::max() % 22,
|
||||
std::numeric_limits<uint128_t>::max() % 23,
|
||||
std::numeric_limits<uint128_t>::max() % 24,
|
||||
std::numeric_limits<uint128_t>::max() % 25,
|
||||
std::numeric_limits<uint128_t>::max() % 26,
|
||||
std::numeric_limits<uint128_t>::max() % 27,
|
||||
std::numeric_limits<uint128_t>::max() % 28,
|
||||
std::numeric_limits<uint128_t>::max() % 29,
|
||||
std::numeric_limits<uint128_t>::max() % 31,
|
||||
std::numeric_limits<uint128_t>::max() % 32,
|
||||
std::numeric_limits<uint128_t>::max() % 33,
|
||||
std::numeric_limits<uint128_t>::max() % 34,
|
||||
std::numeric_limits<uint128_t>::max() % 35,
|
||||
| 495f615f | David Sorber | std::numeric_limits<uint128_t>::max() % 36,
|
||
std::numeric_limits<uint128_t>::max() % 37,
|
||||
std::numeric_limits<uint128_t>::max() % 38
|
||||
| 7fa2f28e | David Sorber | };
|
||
| 495f615f | David Sorber | int128_t strtoll_128(const char* nptr, char** endptr, int base);
|
||
uint128_t strtoull_128(const char* nptr, char** endptr, int base);
|
||||
int128_t strtoll_128_b10opt(const char* nptr, char** endptr, int base=10);
|
||||
uint128_t strtoull_128_b10opt(const char* nptr, char** endptr, int base=10);
|
||||
// Source: https://github.com/jbapple/128-bit-literals/blob/master/suffix128.hpp
|
||||
namespace suffix128 {
|
||||
// Returns the value of the hexadecimal character
|
||||
constexpr unsigned __int128 CharValue(char c) {
|
||||
return (c >= '0' && c <= '9')
|
||||
? (c - '0')
|
||||
: ((c >= 'a' && c <= 'f') ? (10 + (c - 'a')) : (10 + (c - 'A')));
|
||||
| 7fa2f28e | David Sorber | }
|
||
| 495f615f | David Sorber | static constexpr unsigned __int128 MAX128 = ~static_cast<unsigned __int128>(0);
|
||
| 7fa2f28e | David Sorber | |||
| 495f615f | David Sorber | // ValidateU128Helper<BASE, c1, c2, ... , cn>(v) returns true iff cn + ... + c2
|
||
// * BASE^(n-2) + c1 * BASE^(n-1) + v * BASE^n is a valid 128-bit unsigned
|
||||
// number when interpreted in base BASE.
|
||||
template <int BASE>
|
||||
constexpr bool ValidateU128Helper(unsigned __int128) {
|
||||
return true;
|
||||
| 7fa2f28e | David Sorber | }
|
||
| 495f615f | David Sorber | template <int BASE, char C, char... CS>
|
||
constexpr bool ValidateU128Helper(unsigned __int128 accumulate) {
|
||||
return (C == '\'') ? ValidateU128Helper<BASE, CS...>(accumulate)
|
||||
: ((accumulate <= MAX128 / BASE) &&
|
||||
(BASE * accumulate <= MAX128 - CharValue(C)) &&
|
||||
ValidateU128Helper<BASE, CS...>(accumulate * BASE +
|
||||
CharValue(C)));
|
||||
}
|
||||
| c7e0510c | David Sorber | |||
| 495f615f | David Sorber | // ValidateU128<BASE, c1, c2, ... , cn>(v) returns true iff cn + ... + c2 *
|
||
// BASE^(n-2) + c1 * BASE^(n-1) is a valid 128-bit unsigned number when
|
||||
// interpreted in base BASE.
|
||||
template <int BASE, char... CS>
|
||||
constexpr bool ValidateU128() {
|
||||
return ValidateU128Helper<BASE, CS...>(0);
|
||||
| c7e0510c | David Sorber | }
|
||
| 495f615f | David Sorber | // MakeU128Helper<BASE, c1, c2, ... , cn>(v) returns cn + ... + c2 *
|
||
// BASE^(n-2) + c1 * BASE^(n-1) + result * BASE^n.
|
||||
template <int BASE>
|
||||
constexpr unsigned __int128 MakeU128Helper(unsigned __int128 result) {
|
||||
return result;
|
||||
}
|
||||
| c7e0510c | David Sorber | |||
| 495f615f | David Sorber | template <int BASE, char C, char... CS>
|
||
constexpr unsigned __int128 MakeU128Helper(unsigned __int128 result) {
|
||||
return MakeU128Helper<BASE, CS...>(
|
||||
(C == '\'') ? result : (result * BASE + CharValue(C)));
|
||||
}
|
||||
// MakeU128<BASE, c1, c2, ... , cn>(v) returns cn + ... + c2 * BASE^(n-2) + c1 *
|
||||
// BASE^(n-1).
|
||||
template <int BASE, char... CS>
|
||||
constexpr unsigned __int128 MakeU128() {
|
||||
return MakeU128Helper<BASE, CS...>(0);
|
||||
}
|
||||
template <char... CS>
|
||||
struct StaticU128 {
|
||||
static constexpr bool IS_VALID = ValidateU128<10, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<10, CS...>();
|
||||
};
|
||||
template <char... CS>
|
||||
struct StaticU128<'0', 'x', CS...> {
|
||||
static constexpr bool IS_VALID = ValidateU128<16, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<16, CS...>();
|
||||
};
|
||||
template <char... CS>
|
||||
struct StaticU128<'0', 'X', CS...> {
|
||||
static constexpr bool IS_VALID = ValidateU128<16, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<16, CS...>();
|
||||
};
|
||||
template <char... CS>
|
||||
struct StaticU128<'0', 'b', CS...> {
|
||||
static constexpr bool IS_VALID = ValidateU128<2, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<2, CS...>();
|
||||
};
|
||||
template <char... CS>
|
||||
struct StaticU128<'0', 'B', CS...> {
|
||||
static constexpr bool IS_VALID = ValidateU128<2, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<2, CS...>();
|
||||
};
|
||||
template <char... CS>
|
||||
struct StaticU128<'0', CS...> {
|
||||
static constexpr bool IS_VALID = ValidateU128<8, CS...>();
|
||||
static constexpr unsigned __int128 PAYLOAD = MakeU128<8, CS...>();
|
||||
};
|
||||
static constexpr unsigned __int128 SIGNED_LIMIT =
|
||||
(static_cast<unsigned __int128>(1) << 127) - 1;
|
||||
template <char... CS>
|
||||
struct Static128 {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<10, CS...>() && (MakeU128<10, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<10, CS...>());
|
||||
};
|
||||
template <char... CS>
|
||||
struct Static128<'0', 'x', CS...> {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<16, CS...>() && (MakeU128<16, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<16, CS...>());
|
||||
};
|
||||
template <char... CS>
|
||||
struct Static128<'0', 'X', CS...> {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<16, CS...>() && (MakeU128<16, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<16, CS...>());
|
||||
};
|
||||
template <char... CS>
|
||||
struct Static128<'0', 'b', CS...> {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<2, CS...>() && (MakeU128<2, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<2, CS...>());
|
||||
};
|
||||
template <char... CS>
|
||||
struct Static128<'0', 'B', CS...> {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<2, CS...>() && (MakeU128<2, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<2, CS...>());
|
||||
};
|
||||
template <char... CS>
|
||||
struct Static128<'0', CS...> {
|
||||
static constexpr bool IS_VALID =
|
||||
ValidateU128<8, CS...>() && (MakeU128<8, CS...>() <= SIGNED_LIMIT);
|
||||
static constexpr __int128 PAYLOAD =
|
||||
static_cast<__int128>(MakeU128<8, CS...>());
|
||||
};
|
||||
} // namespace suffix128
|
||||
template <char... CS>
|
||||
constexpr unsigned __int128 operator"" _u128() {
|
||||
static_assert(suffix128::StaticU128<CS...>::IS_VALID,
|
||||
"Invalid characters or number too large");
|
||||
return suffix128::StaticU128<CS...>::PAYLOAD;
|
||||
}
|
||||
template <char... CS>
|
||||
constexpr __int128 operator"" _128() {
|
||||
static_assert(suffix128::Static128<CS...>::IS_VALID,
|
||||
"Invalid characters or number too large");
|
||||
return suffix128::Static128<CS...>::PAYLOAD;
|
||||
| c7e0510c | David Sorber | }
|
||
| 7fa2f28e | David Sorber | #endif
|