Reduce register pressure and cleanup interface for standard.

This commit is contained in:
IRainman 2025-04-07 23:21:29 +03:00
parent 3faba016af
commit 4f0615b4b4
3 changed files with 56 additions and 53 deletions

View File

@ -260,7 +260,7 @@ enum class parse_error {
}; };
template <typename UC> struct parsed_number_string_t { template <typename UC> struct parsed_number_string_t {
int64_t exponent{0}; int16_t exponent{0};
uint64_t mantissa{0}; uint64_t mantissa{0};
UC const *lastmatch{nullptr}; UC const *lastmatch{nullptr};
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
@ -293,11 +293,11 @@ template <bool basic_json_fmt, typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
parse_number_string(UC const *p, UC const *pend, parse_number_string(UC const *p, UC const *pend,
parse_options_t<UC> const &options) noexcept { parse_options_t<UC> const &options) noexcept {
// V2008 Cyclomatic complexity: 59. // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity
// Consider refactoring the 'parse_number_string' function. // Consider refactoring the 'parse_number_string' function.
// FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this.
parsed_number_string_t<UC> answer; parsed_number_string_t<UC> answer;
FASTFLOAT_ASSUME(p < pend); // assume p < pend, so dereference without checks; FASTFLOAT_ASSUME(p < pend); // so dereference without checks;
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
answer.negative = (*p == UC('-')); answer.negative = (*p == UC('-'));
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
@ -338,7 +338,7 @@ parse_number_string(UC const *p, UC const *pend,
++p; ++p;
} }
UC const *const end_of_integer_part = p; UC const *const end_of_integer_part = p;
int64_t digit_count = int64_t(end_of_integer_part - start_digits); int16_t digit_count = static_cast<int16_t>(end_of_integer_part - start_digits);
answer.integer = span<UC const>(start_digits, size_t(digit_count)); answer.integer = span<UC const>(start_digits, size_t(digit_count));
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) {
@ -353,7 +353,7 @@ parse_number_string(UC const *p, UC const *pend,
} }
#endif #endif
int64_t exponent = 0; int16_t exponent = 0;
bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); bool const has_decimal_point = (p != pend) && (*p == options.decimal_point);
if (has_decimal_point) { if (has_decimal_point) {
++p; ++p;
@ -363,11 +363,11 @@ parse_number_string(UC const *p, UC const *pend,
loop_parse_if_eight_digits(p, pend, i); loop_parse_if_eight_digits(p, pend, i);
while ((p != pend) && is_integer(*p)) { while ((p != pend) && is_integer(*p)) {
uint8_t digit = uint8_t(*p - UC('0')); uint8_t const digit = uint8_t(*p - UC('0'));
++p;
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
++p;
} }
exponent = before - p; exponent = static_cast<int16_t>(before - p);
answer.fraction = span<UC const>(before, size_t(p - before)); answer.fraction = span<UC const>(before, size_t(p - before));
digit_count -= exponent; digit_count -= exponent;
} }
@ -383,19 +383,20 @@ parse_number_string(UC const *p, UC const *pend,
else if (digit_count == 0) { // we must have encountered at least one integer! else if (digit_count == 0) { // we must have encountered at least one integer!
return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa); return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
} }
int64_t exp_number = 0; // explicit exponential part int16_t exp_number = 0; // explicit exponential part
if ((uint64_t(options.format & chars_format::scientific) && (p != pend) && if ((uint64_t(options.format & chars_format::scientific) && (p != pend) &&
((UC('e') == *p) || (UC('E') == *p))) ((UC('e') == *p) || (UC('E') == *p)))
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|| (uint64_t(options.format & detail::basic_fortran_fmt) && || (uint64_t(options.format & chars_format::fortran) &&
((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || ((UC('+') == *p) || (UC('-') == *p)
(UC('D') == *p))) || (UC('d') == *p) || (UC('D') == *p)))
#endif #endif
) { ) {
UC const *location_of_e = p; UC const *location_of_e = p;
if (((UC('e') == *p) || (UC('E') == *p)) if (((UC('e') == *p) || (UC('E') == *p))
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|| (UC('d') == *p) || (UC('D') == *p) || (uint64_t(options.format & chars_format::fortran) &&
((UC('d') == *p) || (UC('D') == *p)))
#endif #endif
) { ) {
++p; ++p;
@ -421,10 +422,8 @@ parse_number_string(UC const *p, UC const *pend,
p = location_of_e; p = location_of_e;
} else { } else {
while ((p != pend) && is_integer(*p)) { while ((p != pend) && is_integer(*p)) {
uint8_t digit = uint8_t(*p - UC('0')); uint8_t const digit = uint8_t(*p - UC('0'));
if (exp_number < 0x10000000) { exp_number = 10 * exp_number + digit;
exp_number = 10 * exp_number + digit;
}
++p; ++p;
} }
if (neg_exp) { if (neg_exp) {
@ -475,7 +474,7 @@ parse_number_string(UC const *p, UC const *pend,
++p; ++p;
} }
if (i >= minimal_nineteen_digit_integer) { // We have a big integers if (i >= minimal_nineteen_digit_integer) { // We have a big integers
exponent = end_of_integer_part - p + exp_number; exponent = static_cast<uint16_t>(end_of_integer_part - p) + exp_number;
} else { // We have a value with a fractional component. } else { // We have a value with a fractional component.
p = answer.fraction.ptr; p = answer.fraction.ptr;
UC const *frac_end = p + answer.fraction.len(); UC const *frac_end = p + answer.fraction.len();
@ -483,7 +482,7 @@ parse_number_string(UC const *p, UC const *pend,
i = i * 10 + uint64_t(*p - UC('0')); i = i * 10 + uint64_t(*p - UC('0'));
++p; ++p;
} }
exponent = answer.fraction.ptr - p + exp_number; exponent = static_cast<uint16_t>(answer.fraction.ptr - p) + exp_number;
} }
// We have now corrected both exponent and i, to a truncated value // We have now corrected both exponent and i, to a truncated value
} }
@ -548,7 +547,7 @@ parse_int_string(UC const *p, UC const *pend, T &value,
p++; p++;
} }
uint8_t const digit_count = size_t(p - start_digits); uint8_t const digit_count = static_cast<uint8_t>(p - start_digits);
if (digit_count == 0) { if (digit_count == 0) {
if (has_leading_zeros) { if (has_leading_zeros) {

View File

@ -39,10 +39,10 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
// effect on performance: in order to have a faster algorithm, we'd need // effect on performance: in order to have a faster algorithm, we'd need
// to slow down performance for faster algorithms, and this is still fast. // to slow down performance for faster algorithms, and this is still fast.
template <typename UC> template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t
scientific_exponent(const parsed_number_string_t<UC> &num) noexcept { scientific_exponent(const parsed_number_string_t<UC> &num) noexcept {
uint64_t mantissa = num.mantissa; uint64_t mantissa = num.mantissa;
int32_t exponent = int32_t(num.exponent); int16_t exponent = num.exponent;
while (mantissa >= 10000) { while (mantissa >= 10000) {
mantissa /= 10000; mantissa /= 10000;
exponent += 4; exponent += 4;
@ -223,8 +223,8 @@ is_truncated(span<UC const> s) noexcept {
template <typename UC> template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
parse_eight_digits(UC const *&p, limb &value, unsigned int &counter, parse_eight_digits(UC const *&p, limb &value, uint16_t &counter,
unsigned int &count) noexcept { uint16_t &count) noexcept {
value = value * 100000000 + parse_eight_digits_unrolled(p); value = value * 100000000 + parse_eight_digits_unrolled(p);
p += 8; p += 8;
counter += 8; counter += 8;
@ -233,8 +233,8 @@ parse_eight_digits(UC const *&p, limb &value, unsigned int &counter,
template <typename UC> template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void
parse_one_digit(UC const *&p, limb &value, unsigned int &counter, parse_one_digit(UC const *&p, limb &value, uint16_t &counter,
unsigned int &count) noexcept { uint16_t &count) noexcept {
value = value * 10 + limb(*p - UC('0')); value = value * 10 + limb(*p - UC('0'));
p++; p++;
counter++; counter++;
@ -248,7 +248,7 @@ add_native(bigint &big, limb power, limb value) noexcept {
} }
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
round_up_bigint(bigint &big, unsigned int &count) noexcept { round_up_bigint(bigint &big, uint16_t &count) noexcept {
// need to round-up the digits, but need to avoid rounding // need to round-up the digits, but need to avoid rounding
// ....9999 to ...10000, which could cause a false halfway point. // ....9999 to ...10000, which could cause a false halfway point.
add_native(big, 10, 1); add_native(big, 10, 1);
@ -259,17 +259,17 @@ round_up_bigint(bigint &big, unsigned int &count) noexcept {
template <typename UC> template <typename UC>
inline FASTFLOAT_CONSTEXPR20 void inline FASTFLOAT_CONSTEXPR20 void
parse_mantissa(bigint &result, const parsed_number_string_t<UC> &num, parse_mantissa(bigint &result, const parsed_number_string_t<UC> &num,
unsigned int max_digits, unsigned int &digits) noexcept { uint16_t const max_digits, uint16_t &digits) noexcept {
// try to minimize the number of big integer and scalar multiplication. // try to minimize the number of big integer and scalar multiplication.
// therefore, try to parse 8 digits at a time, and multiply by the largest // therefore, try to parse 8 digits at a time, and multiply by the largest
// scalar value (9 or 19 digits) for each step. // scalar value (9 or 19 digits) for each step.
unsigned int counter = 0; uint16_t counter = 0;
digits = 0; digits = 0;
limb value = 0; limb value = 0;
#ifdef FASTFLOAT_64BIT_LIMB #ifdef FASTFLOAT_64BIT_LIMB
unsigned int step = 19; uint16_t const step = 19;
#else #else
unsigned int step = 9; uint16_t const step = 9;
#endif #endif
// process all integer digits. // process all integer digits.
@ -370,7 +370,7 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept {
// are of the same magnitude. // are of the same magnitude.
template <typename T> template <typename T>
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
negative_digit_comp(bigint &bigmant, const adjusted_mantissa &am, negative_digit_comp(bigint &bigmant, const adjusted_mantissa am,
const int32_t exponent) noexcept { const int32_t exponent) noexcept {
bigint &real_digits = bigmant; bigint &real_digits = bigmant;
const int32_t &real_exp = exponent; const int32_t &real_exp = exponent;
@ -443,13 +443,13 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp(
// remove the invalid exponent bias // remove the invalid exponent bias
am.power2 -= invalid_am_bias; am.power2 -= invalid_am_bias;
int32_t sci_exp = scientific_exponent(num); int16_t sci_exp = scientific_exponent(num);
unsigned int max_digits = binary_format<T>::max_digits(); uint16_t const max_digits = static_cast<uint16_t>(binary_format<T>::max_digits());
unsigned int digits = 0; uint16_t digits = 0;
bigint bigmant; bigint bigmant;
parse_mantissa(bigmant, num, max_digits, digits); parse_mantissa(bigmant, num, max_digits, digits);
// can't underflow, since digits is at most max_digits. // can't underflow, since digits is at most max_digits.
int32_t exponent = sci_exp + 1 - int32_t(digits); int16_t exponent = sci_exp + 1 - digits;
if (exponent >= 0) { if (exponent >= 0) {
return positive_digit_comp<T>(bigmant, exponent); return positive_digit_comp<T>(bigmant, exponent);
} else { } else {

View File

@ -69,7 +69,7 @@ using from_chars_result = from_chars_result_t<char>;
template <typename UC> struct parse_options_t { template <typename UC> struct parse_options_t {
FASTFLOAT_CONSTEXPR20 explicit parse_options_t( FASTFLOAT_CONSTEXPR20 explicit parse_options_t(
chars_format fmt = chars_format::general, UC dot = UC('.'), chars_format fmt = chars_format::general, UC dot = UC('.'),
const int b = 10) noexcept int const b = 10) noexcept
: format(fmt), decimal_point(dot), base(static_cast<uint8_t>(b)) {} : format(fmt), decimal_point(dot), base(static_cast<uint8_t>(b)) {}
/** Which number formats are accepted */ /** Which number formats are accepted */
@ -427,12 +427,10 @@ struct adjusted_mantissa {
int32_t power2; // a negative value indicates an invalid result int32_t power2; // a negative value indicates an invalid result
adjusted_mantissa() noexcept = default; adjusted_mantissa() noexcept = default;
fastfloat_really_inline
constexpr bool operator==(adjusted_mantissa const &o) const noexcept { constexpr bool operator==(adjusted_mantissa const &o) const noexcept {
return mantissa == o.mantissa && power2 == o.power2; return mantissa == o.mantissa && power2 == o.power2;
} }
fastfloat_really_inline
constexpr bool operator!=(adjusted_mantissa const &o) const noexcept { constexpr bool operator!=(adjusted_mantissa const &o) const noexcept {
return mantissa != o.mantissa || power2 != o.power2; return mantissa != o.mantissa || power2 != o.power2;
} }
@ -449,10 +447,10 @@ template <typename T, typename U = void> struct binary_format_lookup_tables;
template <typename T> struct binary_format : binary_format_lookup_tables<T> { template <typename T> struct binary_format : binary_format_lookup_tables<T> {
using equiv_uint = equiv_uint_t<T>; using equiv_uint = equiv_uint_t<T>;
static constexpr unsigned int mantissa_explicit_bits(); static constexpr int mantissa_explicit_bits();
static constexpr int minimum_exponent(); static constexpr int minimum_exponent();
static constexpr int infinite_power(); static constexpr int infinite_power();
static constexpr unsigned int sign_index(); static constexpr int sign_index();
static constexpr int static constexpr int
min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
static constexpr int max_exponent_fast_path(); static constexpr int max_exponent_fast_path();
@ -464,7 +462,7 @@ template <typename T> struct binary_format : binary_format_lookup_tables<T> {
static constexpr int largest_power_of_ten(); static constexpr int largest_power_of_ten();
static constexpr int smallest_power_of_ten(); static constexpr int smallest_power_of_ten();
static constexpr T exact_power_of_ten(int64_t power); static constexpr T exact_power_of_ten(int64_t power);
static constexpr unsigned int max_digits(); static constexpr size_t max_digits();
static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint exponent_mask();
static constexpr equiv_uint mantissa_mask(); static constexpr equiv_uint mantissa_mask();
static constexpr equiv_uint hidden_bit_mask(); static constexpr equiv_uint hidden_bit_mask();
@ -572,12 +570,12 @@ inline constexpr int binary_format<float>::min_exponent_fast_path() {
} }
template <> template <>
inline constexpr unsigned int binary_format<double>::mantissa_explicit_bits() { inline constexpr int binary_format<double>::mantissa_explicit_bits() {
return 52; return 52;
} }
template <> template <>
inline constexpr unsigned int binary_format<float>::mantissa_explicit_bits() { inline constexpr int binary_format<float>::mantissa_explicit_bits() {
return 23; return 23;
} }
@ -619,11 +617,11 @@ template <> inline constexpr int binary_format<float>::infinite_power() {
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
template <> inline constexpr unsigned int binary_format<double>::sign_index() { template <> inline constexpr int binary_format<double>::sign_index() {
return 63; return 63;
} }
template <> inline constexpr unsigned int binary_format<float>::sign_index() { template <> inline constexpr int binary_format<float>::sign_index() {
return 31; return 31;
} }
@ -708,7 +706,7 @@ inline constexpr int binary_format<std::float16_t>::max_exponent_fast_path() {
} }
template <> template <>
inline constexpr unsigned int binary_format<std::float16_t>::mantissa_explicit_bits() { inline constexpr int binary_format<std::float16_t>::mantissa_explicit_bits() {
return 10; return 10;
} }
@ -835,7 +833,7 @@ binary_format<std::bfloat16_t>::hidden_bit_mask() {
} }
template <> template <>
inline constexpr unsigned int binary_format<std::bfloat16_t>::mantissa_explicit_bits() { inline constexpr int binary_format<std::bfloat16_t>::mantissa_explicit_bits() {
return 7; return 7;
} }
@ -910,7 +908,7 @@ template <>
inline constexpr uint64_t inline constexpr uint64_t
binary_format<double>::max_mantissa_fast_path(int64_t power) { binary_format<double>::max_mantissa_fast_path(int64_t power) {
// caller is responsible to ensure that // caller is responsible to ensure that
// power >= 0 && power <= 22 FASTFLOAT_ASSUME(power >= 0 && power <= 22);
// //
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)max_mantissa[0], max_mantissa[power]; return (void)max_mantissa[0], max_mantissa[power];
@ -920,7 +918,7 @@ template <>
inline constexpr uint64_t inline constexpr uint64_t
binary_format<float>::max_mantissa_fast_path(int64_t power) { binary_format<float>::max_mantissa_fast_path(int64_t power) {
// caller is responsible to ensure that // caller is responsible to ensure that
// power >= 0 && power <= 10 FASTFLOAT_ASSUME(power >= 0 && power <= 10);
// //
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)max_mantissa[0], max_mantissa[power]; return (void)max_mantissa[0], max_mantissa[power];
@ -929,12 +927,18 @@ binary_format<float>::max_mantissa_fast_path(int64_t power) {
template <> template <>
inline constexpr double inline constexpr double
binary_format<double>::exact_power_of_ten(int64_t power) { binary_format<double>::exact_power_of_ten(int64_t power) {
// caller is responsible to ensure that
FASTFLOAT_ASSUME(power >= 0 && power <= 22);
//
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)powers_of_ten[0], powers_of_ten[power]; return (void)powers_of_ten[0], powers_of_ten[power];
} }
template <> template <>
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
// caller is responsible to ensure that
FASTFLOAT_ASSUME(power >= 0 && power <= 10);
//
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)powers_of_ten[0], powers_of_ten[power]; return (void)powers_of_ten[0], powers_of_ten[power];
} }
@ -956,11 +960,11 @@ template <> inline constexpr int binary_format<float>::smallest_power_of_ten() {
return -64; return -64;
} }
template <> inline constexpr unsigned int binary_format<double>::max_digits() { template <> inline constexpr size_t binary_format<double>::max_digits() {
return 769; return 769;
} }
template <> inline constexpr unsigned int binary_format<float>::max_digits() { template <> inline constexpr size_t binary_format<float>::max_digits() {
return 114; return 114;
} }
@ -1005,7 +1009,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float(
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
bool const negative, bool const negative,
#endif #endif
adjusted_mantissa const &am, T &value) noexcept { adjusted_mantissa const am, T &value) noexcept {
using equiv_uint = equiv_uint_t<T>; using equiv_uint = equiv_uint_t<T>;
equiv_uint word = equiv_uint(am.mantissa); equiv_uint word = equiv_uint(am.mantissa);
word = equiv_uint(word | equiv_uint(am.power2) word = equiv_uint(word | equiv_uint(am.power2)