Revision 495f615f
Added by David Sorber about 4 years ago
| software/fixed/int128.h | ||
|---|---|---|
|
typedef unsigned __int128 uint128_t;
|
||
|
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& dest, uint128_t value)
|
||
|
{
|
||
|
std::ostream::sentry check(dest);
|
||
|
if (check)
|
||
|
{
|
||
|
char buffer[128];
|
||
|
char* pos = std::end(buffer);
|
||
|
do
|
||
|
{
|
||
|
--pos;
|
||
|
*pos = "0123456789"[value % 10];
|
||
|
value /= 10;
|
||
|
} while (value != 0);
|
||
|
int len = std::end(buffer) - pos;
|
||
|
if (dest.rdbuf()->sputn(pos, len) != len)
|
||
|
{
|
||
|
dest.setstate(std::ios_base::badbit);
|
||
|
}
|
||
|
}
|
||
|
return dest;
|
||
|
}
|
||
|
std::ostream& operator<<(std::ostream& dest, uint128_t value);
|
||
|
|
||
|
std::ostream& operator<<(std::ostream& dest, int128_t value)
|
||
|
{
|
||
|
std::ostream::sentry check(dest);
|
||
|
if (check)
|
||
|
{
|
||
|
uint128_t tmp = value < 0 ? -value : value;
|
||
|
char buffer[128];
|
||
|
char* pos = std::end(buffer);
|
||
|
do
|
||
|
{
|
||
|
--pos;
|
||
|
*pos = "0123456789"[tmp % 10];
|
||
|
tmp /= 10;
|
||
|
} while (tmp != 0);
|
||
|
if (value < 0)
|
||
|
{
|
||
|
--pos;
|
||
|
*pos = '-';
|
||
|
}
|
||
|
int len = std::end(buffer) - pos;
|
||
|
if (dest.rdbuf()->sputn(pos, len) != len)
|
||
|
{
|
||
|
dest.setstate(std::ios_base::badbit);
|
||
|
}
|
||
|
}
|
||
|
return dest;
|
||
|
}
|
||
|
std::ostream& operator<<(std::ostream& dest, int128_t value);
|
||
|
|
||
|
constexpr uint128_t max_tab[]
|
||
|
{
|
||
| ... | ... | |
|
std::numeric_limits<uint128_t>::max() / 33,
|
||
|
std::numeric_limits<uint128_t>::max() / 34,
|
||
|
std::numeric_limits<uint128_t>::max() / 35,
|
||
|
std::numeric_limits<uint128_t>::max() / 36
|
||
|
std::numeric_limits<uint128_t>::max() / 36,
|
||
|
std::numeric_limits<uint128_t>::max() / 37,
|
||
|
std::numeric_limits<uint128_t>::max() / 38
|
||
|
};
|
||
|
|
||
|
constexpr uint32_t rem_tab[]
|
||
| ... | ... | |
|
std::numeric_limits<uint128_t>::max() % 33,
|
||
|
std::numeric_limits<uint128_t>::max() % 34,
|
||
|
std::numeric_limits<uint128_t>::max() % 35,
|
||
|
std::numeric_limits<uint128_t>::max() % 36
|
||
|
std::numeric_limits<uint128_t>::max() % 36,
|
||
|
std::numeric_limits<uint128_t>::max() % 37,
|
||
|
std::numeric_limits<uint128_t>::max() % 38
|
||
|
};
|
||
|
|
||
|
int128_t strtoll_128(const char* nptr, char** endptr, int base)
|
||
|
{
|
||
|
bool negative = false;
|
||
|
uint128_t cutoff = 0;
|
||
|
uint32_t cutlim = 0;
|
||
|
int128_t value = 0;
|
||
|
const char* ptr;
|
||
|
unsigned char chr;
|
||
|
const char *save, *end;
|
||
|
bool overflow = false;
|
||
|
|
||
|
// Validate the base parameter
|
||
|
if (base < 0 || base == 1 || base > 36)
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Base value \"" << base << "\" is invalid; base must be "
|
||
|
<< "between 2-36 (inclusive).";
|
||
|
throw std::out_of_range(msg.str());
|
||
|
}
|
||
|
|
||
|
save = ptr = nptr;
|
||
|
|
||
|
// Skip any leading whitespace
|
||
|
while (std::isspace(*ptr))
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Check for end of string
|
||
|
if (__builtin_expect((*ptr == '\0'), 0))
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Parse -/+
|
||
|
if (*ptr == '-')
|
||
|
{
|
||
|
negative = true;
|
||
|
++ptr;
|
||
|
}
|
||
|
else if (*ptr == '+')
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Auto detect/validate base
|
||
|
if (*ptr == '0')
|
||
|
{
|
||
|
if ((base == 0 || base == 16) && std::toupper(ptr[1])== 'X')
|
||
|
{
|
||
|
ptr += 2;
|
||
|
base = 16;
|
||
|
}
|
||
|
else if (base == 0)
|
||
|
{
|
||
|
base = 8;
|
||
|
}
|
||
|
}
|
||
|
else if (base == 0)
|
||
|
{
|
||
|
base = 10;
|
||
|
}
|
||
|
|
||
|
// Save start of digits
|
||
|
save = ptr;
|
||
|
end = nullptr;
|
||
|
|
||
|
cutoff = max_tab[base - 2];;
|
||
|
cutlim = rem_tab[base - 2];
|
||
|
|
||
|
// Iterate over the characters
|
||
|
chr = *ptr;
|
||
|
for (; chr != '\0'; chr = *++ptr)
|
||
|
{
|
||
|
if (ptr == end)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (chr >= '0' && chr <= '9')
|
||
|
{
|
||
|
chr -= '0';
|
||
|
}
|
||
|
else if (std::isalpha(chr))
|
||
|
{
|
||
|
chr = std::toupper(chr) - 'A' + 10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (static_cast<int>(chr) >= base)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (value > cutoff || (value == cutoff && chr > cutlim))
|
||
|
{
|
||
|
overflow = true;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
value *= static_cast<uint128_t>(base);
|
||
|
value += (int)chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if no conversion was done
|
||
|
if (ptr == save)
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Store end if requested
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(ptr);
|
||
|
}
|
||
|
|
||
|
// Check for overflow
|
||
|
if (__builtin_expect((overflow), 0))
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Overflow detected at input offset " << (ptr - nptr);
|
||
|
throw std::overflow_error(msg.str());
|
||
|
}
|
||
|
|
||
|
// Regular return path
|
||
|
return negative ? -value : value;
|
||
|
|
||
|
noconv:
|
||
|
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
if (save - nptr >= 2 && std::toupper(save[-1]) == 'X' && save[-2] == '0')
|
||
|
{
|
||
|
*endptr = const_cast<char*>(&save[-1]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*endptr = const_cast<char*>(nptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
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')));
|
||
|
}
|
||
|
|
||
|
static constexpr unsigned __int128 MAX128 = ~static_cast<unsigned __int128>(0);
|
||
|
|
||
|
uint128_t strtoull_128(const char* nptr, char** endptr, int base)
|
||
|
{
|
||
|
uint128_t cutoff = 0;
|
||
|
uint32_t cutlim = 0;
|
||
|
uint128_t value = 0;
|
||
|
const char* ptr;
|
||
|
unsigned char chr;
|
||
|
const char *save, *end;
|
||
|
bool overflow = false;
|
||
|
|
||
|
// Validate the base parameter
|
||
|
if (base < 0 || base == 1 || base > 36)
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Base value \"" << base << "\" is invalid; base must be "
|
||
|
<< "between 2-36 (inclusive).";
|
||
|
throw std::out_of_range(msg.str());
|
||
|
}
|
||
|
|
||
|
save = ptr = nptr;
|
||
|
|
||
|
// Skip any leading whitespace
|
||
|
while (std::isspace(*ptr))
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Check for end of string
|
||
|
if (__builtin_expect((*ptr == '\0'), 0))
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Parse -/+
|
||
|
if (*ptr == '-' || *ptr == '+')
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Auto detect/validate base
|
||
|
if (*ptr == '0')
|
||
|
{
|
||
|
if ((base == 0 || base == 16) && std::toupper(ptr[1])== 'X')
|
||
|
{
|
||
|
ptr += 2;
|
||
|
base = 16;
|
||
|
}
|
||
|
else if (base == 0)
|
||
|
{
|
||
|
base = 8;
|
||
|
}
|
||
|
}
|
||
|
else if (base == 0)
|
||
|
{
|
||
|
base = 10;
|
||
|
}
|
||
|
|
||
|
// Save start of digits
|
||
|
save = ptr;
|
||
|
end = nullptr;
|
||
|
|
||
|
cutoff = max_tab[base - 2];;
|
||
|
cutlim = rem_tab[base - 2];
|
||
|
|
||
|
// Iterate over the characters
|
||
|
chr = *ptr;
|
||
|
for (; chr != '\0'; chr = *++ptr)
|
||
|
{
|
||
|
if (ptr == end)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (chr >= '0' && chr <= '9')
|
||
|
{
|
||
|
chr -= '0';
|
||
|
}
|
||
|
else if (std::isalpha(chr))
|
||
|
{
|
||
|
chr = std::toupper(chr) - 'A' + 10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (static_cast<int>(chr) >= base)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (value > cutoff || (value == cutoff && chr > cutlim))
|
||
|
{
|
||
|
overflow = true;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
value *= static_cast<uint128_t>(base);
|
||
|
value += (int)chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if no conversion was done
|
||
|
if (ptr == save)
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Store end if requested
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(ptr);
|
||
|
}
|
||
|
|
||
|
// Check for overflow
|
||
|
if (__builtin_expect((overflow), 0))
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Overflow detected at input offset " << (ptr - nptr);
|
||
|
throw std::overflow_error(msg.str());
|
||
|
}
|
||
|
|
||
|
// Regular return path
|
||
|
return value;
|
||
|
|
||
|
noconv:
|
||
|
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
if (save - nptr >= 2 && std::toupper(save[-1]) == 'X' && save[-2] == '0')
|
||
|
{
|
||
|
*endptr = const_cast<char*>(&save[-1]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*endptr = const_cast<char*>(nptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
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)));
|
||
|
}
|
||
|
|
||
|
int128_t strtoll_128_b10opt(const char* nptr, char** endptr, int base=10)
|
||
|
{
|
||
|
bool negative = false;
|
||
|
uint128_t cutoff = 0;
|
||
|
uint32_t cutlim = 0;
|
||
|
int128_t value = 0;
|
||
|
const char* ptr;
|
||
|
unsigned char chr;
|
||
|
const char *save, *end;
|
||
|
bool overflow = false;
|
||
|
|
||
|
// Validate the base parameter
|
||
|
#if 0
|
||
|
if (base < 0 || base == 1 || base > 36)
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Base value \"" << base << "\" is invalid; base must be "
|
||
|
<< "between 2-36 (inclusive).";
|
||
|
throw std::out_of_range(msg.str());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
save = ptr = nptr;
|
||
|
|
||
|
// Skip any leading whitespace
|
||
|
while (std::isspace(*ptr))
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Check for end of string
|
||
|
if (__builtin_expect((*ptr == '\0'), 0))
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Parse -/+
|
||
|
if (*ptr == '-')
|
||
|
{
|
||
|
negative = true;
|
||
|
++ptr;
|
||
|
}
|
||
|
else if (*ptr == '+')
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Save start of digits
|
||
|
save = ptr;
|
||
|
end = nullptr;
|
||
|
|
||
|
cutoff = max_tab[8]; // base 10
|
||
|
cutlim = rem_tab[8];
|
||
|
|
||
|
// Iterate over the characters
|
||
|
chr = *ptr;
|
||
|
for (; chr != '\0'; chr = *++ptr)
|
||
|
{
|
||
|
if (ptr == end)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (chr >= '0' && chr <= '9')
|
||
|
{
|
||
|
chr -= '0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (value > cutoff || (value == cutoff && chr > cutlim))
|
||
|
{
|
||
|
overflow = true;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
value *= static_cast<uint128_t>(10);
|
||
|
value += (int)chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if no conversion was done
|
||
|
if (ptr == save)
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Store end if requested
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(ptr);
|
||
|
}
|
||
|
|
||
|
// Check for overflow
|
||
|
if (__builtin_expect((overflow), 0))
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Overflow detected at input offset " << (ptr - nptr);
|
||
|
throw std::overflow_error(msg.str());
|
||
|
}
|
||
|
|
||
|
// Regular return path
|
||
|
return negative ? -value : value;
|
||
|
|
||
|
noconv:
|
||
|
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(nptr);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
// 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);
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
uint128_t strtoull_128_b10opt(const char* nptr, char** endptr, int base=10)
|
||
|
{
|
||
|
uint128_t cutoff = 0;
|
||
|
uint32_t cutlim = 0;
|
||
|
uint128_t value = 0;
|
||
|
const char* ptr;
|
||
|
unsigned char chr;
|
||
|
const char *save, *end;
|
||
|
bool overflow = false;
|
||
|
|
||
|
// Validate the base parameter
|
||
|
#if 0
|
||
|
if (base < 0 || base == 1 || base > 36)
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Base value \"" << base << "\" is invalid; base must be "
|
||
|
<< "between 2-36 (inclusive).";
|
||
|
throw std::out_of_range(msg.str());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
save = ptr = nptr;
|
||
|
|
||
|
// Skip any leading whitespace
|
||
|
while (std::isspace(*ptr))
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Check for end of string
|
||
|
if (__builtin_expect((*ptr == '\0'), 0))
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Parse -/+
|
||
|
if (*ptr == '-' || *ptr == '+')
|
||
|
{
|
||
|
++ptr;
|
||
|
}
|
||
|
|
||
|
// Save start of digits
|
||
|
save = ptr;
|
||
|
end = nullptr;
|
||
|
|
||
|
cutoff = max_tab[8]; // base 10
|
||
|
cutlim = rem_tab[8];
|
||
|
|
||
|
// Iterate over the characters
|
||
|
chr = *ptr;
|
||
|
for (; chr != '\0'; chr = *++ptr)
|
||
|
{
|
||
|
if (ptr == end)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (chr >= '0' && chr <= '9')
|
||
|
{
|
||
|
chr -= '0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (value > cutoff || (value == cutoff && chr > cutlim))
|
||
|
{
|
||
|
overflow = true;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
value *= static_cast<uint128_t>(10);
|
||
|
value += (int)chr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check if no conversion was done
|
||
|
if (ptr == save)
|
||
|
{
|
||
|
goto noconv;
|
||
|
}
|
||
|
|
||
|
// Store end if requested
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(ptr);
|
||
|
}
|
||
|
|
||
|
// Check for overflow
|
||
|
if (__builtin_expect((overflow), 0))
|
||
|
{
|
||
|
std::ostringstream msg;
|
||
|
msg << "Overflow detected at input offset " << (ptr - nptr);
|
||
|
throw std::overflow_error(msg.str());
|
||
|
}
|
||
|
|
||
|
// Regular return path
|
||
|
return value;
|
||
|
|
||
|
noconv:
|
||
|
|
||
|
if (endptr != nullptr)
|
||
|
{
|
||
|
*endptr = const_cast<char*>(nptr);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
Adding combined updates to the fixed point type.