root/software/fixed/int128.cc @ e6e5f703
| 495f615f | David Sorber | #include "int128.h"
|
|
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, 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;
|
|||
}
|
|||
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 > static_cast<int128_t>(cutoff) ||
|
|||
(value == static_cast<int128_t>(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;
|
|||
}
|
|||
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;
|
|||
}
|
|||
int128_t strtoll_128_b10opt(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 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 > static_cast<int128_t>(cutoff) ||
|
|||
(value == static_cast<int128_t>(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;
|
|||
}
|
|||
uint128_t strtoull_128_b10opt(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 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;
|
|||
}
|