From b0b1954c871b9abf0bbc4f5dce3be5389a3dd35d Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 5 Mar 2025 23:21:24 +0300 Subject: [PATCH 001/252] * Added a config macro FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN and FASTFLOAT_DISALLOW_NAN. This both allow to significantly reduce code size and speedup your code when you use fast_float as a part of your parser. --- include/fast_float/ascii_number.h | 16 ++++++++- include/fast_float/digit_comparison.h | 6 +++- include/fast_float/float_common.h | 29 ++++++++++++++-- include/fast_float/parse_number.h | 50 ++++++++++++++++++++++----- 4 files changed, 89 insertions(+), 12 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9001016a..0133c1ad 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -255,7 +255,9 @@ template struct parsed_number_string_t { int64_t exponent{0}; uint64_t mantissa{0}; UC const *lastmatch{nullptr}; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN bool negative{false}; +#endif bool valid{false}; bool too_many_digits{false}; // contains the range of the significant digits @@ -290,6 +292,7 @@ parse_number_string(UC const *p, UC const *pend, answer.valid = false; answer.too_many_digits = false; // assume p < pend, so dereference without checks; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*p == UC('-')) || @@ -314,6 +317,7 @@ parse_number_string(UC const *p, UC const *pend, } } } +#endif UC const *const start_digits = p; uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) @@ -481,6 +485,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const first = p; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN bool const negative = (*p == UC('-')); #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -498,6 +503,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { ++p; } +#endif UC const *const start_num = p; @@ -553,12 +559,17 @@ parse_int_string(UC const *p, UC const *pend, T &value, // check other types overflow if (!std::is_same::value) { - if (i > uint64_t(std::numeric_limits::max()) + uint64_t(negative)) { + if (i > uint64_t(std::numeric_limits::max()) +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + + uint64_t(negative) +#endif + ) { answer.ec = std::errc::result_out_of_range; return answer; } } +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN if (negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -576,8 +587,11 @@ parse_int_string(UC const *p, UC const *pend, T &value, #pragma warning(pop) #endif } else { +#endif value = T(i); +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN } +#endif answer.ec = std::errc(); return answer; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index d7ef3d9a..00b5dba1 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -381,7 +381,11 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( round(am_b, [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); T b; - to_float(false, am_b, b); + to_float( +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + false, +#endif + am_b, b); adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); int32_t theor_exp = theor.power2; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2d2afcab..fe69bf4e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -51,8 +51,10 @@ enum class chars_format : uint64_t { json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, general = fixed | scientific, +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN allow_leading_plus = 1 << 7, skip_white_space = 1 << 8, +#endif }; template struct from_chars_result_t { @@ -606,6 +608,8 @@ template <> inline constexpr int binary_format::infinite_power() { return 0xFF; } +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + template <> inline constexpr int binary_format::sign_index() { return 63; } @@ -614,6 +618,8 @@ template <> inline constexpr int binary_format::sign_index() { return 31; } +#endif + template <> inline constexpr int binary_format::max_exponent_fast_path() { return 22; @@ -979,13 +985,19 @@ binary_format::hidden_bit_mask() { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -to_float(bool negative, adjusted_mantissa am, T &value) { +to_float( +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + bool negative, +#endif + adjusted_mantissa am, T &value) { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) << binary_format::mantissa_explicit_bits()); +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN word = equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); +#endif #if FASTFLOAT_HAS_BIT_CAST value = std::bit_cast(word); #else @@ -993,6 +1005,8 @@ to_float(bool negative, adjusted_mantissa am, T &value) { #endif } +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + template struct space_lut { static constexpr bool value[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1018,6 +1032,8 @@ template constexpr bool is_space(UC c) { return c < 256 && space_lut<>::value[uint8_t(c)]; } +#endif + template static constexpr uint64_t int_cmp_zeros() { static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size"); @@ -1032,6 +1048,8 @@ template static constexpr int int_cmp_len() { return sizeof(uint64_t) / sizeof(UC); } +#ifndef FASTFLOAT_DISALLOW_NAN + template constexpr UC const *str_const_nan(); template <> constexpr char const *str_const_nan() { return "nan"; } @@ -1052,6 +1070,8 @@ template <> constexpr char8_t const *str_const_nan() { } #endif +#endif + template constexpr UC const *str_const_inf(); template <> constexpr char const *str_const_inf() { return "infinity"; } @@ -1223,7 +1243,12 @@ operator^=(chars_format &lhs, chars_format rhs) noexcept { namespace detail { // adjust for deprecated feature macros -constexpr chars_format adjust_for_feature_macros(chars_format fmt) { +fastfloat_really_inline constexpr chars_format adjust_for_feature_macros(chars_format fmt) { +#if defined(FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN) && \ + (defined(FASTFLOAT_ALLOWS_LEADING_PLUS) || \ + defined(FASTFLOAT_SKIP_WHITE_SPACE)) +#error "FASTFLOAT_ALLOWS_LEADING_PLUS and FASTFLOAT_SKIP_WHITE_SPACE require FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN to be undefined" +#endif return fmt #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS | chars_format::allow_leading_plus diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 0dbb3a14..1c45bcca 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -22,11 +22,16 @@ namespace detail { template from_chars_result_t FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, - T &value, chars_format fmt) noexcept { + T &value +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + , chars_format fmt +#endif + ) noexcept { from_chars_result_t answer{}; answer.ptr = first; answer.ec = std::errc(); // be optimistic // assume first < last, so dereference without checks; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*first == UC('-')) || @@ -34,11 +39,16 @@ from_chars_result_t (*first == UC('+')))) { ++first; } +#endif if (last - first >= 3) { +#ifndef FASTFLOAT_DISALLOW_NAN if (fastfloat_strncasecmp(first, str_const_nan(), 3)) { answer.ptr = (first += 3); - value = minusSign ? -std::numeric_limits::quiet_NaN() - : std::numeric_limits::quiet_NaN(); + value = +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + minusSign ? -std::numeric_limits::quiet_NaN() : +#endif + std::numeric_limits::quiet_NaN(); // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan). if (first != last && *first == UC('(')) { @@ -54,6 +64,7 @@ from_chars_result_t } return answer; } +#endif if (fastfloat_strncasecmp(first, str_const_inf(), 3)) { if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf() + 3, 5)) { @@ -61,8 +72,11 @@ from_chars_result_t } else { answer.ptr = first + 3; } - value = minusSign ? -std::numeric_limits::infinity() - : std::numeric_limits::infinity(); + value = +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + minusSign ? -std::numeric_limits::infinity() : +#endif + std::numeric_limits::infinity(); return answer; } } @@ -231,9 +245,11 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { } else { value = value * binary_format::exact_power_of_ten(pns.exponent); } +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN if (pns.negative) { value = -value; } +#endif return answer; } } else { @@ -246,15 +262,21 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { #if defined(__clang__) || defined(FASTFLOAT_32BIT) // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD if (pns.mantissa == 0) { - value = pns.negative ? T(-0.) : T(0.); + value = +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + pns.negative ? T(-0.) : +#endif + T(0.); return answer; } #endif value = T(pns.mantissa) * binary_format::exact_power_of_ten(pns.exponent); +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN if (pns.negative) { value = -value; } +#endif return answer; } } @@ -272,7 +294,11 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { if (am.power2 < 0) { am = digit_comp(pns, am); } - to_float(pns.negative, am, value); + to_float( +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + pns.negative, +#endif + am, value); // Test for over/underflow. if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format::infinite_power()) { @@ -294,11 +320,13 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, chars_format const fmt = detail::adjust_for_feature_macros(options.format); from_chars_result_t answer; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN if (uint64_t(fmt & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } } +#endif if (first == last) { answer.ec = std::errc::invalid_argument; answer.ptr = first; @@ -312,7 +340,11 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, answer.ptr = first; return answer; } else { - return detail::parse_infnan(first, last, value, fmt); + return detail::parse_infnan(first, last, value +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN + , fmt +#endif + ); } } @@ -348,11 +380,13 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, int const base = options.base; from_chars_result_t answer; +#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN if (uint64_t(fmt & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } } +#endif if (first == last || base < 2 || base > 36) { answer.ec = std::errc::invalid_argument; answer.ptr = first; From 63f6abebdf792c4ce6404b295d772655c986c8cb Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 5 Mar 2025 23:21:24 +0300 Subject: [PATCH 002/252] * Added an option disallow_leading_sign and stronger constexpr / consteval, also significantly reduce register pressure by reducing copy of constant data. --- include/fast_float/ascii_number.h | 109 ++++++++++-------- include/fast_float/bigint.h | 20 ++-- include/fast_float/constexpr_feature_detect.h | 2 + include/fast_float/decimal_to_binary.h | 2 +- include/fast_float/digit_comparison.h | 10 +- include/fast_float/float_common.h | 58 +++++----- include/fast_float/parse_number.h | 47 ++++---- 7 files changed, 128 insertions(+), 120 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9001016a..ec34a1cb 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -202,7 +202,7 @@ template template ()) = 0> #endif // dummy for compile -bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { +FASTFLOAT_CONSTEVAL20 bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { return 0; } @@ -269,7 +269,7 @@ using parsed_number_string = parsed_number_string_t; template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t -report_parse_error(UC const *p, parse_error error) { +report_parse_error(UC const *p, parse_error error) noexcept { parsed_number_string_t answer; answer.valid = false; answer.lastmatch = p; @@ -282,38 +282,41 @@ report_parse_error(UC const *p, parse_error error) { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, - parse_options_t options) noexcept { - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - UC const decimal_point = options.decimal_point; + const parse_options_t options) noexcept { parsed_number_string_t answer; answer.valid = false; answer.too_many_digits = false; - // assume p < pend, so dereference without checks; - answer.negative = (*p == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && - !uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) { - ++p; - if (p == pend) { - return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); - } - if (uint64_t(fmt & detail::basic_json_fmt)) { - if (!is_integer(*p)) { // a sign must be followed by an integer - return report_parse_error(p, - parse_error::missing_integer_after_sign); - } - } else { - if (!is_integer(*p) && - (*p != - decimal_point)) { // a sign must be followed by an integer or the dot + [[assume(p < pend)]]; // assume p < pend, so dereference without checks; + if (!uint64_t(options.format & chars_format::disallow_leading_sign)) { + answer.negative = (*p == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*p == UC('-')) || + (uint64_t(options.format & chars_format::allow_leading_plus) && + !uint64_t(options.format & detail::basic_json_fmt) && *p == UC('+'))) { + ++p; + if (p == pend) { return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } + if (uint64_t(options.format & detail::basic_json_fmt)) { + if (!is_integer(*p)) { // a sign must be followed by an integer + return report_parse_error(p, + parse_error::missing_integer_after_sign); + } + } else { + if (!is_integer(*p) && + (*p != + options.decimal_point)) { // a sign must be followed by an integer or the dot + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + } } + } else { + answer.negative = false; } + UC const *const start_digits = p; uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) @@ -329,7 +332,7 @@ parse_number_string(UC const *p, UC const *pend, UC const *const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); - if (uint64_t(fmt & detail::basic_json_fmt)) { + if (uint64_t(options.format & detail::basic_json_fmt)) { // at least 1 digit in integer part, without leading zeros if (digit_count == 0) { return report_parse_error(p, parse_error::no_digits_in_integer_part); @@ -341,7 +344,7 @@ parse_number_string(UC const *p, UC const *pend, } int64_t exponent = 0; - bool const has_decimal_point = (p != pend) && (*p == decimal_point); + bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); if (has_decimal_point) { ++p; UC const *before = p; @@ -358,7 +361,7 @@ parse_number_string(UC const *p, UC const *pend, answer.fraction = span(before, size_t(p - before)); digit_count -= exponent; } - if (uint64_t(fmt & detail::basic_json_fmt)) { + if (uint64_t(options.format & detail::basic_json_fmt)) { // at least 1 digit in fractional part if (has_decimal_point && exponent == 0) { return report_parse_error(p, @@ -369,9 +372,9 @@ parse_number_string(UC const *p, UC const *pend, return report_parse_error(p, parse_error::no_digits_in_mantissa); } int64_t exp_number = 0; // explicit exponential part - if ((uint64_t(fmt & chars_format::scientific) && (p != pend) && + if ((uint64_t(options.format & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) || - (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) && + (uint64_t(options.format & detail::basic_fortran_fmt) && (p != pend) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || (UC('D') == *p)))) { UC const *location_of_e = p; @@ -389,7 +392,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } if ((p == pend) || !is_integer(*p)) { - if (!uint64_t(fmt & chars_format::fixed)) { + if (!uint64_t(options.format & chars_format::fixed)) { // The exponential part is invalid for scientific notation, so it must // be a trailing token for fixed notation. However, fixed notation is // disabled, so report a scientific notation error. @@ -412,8 +415,8 @@ parse_number_string(UC const *p, UC const *pend, } } else { // If it scientific and not fixed, we have to bail out. - if (uint64_t(fmt & chars_format::scientific) && - !uint64_t(fmt & chars_format::fixed)) { + if (uint64_t(options.format & chars_format::scientific) && + !uint64_t(options.format & chars_format::fixed)) { return report_parse_error(p, parse_error::missing_exponential_part); } } @@ -431,7 +434,8 @@ parse_number_string(UC const *p, UC const *pend, // We need to be mindful of the case where we only have zeroes... // E.g., 0.000000000...000. UC const *start = start_digits; - while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { + while ((start != pend) && (*start == UC('0') || + *start == options.decimal_point)) { if (*start == UC('0')) { digit_count--; } @@ -474,29 +478,32 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_int_string(UC const *p, UC const *pend, T &value, parse_options_t options) { - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - int const base = options.base; from_chars_result_t answer; UC const *const first = p; - bool const negative = (*p == UC('-')); + bool negative; + if (!uint64_t(options.fmt & chars_format::disallow_leading_sign)) { + negative = (*p == UC('-')); #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) #pragma warning(disable : 4127) #endif - if (!std::is_signed::value && negative) { + if (!std::is_signed::value && negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(pop) #endif - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - if ((*p == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { - ++p; + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + if ((*p == UC('-')) || + (uint64_t(options.fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { + ++p; + } + } else { + negative = false; } UC const *const start_num = p; @@ -510,15 +517,15 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_digits = p; uint64_t i = 0; - if (base == 10) { + if (options.base == 10) { loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { - uint8_t digit = ch_to_digit(*p); - if (digit >= base) { + const uint8_t digit = ch_to_digit(*p); + if (digit >= options.base) { break; } - i = uint64_t(base) * i + digit; // might overflow, check this later + i = static_cast(options.base) * i + digit; // might overflow, check this later p++; } @@ -539,14 +546,14 @@ parse_int_string(UC const *p, UC const *pend, T &value, answer.ptr = p; // check u64 overflow - size_t max_digits = max_digits_u64(base); + size_t const max_digits = max_digits_u64(options.base); if (digit_count > max_digits) { answer.ec = std::errc::result_out_of_range; return answer; } // this check can be eliminated for all other types, but they will all require // a max_digits(base) equivalent - if (digit_count == max_digits && i < min_safe_u64(base)) { + if (digit_count == max_digits && i < min_safe_u64(options.base)) { answer.ec = std::errc::result_out_of_range; return answer; } diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 74901e39..e609f69f 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -42,14 +42,14 @@ template struct stackvec { // we never need more than 150 limbs uint16_t length{0}; - stackvec() = default; + FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; stackvec &operator=(stackvec const &) = delete; stackvec(stackvec &&) = delete; stackvec &operator=(stackvec &&other) = delete; // create stack vector from existing limb span. - FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) { + FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) noexcept { FASTFLOAT_ASSERT(try_extend(s)); } @@ -435,14 +435,14 @@ struct bigint : pow5_tables<> { // storage of the limbs, in little-endian order. stackvec vec; - FASTFLOAT_CONSTEXPR20 bigint() : vec() {} + FASTFLOAT_CONSTEXPR20 bigint() noexcept : vec() {} bigint(bigint const &) = delete; bigint &operator=(bigint const &) = delete; bigint(bigint &&) = delete; bigint &operator=(bigint &&other) = delete; - FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() { + FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) noexcept : vec() { #ifdef FASTFLOAT_64BIT_LIMB vec.push_unchecked(value); #else @@ -517,8 +517,8 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - size_t shl = n; - size_t shr = limb_bits - shl; + size_t const shl = n; + size_t const shr = limb_bits - shl; limb prev = 0; for (size_t index = 0; index < vec.len(); index++) { limb xi = vec[index]; @@ -556,8 +556,8 @@ struct bigint : pow5_tables<> { // move the limbs left by `n` bits. FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { - size_t rem = n % limb_bits; - size_t div = n / limb_bits; + size_t const rem = n % limb_bits; + size_t const div = n / limb_bits; if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -598,8 +598,8 @@ struct bigint : pow5_tables<> { // multiply as if by 5 raised to a power. FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { // multiply by a power of 5 - size_t large_length = sizeof(large_power_of_5) / sizeof(limb); - limb_span large = limb_span(large_power_of_5, large_length); + size_t const large_length = sizeof(large_power_of_5) / sizeof(limb); + limb_span const large = limb_span(large_power_of_5, large_length); while (exp >= large_step) { FASTFLOAT_TRY(large_mul(vec, large)); exp -= large_step; diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 648b55d4..26752eea 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -32,9 +32,11 @@ defined(__cpp_lib_constexpr_algorithms) && \ __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ #define FASTFLOAT_CONSTEXPR20 constexpr +#define FASTFLOAT_CONSTEVAL20 consteval #define FASTFLOAT_IS_CONSTEXPR 1 #else #define FASTFLOAT_CONSTEXPR20 +#define FASTFLOAT_CONSTEVAL20 #define FASTFLOAT_IS_CONSTEXPR 0 #endif diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 94876826..94d0a000 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -19,7 +19,7 @@ namespace fast_float { // template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 -compute_product_approximation(int64_t q, uint64_t w) { +compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact // because The line value128 firstproduct = full_multiplication(w, diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index d7ef3d9a..ea8457a2 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -40,7 +40,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, // to slow down performance for faster algorithms, and this is still fast. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t -scientific_exponent(parsed_number_string_t &num) noexcept { +scientific_exponent(const parsed_number_string_t &num) noexcept { uint64_t mantissa = num.mantissa; int32_t exponent = int32_t(num.exponent); while (mantissa >= 10000) { @@ -258,7 +258,7 @@ round_up_bigint(bigint &big, size_t &count) noexcept { // parse the significant digits into a big integer template inline FASTFLOAT_CONSTEXPR20 void -parse_mantissa(bigint &result, parsed_number_string_t &num, +parse_mantissa(bigint &result, const parsed_number_string_t &num, size_t max_digits, size_t &digits) noexcept { // 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 @@ -370,9 +370,9 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { // are of the same magnitude. template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept { + bigint &bigmant, const adjusted_mantissa& am, const int32_t exponent) noexcept { bigint &real_digits = bigmant; - int32_t real_exp = exponent; + const int32_t &real_exp = exponent; // get the value of `b`, rounded down, and get a bigint representation of b+h adjusted_mantissa am_b = am; @@ -434,7 +434,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // of both, and use that to direct rounding. template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -digit_comp(parsed_number_string_t &num, adjusted_mantissa am) noexcept { +digit_comp(const parsed_number_string_t &num, adjusted_mantissa& am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2d2afcab..a08f72d4 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -53,6 +53,7 @@ enum class chars_format : uint64_t { general = fixed | scientific, allow_leading_plus = 1 << 7, skip_white_space = 1 << 8, + disallow_leading_sign = 1 << 9, }; template struct from_chars_result_t { @@ -63,16 +64,24 @@ template struct from_chars_result_t { using from_chars_result = from_chars_result_t; template struct parse_options_t { - constexpr explicit parse_options_t(chars_format fmt = chars_format::general, - UC dot = UC('.'), int b = 10) + FASTFLOAT_CONSTEXPR20 explicit parse_options_t(chars_format fmt = chars_format::general, + UC dot = UC('.'), unsigned char b = 10) noexcept : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ - chars_format format; + const chars_format format + // adjust for deprecated feature macros +#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS + | chars_format::allow_leading_plus +#endif +#ifdef FASTFLOAT_SKIP_WHITE_SPACE + | chars_format::skip_white_space +#endif + ; /** The character used as decimal point */ - UC decimal_point; + const UC decimal_point; /** The base used for integers */ - int base; + const unsigned char base; }; using parse_options = parse_options_t; @@ -212,7 +221,7 @@ using parse_options = parse_options_t; namespace fast_float { -fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { +fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED return std::is_constant_evaluated(); #else @@ -265,7 +274,7 @@ struct is_supported_char_type template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, - size_t length) { + size_t length) noexcept { for (size_t i = 0; i < length; ++i) { UC const actual = actual_mixedcase[i]; if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { @@ -300,9 +309,9 @@ struct value128 { uint64_t low; uint64_t high; - constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} + constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} - constexpr value128() : low(0), high(0) {} + constexpr value128() noexcept : low(0), high(0) {} }; /* Helper C++14 constexpr generic implementation of leading_zeroes */ @@ -336,8 +345,9 @@ leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { /* result might be undefined when input_num is zero */ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int -leading_zeroes(uint64_t input_num) { +leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); + [[assume(input_num > 0)]]; if (cpp20_and_in_constexpr()) { return leading_zeroes_generic(input_num); } @@ -357,12 +367,12 @@ leading_zeroes(uint64_t input_num) { } // slow emulation routine for 32-bit -fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) { +fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) noexcept { return x * (uint64_t)y; } fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t -umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { +umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); @@ -388,7 +398,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, // compute 64-bit a*b fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 -full_multiplication(uint64_t a, uint64_t b) { +full_multiplication(uint64_t a, uint64_t b) noexcept { if (cpp20_and_in_constexpr()) { value128 answer; answer.low = umul128_generic(a, b, &answer.high); @@ -416,13 +426,13 @@ full_multiplication(uint64_t a, uint64_t b) { struct adjusted_mantissa { uint64_t mantissa{0}; int32_t power2{0}; // a negative value indicates an invalid result - adjusted_mantissa() = default; + adjusted_mantissa() noexcept = default; - constexpr bool operator==(adjusted_mantissa const &o) const { + constexpr bool operator==(adjusted_mantissa const &o) const noexcept { return mantissa == o.mantissa && power2 == o.power2; } - constexpr bool operator!=(adjusted_mantissa const &o) const { + constexpr bool operator!=(adjusted_mantissa const &o) const noexcept { return mantissa != o.mantissa || power2 != o.power2; } }; @@ -979,7 +989,7 @@ binary_format::hidden_bit_mask() { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -to_float(bool negative, adjusted_mantissa am, T &value) { +to_float(const bool negative, const adjusted_mantissa am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) @@ -1221,20 +1231,6 @@ operator^=(chars_format &lhs, chars_format rhs) noexcept { return lhs = (lhs ^ rhs); } -namespace detail { -// adjust for deprecated feature macros -constexpr chars_format adjust_for_feature_macros(chars_format fmt) { - return fmt -#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS - | chars_format::allow_leading_plus -#endif -#ifdef FASTFLOAT_SKIP_WHITE_SPACE - | chars_format::skip_white_space -#endif - ; -} -} // namespace detail - } // namespace fast_float #endif diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 0dbb3a14..041bede5 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -22,18 +22,26 @@ namespace detail { template from_chars_result_t FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, - T &value, chars_format fmt) noexcept { + T &value, const chars_format fmt) noexcept { from_chars_result_t answer{}; answer.ptr = first; answer.ec = std::errc(); // be optimistic - // assume first < last, so dereference without checks; - bool const minusSign = (*first == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*first == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && - (*first == UC('+')))) { - ++first; + [[assume(first < last)]]; // so dereference without checks + + bool minusSign; + if (!uint64_t(fmt & chars_format::disallow_leading_sign)) { + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + minusSign = (*first == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*first == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + (*first == UC('+')))) { + ++first; + } + } else { + minusSign = false; } + if (last - first >= 3) { if (fastfloat_strncasecmp(first, str_const_nan(), 3)) { answer.ptr = (first += 3); @@ -284,17 +292,15 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + const parse_options_t options) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - from_chars_result_t answer; - if (uint64_t(fmt & chars_format::skip_white_space)) { + if (uint64_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } @@ -307,12 +313,12 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, parsed_number_string_t pns = parse_number_string(first, last, options); if (!pns.valid) { - if (uint64_t(fmt & chars_format::no_infnan)) { + if (uint64_t(options.format & chars_format::no_infnan)) { answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } else { - return detail::parse_infnan(first, last, value, fmt); + return detail::parse_infnan(first, last, value, options.format); } } @@ -344,16 +350,13 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - chars_format const fmt = detail::adjust_for_feature_macros(options.format); - int const base = options.base; - from_chars_result_t answer; - if (uint64_t(fmt & chars_format::skip_white_space)) { + if (uint64_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } } - if (first == last || base < 2 || base > 36) { + if (first == last || options.base < 2 || options.base > 36) { answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; @@ -370,7 +373,7 @@ template <> struct from_chars_advanced_caller<1> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + const parse_options_t options) noexcept { return from_chars_float_advanced(first, last, value, options); } }; @@ -379,7 +382,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + const parse_options_t options) noexcept { return from_chars_int_advanced(first, last, value, options); } }; @@ -387,7 +390,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + const parse_options_t options) noexcept { return from_chars_advanced_caller< size_t(is_supported_float_type::value) + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, From 28795646abddf2637b06fb79747f59d34332e810 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 6 Mar 2025 19:43:47 +0300 Subject: [PATCH 003/252] more const --- include/fast_float/parse_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 041bede5..f3b06195 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -203,7 +203,7 @@ from_chars(UC const *first, UC const *last, T &value, */ template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { +from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); From 9ebac23081ee5bca04c1e73ce454b686a2653473 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 6 Mar 2025 22:25:05 +0300 Subject: [PATCH 004/252] Added a config option FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN for faster and more compact code parsing numbers with input support only positive C/C++ style numbers without nan or inf. That case is very useful in mathematical applications, game development, CSS parsing, embedded code, etc... Additional improve in constant initialization. --- include/fast_float/ascii_number.h | 83 ++++++++++++++++----------- include/fast_float/digit_comparison.h | 6 +- include/fast_float/float_common.h | 36 ++++++++++-- include/fast_float/parse_number.h | 35 ++++++++--- 4 files changed, 113 insertions(+), 47 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index ec34a1cb..4b298b35 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -234,6 +234,7 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend, enum class parse_error { no_error, +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // [JSON-only] The minus sign must be followed by an integer. missing_integer_after_sign, // A sign must be followed by an integer or dot. @@ -245,6 +246,7 @@ enum class parse_error { // [JSON-only] If there is a decimal point, there must be digits in the // fractional part. no_digits_in_fractional_part, +#endif // The mantissa must have at least one digit. no_digits_in_mantissa, // Scientific notation requires an exponential part. @@ -255,7 +257,9 @@ template struct parsed_number_string_t { int64_t exponent{0}; uint64_t mantissa{0}; UC const *lastmatch{nullptr}; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; +#endif bool valid{false}; bool too_many_digits{false}; // contains the range of the significant digits @@ -288,34 +292,32 @@ parse_number_string(UC const *p, UC const *pend, answer.valid = false; answer.too_many_digits = false; [[assume(p < pend)]]; // assume p < pend, so dereference without checks; - if (!uint64_t(options.format & chars_format::disallow_leading_sign)) { - answer.negative = (*p == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || - (uint64_t(options.format & chars_format::allow_leading_plus) && - !uint64_t(options.format & detail::basic_json_fmt) && *p == UC('+'))) { - ++p; - if (p == pend) { +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + answer.negative = (*p == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*p == UC('-')) || + (uint64_t(options.format & chars_format::allow_leading_plus) && + !uint64_t(options.format & detail::basic_json_fmt) && *p == UC('+'))) { + ++p; + if (p == pend) { + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + if (uint64_t(options.format & detail::basic_json_fmt)) { + if (!is_integer(*p)) { // a sign must be followed by an integer + return report_parse_error(p, + parse_error::missing_integer_after_sign); + } + } else { + if (!is_integer(*p) && + (*p != + options.decimal_point)) { // a sign must be followed by an integer or the dot return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } - if (uint64_t(options.format & detail::basic_json_fmt)) { - if (!is_integer(*p)) { // a sign must be followed by an integer - return report_parse_error(p, - parse_error::missing_integer_after_sign); - } - } else { - if (!is_integer(*p) && - (*p != - options.decimal_point)) { // a sign must be followed by an integer or the dot - return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); - } - } } - } else { - answer.negative = false; } +#endif UC const *const start_digits = p; @@ -332,6 +334,7 @@ parse_number_string(UC const *p, UC const *pend, UC const *const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & detail::basic_json_fmt)) { // at least 1 digit in integer part, without leading zeros if (digit_count == 0) { @@ -342,6 +345,7 @@ parse_number_string(UC const *p, UC const *pend, parse_error::leading_zeros_in_integer_part); } } +#endif int64_t exponent = 0; bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); @@ -361,22 +365,28 @@ parse_number_string(UC const *p, UC const *pend, answer.fraction = span(before, size_t(p - before)); digit_count -= exponent; } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & detail::basic_json_fmt)) { // at least 1 digit in fractional part if (has_decimal_point && exponent == 0) { return report_parse_error(p, parse_error::no_digits_in_fractional_part); } - } else if (digit_count == + } else +#endif + if (digit_count == 0) { // we must have encountered at least one integer! return report_parse_error(p, parse_error::no_digits_in_mantissa); } int64_t exp_number = 0; // explicit exponential part if ((uint64_t(options.format & chars_format::scientific) && (p != pend) && - ((UC('e') == *p) || (UC('E') == *p))) || - (uint64_t(options.format & detail::basic_fortran_fmt) && (p != pend) && + ((UC('e') == *p) || (UC('E') == *p))) +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + || (uint64_t(options.format & detail::basic_fortran_fmt) && (p != pend) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p)))) { + (UC('D') == *p))) +#endif + ) { UC const *location_of_e = p; if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || (UC('D') == *p)) { @@ -483,9 +493,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const first = p; - bool negative; - if (!uint64_t(options.fmt & chars_format::disallow_leading_sign)) { - negative = (*p == UC('-')); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + bool const negative = (*p == UC('-')); #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) #pragma warning(disable : 4127) @@ -502,9 +511,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, (uint64_t(options.fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { ++p; } - } else { - negative = false; - } +#endif UC const *const start_num = p; @@ -560,12 +567,17 @@ parse_int_string(UC const *p, UC const *pend, T &value, // check other types overflow if (!std::is_same::value) { - if (i > uint64_t(std::numeric_limits::max()) + uint64_t(negative)) { + if (i > uint64_t(std::numeric_limits::max()) +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + + uint64_t(negative) +#endif + ) { answer.ec = std::errc::result_out_of_range; return answer; } } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -583,8 +595,11 @@ parse_int_string(UC const *p, UC const *pend, T &value, #pragma warning(pop) #endif } else { +#endif value = T(i); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN } +#endif answer.ec = std::errc(); return answer; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index ea8457a2..a8d4eeca 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -381,7 +381,11 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( round(am_b, [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); T b; - to_float(false, am_b, b); + to_float( +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + false, +#endif + am_b, b); adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); int32_t theor_exp = theor.power2; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index a08f72d4..edcda12c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -35,25 +35,29 @@ namespace fast_float { enum class chars_format : uint64_t; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN namespace detail { constexpr chars_format basic_json_fmt = chars_format(1 << 5); constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); } // namespace detail +#endif enum class chars_format : uint64_t { scientific = 1 << 0, fixed = 1 << 2, + general = fixed | scientific, hex = 1 << 3, +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN no_infnan = 1 << 4, // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 - json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan, + json = uint64_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. - json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, - fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, - general = fixed | scientific, + json_or_infnan = uint64_t(detail::basic_json_fmt) | general, + fortran = uint64_t(detail::basic_fortran_fmt) | general, allow_leading_plus = 1 << 7, skip_white_space = 1 << 8, disallow_leading_sign = 1 << 9, +#endif }; template struct from_chars_result_t { @@ -616,6 +620,8 @@ template <> inline constexpr int binary_format::infinite_power() { return 0xFF; } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + template <> inline constexpr int binary_format::sign_index() { return 63; } @@ -624,6 +630,8 @@ template <> inline constexpr int binary_format::sign_index() { return 31; } +#endif + template <> inline constexpr int binary_format::max_exponent_fast_path() { return 22; @@ -750,10 +758,14 @@ inline constexpr int binary_format::infinite_power() { return 0x1F; } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + template <> inline constexpr int binary_format::sign_index() { return 15; } +#endif + template <> inline constexpr int binary_format::largest_power_of_ten() { return 4; @@ -873,10 +885,14 @@ inline constexpr int binary_format::infinite_power() { return 0xFF; } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + template <> inline constexpr int binary_format::sign_index() { return 15; } +#endif + template <> inline constexpr int binary_format::largest_power_of_ten() { return 38; @@ -989,13 +1005,19 @@ binary_format::hidden_bit_mask() { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -to_float(const bool negative, const adjusted_mantissa am, T &value) noexcept { +to_float( +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + const bool negative, +#endif + const adjusted_mantissa am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) << binary_format::mantissa_explicit_bits()); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN word = equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); +#endif #if FASTFLOAT_HAS_BIT_CAST value = std::bit_cast(word); #else @@ -1042,6 +1064,8 @@ template static constexpr int int_cmp_len() { return sizeof(uint64_t) / sizeof(UC); } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + template constexpr UC const *str_const_nan(); template <> constexpr char const *str_const_nan() { return "nan"; } @@ -1084,6 +1108,8 @@ template <> constexpr char8_t const *str_const_inf() { } #endif +#endif + template struct int_luts { static constexpr uint8_t chdigit[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index f3b06195..02233438 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -14,6 +14,7 @@ namespace fast_float { namespace detail { +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN /** * Special case +inf, -inf, nan, infinity, -infinity. * The case comparisons could be made much faster given that we know that the @@ -77,6 +78,7 @@ from_chars_result_t answer.ec = std::errc::invalid_argument; return answer; } +#endif /** * Returns true if the floating-pointing rounding mode is to 'nearest'. @@ -239,9 +241,11 @@ from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { } else { value = value * binary_format::exact_power_of_ten(pns.exponent); } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (pns.negative) { value = -value; } +#endif return answer; } } else { @@ -254,15 +258,21 @@ from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { #if defined(__clang__) || defined(FASTFLOAT_32BIT) // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD if (pns.mantissa == 0) { - value = pns.negative ? T(-0.) : T(0.); + value = +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + pns.negative ? T(-0.) +#endif + : T(0.); return answer; } #endif value = T(pns.mantissa) * binary_format::exact_power_of_ten(pns.exponent); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (pns.negative) { value = -value; } +#endif return answer; } } @@ -280,7 +290,11 @@ from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { if (am.power2 < 0) { am = digit_comp(pns, am); } - to_float(pns.negative, am, value); + to_float( +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + pns.negative, +#endif + am, value); // Test for over/underflow. if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format::infinite_power()) { @@ -300,26 +314,32 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, "only char, wchar_t, char16_t and char32_t are supported"); from_chars_result_t answer; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } } +#endif if (first == last) { answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } - parsed_number_string_t pns = + parsed_number_string_t const pns = parse_number_string(first, last, options); if (!pns.valid) { +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & chars_format::no_infnan)) { +#endif answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN } else { return detail::parse_infnan(first, last, value, options.format); } +#endif } // call overload that takes parsed_number_string_t directly. @@ -335,28 +355,29 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept { static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - parse_options_t options; - options.base = base; + parse_options_t const options(chars_format::general, UC('.'), base); return from_chars_advanced(first, last, value, options); } template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + const parse_options_t options) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - from_chars_result_t answer; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } } +#endif if (first == last || options.base < 2 || options.base > 36) { + from_chars_result_t answer; answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; From 7a38e1bc7566879a79e6896308d2b48a7dd16a30 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 6 Mar 2025 22:47:47 +0300 Subject: [PATCH 005/252] fix for 32 bit build. completely done. All other parser mode also work fine. --- include/fast_float/parse_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 02233438..e165d178 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -260,9 +260,9 @@ from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { if (pns.mantissa == 0) { value = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - pns.negative ? T(-0.) + pns.negative ? T(-0.) : #endif - : T(0.); + T(0.); return answer; } #endif From bc3f331938da63a16c3573d43b0f36cf32ff53fc Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 6 Mar 2025 23:02:50 +0300 Subject: [PATCH 006/252] # cleanup. --- include/fast_float/float_common.h | 1 - include/fast_float/parse_number.h | 20 +++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index edcda12c..daf770cd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -56,7 +56,6 @@ enum class chars_format : uint64_t { fortran = uint64_t(detail::basic_fortran_fmt) | general, allow_leading_plus = 1 << 7, skip_white_space = 1 << 8, - disallow_leading_sign = 1 << 9, #endif }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index e165d178..0863d000 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -28,19 +28,13 @@ from_chars_result_t answer.ptr = first; answer.ec = std::errc(); // be optimistic [[assume(first < last)]]; // so dereference without checks - - bool minusSign; - if (!uint64_t(fmt & chars_format::disallow_leading_sign)) { - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - minusSign = (*first == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*first == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && - (*first == UC('+')))) { - ++first; - } - } else { - minusSign = false; + + bool const minusSign = (*first == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*first == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + (*first == UC('+')))) { + ++first; } if (last - first >= 3) { From aba93f306f6ec76cbeee472bf53201e4c6b1ac0b Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 7 Mar 2025 14:51:20 +0300 Subject: [PATCH 007/252] Additional compile time cleanup. When FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled we assume that we are in parser code with external loop that checks bounds. Function cpp20_and_in_constexpr() now is really compile time evaluated. TODO fix warnings. --- include/fast_float/ascii_number.h | 1 + include/fast_float/float_common.h | 10 +++++++--- include/fast_float/parse_number.h | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 4b298b35..a17e0354 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -515,6 +515,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_num = p; + // use SIMD if possible while (p != pend && *p == UC('0')) { ++p; } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index daf770cd..9ef2e87e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -68,7 +68,7 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t(chars_format fmt = chars_format::general, - UC dot = UC('.'), unsigned char b = 10) noexcept + UC dot = UC('.'), uint8_t b = 10) noexcept : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ @@ -84,7 +84,7 @@ template struct parse_options_t { /** The character used as decimal point */ const UC decimal_point; /** The base used for integers */ - const unsigned char base; + const uint8_t base; /* only allowed from 2 to 36 */ }; using parse_options = parse_options_t; @@ -224,7 +224,7 @@ using parse_options = parse_options_t; namespace fast_float { -fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEVAL20 bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED return std::is_constant_evaluated(); #else @@ -1024,6 +1024,8 @@ to_float( #endif } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + template struct space_lut { static constexpr bool value[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1049,6 +1051,8 @@ template constexpr bool is_space(UC c) { return c < 256 && space_lut<>::value[uint8_t(c)]; } +#endif + template static constexpr uint64_t int_cmp_zeros() { static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size"); diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 0863d000..47f04e84 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -314,12 +314,15 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, first++; } } -#endif if (first == last) { answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } +#else + // We are in parser code with external loop that checks bounds. + [[assume((first < last))]]; +#endif parsed_number_string_t const pns = parse_number_string(first, last, options); if (!pns.valid) { @@ -369,8 +372,15 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, first++; } } +#else + // We are in parser code with external loop that checks bounds. + [[assume((first < last))]]; +#endif + if ( +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + first == last #endif - if (first == last || options.base < 2 || options.base > 36) { + options.base < 2 || options.base > 36) { from_chars_result_t answer; answer.ec = std::errc::invalid_argument; answer.ptr = first; From 388426e35a0823e0b6920c4b531c5a20d72c6cf5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 7 Mar 2025 15:06:44 +0300 Subject: [PATCH 008/252] fix type conversion warning. --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 9ef2e87e..d2ad2ddb 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -68,8 +68,8 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t(chars_format fmt = chars_format::general, - UC dot = UC('.'), uint8_t b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) {} + UC dot = UC('.'), const int b = 10) noexcept + : format(fmt), decimal_point(dot), base(static_cast(b)) {} /** Which number formats are accepted */ const chars_format format From ae29a0dbe53cf575dfa679336da92962e1482cf1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 7 Mar 2025 20:39:20 +0300 Subject: [PATCH 009/252] PVS-Studio founds some errors, I fixed it. --- include/fast_float/ascii_number.h | 4 ++-- include/fast_float/decimal_to_binary.h | 6 +++--- include/fast_float/fast_float.h | 2 +- include/fast_float/float_common.h | 4 ++-- include/fast_float/parse_number.h | 18 +++++++++--------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a17e0354..c5b93f4c 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -286,7 +286,7 @@ report_parse_error(UC const *p, parse_error error) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { parsed_number_string_t answer; answer.valid = false; @@ -487,7 +487,7 @@ parse_number_string(UC const *p, UC const *pend, template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_int_string(UC const *p, UC const *pend, T &value, - parse_options_t options) { + parse_options_t const &options) noexcept { from_chars_result_t answer; diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 94d0a000..028fbdce 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -103,15 +103,15 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept { adjusted_mantissa answer; if ((w == 0) || (q < binary::smallest_power_of_ten())) { - answer.power2 = 0; - answer.mantissa = 0; + // answer.power2 = 0; already set + // answer.mantissa = 0; already set // result should be zero return answer; } if (q > binary::largest_power_of_ten()) { // we want to get infinity: answer.power2 = binary::infinite_power(); - answer.mantissa = 0; + // answer.mantissa = 0; already set return answer; } // At this point in time q is in [powers::smallest_power_of_five, diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index af65c96b..8dfef020 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -43,7 +43,7 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept; + parse_options_t const &options) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index d2ad2ddb..28c55f74 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1006,9 +1006,9 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - const bool negative, + bool const negative, #endif - const adjusted_mantissa am, T &value) noexcept { + adjusted_mantissa const &am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 47f04e84..017cc9c6 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -145,7 +145,7 @@ template struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t options) noexcept { + parse_options_t const &options) noexcept { return from_chars_advanced(first, last, value, options); } }; @@ -155,7 +155,7 @@ template <> struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, std::float32_t &value, - parse_options_t options) noexcept { + parse_options_t const &options) noexcept { // if std::float32_t is defined, and we are in C++23 mode; macro set for // float32; set value to float due to equivalence between float and // float32_t @@ -172,7 +172,7 @@ template <> struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, std::float64_t &value, - parse_options_t options) noexcept { + parse_options_t const &options) noexcept { // if std::float64_t is defined, and we are in C++23 mode; macro set for // float64; set value as double due to equivalence between double and // float64_t @@ -199,7 +199,7 @@ from_chars(UC const *first, UC const *last, T &value, */ template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { +from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -300,7 +300,7 @@ from_chars_advanced(const parsed_number_string_t &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -359,7 +359,7 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); @@ -398,7 +398,7 @@ template <> struct from_chars_advanced_caller<1> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { return from_chars_float_advanced(first, last, value, options); } }; @@ -407,7 +407,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { return from_chars_int_advanced(first, last, value, options); } }; @@ -415,7 +415,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - const parse_options_t options) noexcept { + parse_options_t const &options) noexcept { return from_chars_advanced_caller< size_t(is_supported_float_type::value) + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, From f496321570c6ad7e12dd309934217b6eb3c30805 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 02:37:46 +0300 Subject: [PATCH 010/252] Completely remove deprecated macroses FASTFLOAT_ALLOWS_LEADING_PLUS and FASTFLOAT_SKIP_WHITE_SPACE, please use options. Compilation fix when FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN isn't defined. --- include/fast_float/float_common.h | 10 +--------- include/fast_float/parse_number.h | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 28c55f74..7f2d002c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -72,15 +72,7 @@ template struct parse_options_t { : format(fmt), decimal_point(dot), base(static_cast(b)) {} /** Which number formats are accepted */ - const chars_format format - // adjust for deprecated feature macros -#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS - | chars_format::allow_leading_plus -#endif -#ifdef FASTFLOAT_SKIP_WHITE_SPACE - | chars_format::skip_white_space -#endif - ; + const chars_format format; /** The character used as decimal point */ const UC decimal_point; /** The base used for integers */ diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 017cc9c6..07986035 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -378,7 +378,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, #endif if ( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - first == last + first == last || #endif options.base < 2 || options.base > 36) { from_chars_result_t answer; From ac22204bcc56ae72a6c9d5bfb3e09119cf2d51f8 Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Sun, 9 Mar 2025 02:40:28 +0300 Subject: [PATCH 011/252] Update README.md Added examples of usage FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN macros and documented allow_leading_plus and skip_white_space options --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.md b/README.md index 3eb540b7..a67ede2e 100644 --- a/README.md +++ b/README.md @@ -357,6 +357,49 @@ int main() { } ``` +You also can use not standard options: + +```C++ +#include "fast_float/fast_float.h" +#include + +int main() { + std::string input = " +456"; + double result; + fast_float::parse_options options{chars_format::allow_leading_plus | chars_format::skip_white_space}; + auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); + if ((answer.ec != std::errc()) || ((result != 456))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } + return EXIT_SUCCESS; +} +``` + +For special case scenarious, like mathematical or other AST like parcer that already process minus sign +and only pasre in FastFloat positive numbers in fixed, scientific or hex format and do not have inf or nan +in input you can use macros FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN that significantly reduce +the code size and improve performance: + +```C++ +#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#include "fast_float/fast_float.h" +#include + +int main() { + std::string input = "23.14069263277926900572"; + double result; + fast_float::parse_options options{chars_format::allow_leading_plus | chars_format::skip_white_space}; + auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); + if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) + { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } + input = "-23.14069263277926900572"; + if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on any sign\n"; return EXIT_FAILURE; } + input = "inf"; + if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on infinity\n"; return EXIT_FAILURE; } + input = "nan"; + if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on nan in input\n"; return EXIT_FAILURE; } + return EXIT_SUCCESS; +} +``` + ## Users and Related Work The fast_float library is part of: From c2daa8a614b2d412d12ae8d289b0ab7019d6989a Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 03:41:27 +0300 Subject: [PATCH 012/252] Added FASTFLOAT_ASSUME for support attribute [[assume]] is declared in P1774 --- include/fast_float/ascii_number.h | 2 +- include/fast_float/constexpr_feature_detect.h | 9 +++++++++ include/fast_float/float_common.h | 2 +- include/fast_float/parse_number.h | 6 +++--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index c5b93f4c..ca47afd4 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -291,7 +291,7 @@ parse_number_string(UC const *p, UC const *pend, parsed_number_string_t answer; answer.valid = false; answer.too_many_digits = false; - [[assume(p < pend)]]; // assume p < pend, so dereference without checks; + FASTFLOAT_ASSUME(p < pend); // assume p < pend, so dereference without checks; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 26752eea..b1d1a8a0 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -46,4 +46,13 @@ #define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 #endif +// For support attribute [[assume]] is declared in P1774 +#if defined(__clang__) +#define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) +#elif defined(__GNUC__) && !defined(__ICC) +#define ASSUME(expr) __attribute__((expr))) +#elif defined(_MSC_VER) || defined(__ICC) +#define FASTFLOAT_ASSUME(expr) __assume(expr) +#endif + #endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7f2d002c..28d86713 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -342,7 +342,7 @@ leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); - [[assume(input_num > 0)]]; + FASTFLOAT_ASSUME(input_num > 0); if (cpp20_and_in_constexpr()) { return leading_zeroes_generic(input_num); } diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 07986035..80eb364b 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -27,7 +27,7 @@ from_chars_result_t from_chars_result_t answer{}; answer.ptr = first; answer.ec = std::errc(); // be optimistic - [[assume(first < last)]]; // so dereference without checks + FASTFLOAT_ASSUME(first < last); // so dereference without checks bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here @@ -321,7 +321,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, } #else // We are in parser code with external loop that checks bounds. - [[assume((first < last))]]; + FASTFLOAT_ASSUME(first < last); #endif parsed_number_string_t const pns = parse_number_string(first, last, options); @@ -374,7 +374,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, } #else // We are in parser code with external loop that checks bounds. - [[assume((first < last))]]; + FASTFLOAT_ASSUME(first < last); #endif if ( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 50972439035aa76c7fb2ee36b1f785e7f4d3823f Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 04:07:29 +0300 Subject: [PATCH 013/252] Fix compilation of benchmarks --- benchmarks/benchmark.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 89246945..53429f13 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,7 +1,7 @@ #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS -#include "event_counter.h" #endif +#include "event_counter.h" #include #include "fast_float/fast_float.h" #include From a22dfc6fcf01f6a47a20c74188a007a7fdec49c4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 19:55:54 +0300 Subject: [PATCH 014/252] benchmark are updated, added AST parser emulation for FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN. Now benchmark only measure parameters for fast_float::from_chars and nothing else. Copy-past fix. --- benchmarks/benchmark.cpp | 120 ++++++++++++++++++++++++++------------- 1 file changed, 80 insertions(+), 40 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 53429f13..83493b9a 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -3,8 +3,6 @@ #endif #include "event_counter.h" #include -#include "fast_float/fast_float.h" -#include #include #include #include @@ -19,30 +17,42 @@ #include #include #include -#include #include -template -double findmax_fastfloat64(std::vector> &s) { - double answer = 0; - double x = 0; - for (auto &st : s) { - auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); - if (p == st.data()) { - throw std::runtime_error("bug in findmax_fastfloat"); - } - answer = answer > x ? answer : x; - } - return answer; -} +#include "fast_float/fast_float.h" -template -double findmax_fastfloat32(std::vector> &s) { - float answer = 0; - float x = 0; +event_collector collector{}; + +std::chrono::high_resolution_clock::time_point t1, t2; + +template +Value findmax_fastfloat(std::vector> &s, +#ifdef USING_COUNTERS + std::vector &aggregate +#else + std::chrono::nanoseconds& time +#endif +) { + Value answer = 0; + Value x = 0; for (auto &st : s) { + +#ifdef USING_COUNTERS + collector.start(); +#else + t1 = std::chrono::high_resolution_clock::now(); +#endif + auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); - if (p == st.data()) { + +#ifdef USING_COUNTERS + aggregate.push_back(collector.end()); +#else + t2 = std::chrono::high_resolution_clock::now(); + time += t2 - t1; +#endif + + if (ec != std::errc{}) { throw std::runtime_error("bug in findmax_fastfloat"); } answer = answer > x ? answer : x; @@ -50,8 +60,6 @@ double findmax_fastfloat32(std::vector> &s) { return answer; } -event_collector collector{}; - #ifdef USING_COUNTERS template std::vector @@ -59,14 +67,12 @@ time_it_ns(std::vector> &lines, T const &function, size_t repeat) { std::vector aggregate; bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { - collector.start(); - double ts = function(lines); + for (size_t i = 0; i < repeat; i++) { + double ts = function(lines, aggregate); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; } - aggregate.push_back(collector.end()); } return aggregate; } @@ -135,20 +141,17 @@ template std::pair time_it_ns(std::vector> &lines, T const &function, size_t repeat) { - std::chrono::high_resolution_clock::time_point t1, t2; double average = 0; double min_value = DBL_MAX; bool printed_bug = false; for (size_t i = 0; i < repeat; i++) { - t1 = std::chrono::high_resolution_clock::now(); - double ts = function(lines); + std::chrono::nanoseconds time{}; + const auto ts = function(lines, time); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; } - t2 = std::chrono::high_resolution_clock::now(); - double dif = - std::chrono::duration_cast(t2 - t1).count(); + double dif = std::chrono::duration_cast(time).count(); average += dif; min_value = min_value < dif ? min_value : dif; } @@ -160,7 +163,7 @@ void pretty_print(double volume, size_t number_of_floats, std::string name, std::pair result) { double volumeMB = volume / (1024. * 1024.); printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), - volumeMB * 1000000000 / result.first, + volumeMB * 1'000'000'000 / result.first, (result.second - result.first) * 100.0 / result.second); printf("%8.2f Mfloat/s ", number_of_floats * 1000 / result.first); printf(" %8.2f ns/f \n", double(result.first) / number_of_floats); @@ -191,18 +194,18 @@ void process(std::vector &lines, size_t volume) { double volumeMB = volume / (1024. * 1024.); std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl; pretty_print(volume, lines.size(), "fastfloat (64)", - time_it_ns(lines, findmax_fastfloat64, repeat)); + time_it_ns(lines, findmax_fastfloat, repeat)); pretty_print(volume, lines.size(), "fastfloat (32)", - time_it_ns(lines, findmax_fastfloat32, repeat)); + time_it_ns(lines, findmax_fastfloat, repeat)); std::vector lines16 = widen(lines); volume = 2 * volume; volumeMB = volume / (1024. * 1024.); std::cout << "UTF-16 volume = " << volumeMB << " MB " << std::endl; pretty_print(volume, lines.size(), "fastfloat (64)", - time_it_ns(lines16, findmax_fastfloat64, repeat)); + time_it_ns(lines16, findmax_fastfloat, repeat)); pretty_print(volume, lines.size(), "fastfloat (32)", - time_it_ns(lines16, findmax_fastfloat32, repeat)); + time_it_ns(lines16, findmax_fastfloat, repeat)); } void fileload(std::string filename) { @@ -219,8 +222,45 @@ void fileload(std::string filename) { lines.reserve(10000); // let us reserve plenty of memory. size_t volume = 0; while (getline(inputfile, line)) { - volume += line.size(); - lines.push_back(line); +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + /* This code is a simple parser emulator */ + for (size_t n = 0; n < line.size(); ++n) { + if ((line[n] >= '0' && line[n] <= '9')) + { + /* in the real parser we don't check anything else + and call the from_chars function immediately */ + const auto s = n; + for (++n; n < line.size() && + ((line[n] >= '0' && line[n] <= '9') || + line[n] == 'e' || line[n] == 'E' || + line[n] == '.' || + line[n] == '-' || line[n] == '+' + /* last line for exponent sign*/ + ); + ++n) + { + + } + /*~ in the real parser we don't check anything else + and call the from_chars function immediately */ + + volume += lines.emplace_back(line.substr(s, n)).size(); + } + else + { + /* for the test we simplify skipped all other symbols, + in real application this should be a full parser, + that parse also any mathematical operations like + and - + and this is the reason why we don't need to check a sign + when FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled. */ + ++n; + continue; + } + } + // in the real parser this part of code should return end token +#else + volume += lines.emplace_back(line).size(); +#endif } std::cout << "# read " << lines.size() << " lines " << std::endl; process(lines, volume); From 354f4c3eac93204ca2c37f9ea5fc64501a240850 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 21:09:51 +0300 Subject: [PATCH 015/252] Compilation fix. --- include/fast_float/constexpr_feature_detect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index b1d1a8a0..6e876c51 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -50,7 +50,7 @@ #if defined(__clang__) #define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) #elif defined(__GNUC__) && !defined(__ICC) -#define ASSUME(expr) __attribute__((expr))) +#define ASSUME(expr) __attribute__((expr)) #elif defined(_MSC_VER) || defined(__ICC) #define FASTFLOAT_ASSUME(expr) __assume(expr) #endif From 63eb578d527536eb63336e7b11d9274bba1c7623 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Mar 2025 22:55:04 +0300 Subject: [PATCH 016/252] Add FASTFLOAT_HAS_BYTESWAP check. Improve FASTFLOAT_CONSTEVAL20 usage for older standards. --- include/fast_float/ascii_number.h | 35 ++++++++++++------- include/fast_float/constexpr_feature_detect.h | 8 ++++- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index ca47afd4..7c2f5fd3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -35,12 +35,14 @@ fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { return !(c > UC('9') || c < UC('0')); } +#if FASTFLOAT_HAS_BYTESWAP == 0 fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 | (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 | (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; } +#endif // Read 8 UC into a u64. Truncates UC if not char. template @@ -58,7 +60,11 @@ read8_to_u64(UC const *chars) { ::memcpy(&val, chars, sizeof(uint64_t)); #if FASTFLOAT_IS_BIG_ENDIAN == 1 // Need to read as-if the number was in little-endian order. - val = byteswap(val); + val = +#if FASTFLOAT_HAS_BYTESWAP == 1 + std:: +#endif + byteswap(val); #endif return val; } @@ -382,24 +388,27 @@ parse_number_string(UC const *p, UC const *pend, if ((uint64_t(options.format & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint64_t(options.format & detail::basic_fortran_fmt) && (p != pend) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) + || (uint64_t(options.format & detail::basic_fortran_fmt) && + ((UC('+') == *p) || (UC('-') == *p) || + (UC('d') == *p) || (UC('D') == *p))) #endif ) { UC const *location_of_e = p; - if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || - (UC('D') == *p)) { + if (((UC('e') == *p) || (UC('E') == *p)) +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + || (UC('d') == *p) || (UC('D') == *p) +#endif + ) { ++p; } bool neg_exp = false; - if ((p != pend) && (UC('-') == *p)) { - neg_exp = true; - ++p; - } else if ((p != pend) && - (UC('+') == - *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) - ++p; + if (p != pend) { + if ( UC('-') == *p) { + neg_exp = true; + ++p; + } else if (UC('+') == *p) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + ++p; + } } if ((p == pend) || !is_integer(*p)) { if (!uint64_t(options.format & chars_format::fixed)) { diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 6e876c51..238c8508 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -27,6 +27,12 @@ #define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 #endif +#if defined(__cpp_lib_byteswap) +#define FASTFLOAT_HAS_BYTESWAP 1 +#else +#define FASTFLOAT_HAS_BYTESWAP 0 +#endif + // Testing for relevant C++20 constexpr library features #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ defined(__cpp_lib_constexpr_algorithms) && \ @@ -36,7 +42,7 @@ #define FASTFLOAT_IS_CONSTEXPR 1 #else #define FASTFLOAT_CONSTEXPR20 -#define FASTFLOAT_CONSTEVAL20 +#define FASTFLOAT_CONSTEVAL20 FASTFLOAT_CONSTEXPR14 #define FASTFLOAT_IS_CONSTEXPR 0 #endif From 6c499fda5c0c575bb615c4805136d7b94ade886b Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Mar 2025 05:34:45 +0300 Subject: [PATCH 017/252] FASTFLOAT_ASSUME review. --- include/fast_float/constexpr_feature_detect.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 238c8508..ca245ed7 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -53,12 +53,16 @@ #endif // For support attribute [[assume]] is declared in P1774 -#if defined(__clang__) +#if defined(__clang__) // needs testing #define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) -#elif defined(__GNUC__) && !defined(__ICC) -#define ASSUME(expr) __attribute__((expr)) -#elif defined(_MSC_VER) || defined(__ICC) +#elif defined(__GNUC__) && !defined(__ICC) // needs testing +#define FASTFLOAT_ASSUME(expr) __attribute__((expr)) +#elif defined(__ICC) // needs testing #define FASTFLOAT_ASSUME(expr) __assume(expr) +#elif defined(_MSC_VER) +/* currently disable, because MSVC is generated slower code when enabled, +it's probably reason why MSVC doesnt have [[assume]] */ +#define FASTFLOAT_ASSUME(expr) /*__assume(expr)*/ #endif #endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H From 3e86e9a18eb59938b922ab5e43a709d5dd826813 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Mar 2025 05:40:27 +0300 Subject: [PATCH 018/252] #### # reading C:/Projects/fast_float/build/benchmarks/data/canada.txt #### # read 111126 lines ASCII volume = 1.82777 MB fastfloat (64) : 233.01 MB/s (+/- 2.0 %) 14.17 Mfloat/s 70.59 ns/f fastfloat (32) : 221.31 MB/s (+/- 1.5 %) 13.46 Mfloat/s 74.32 ns/f UTF-16 volume = 3.65553 MB fastfloat (64) : 460.78 MB/s (+/- 1.4 %) 14.01 Mfloat/s 71.39 ns/f fastfloat (32) : 439.76 MB/s (+/- 2.1 %) 13.37 Mfloat/s 74.80 ns/f #### # reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt #### # read 73019 lines ASCII volume = 0.536009 MB fastfloat (64) : 131.38 MB/s (+/- 0.4 %) 17.90 Mfloat/s 55.87 ns/f fastfloat (32) : 123.03 MB/s (+/- 0.4 %) 16.76 Mfloat/s 59.67 ns/f UTF-16 volume = 1.07202 MB fastfloat (64) : 259.29 MB/s (+/- 1.5 %) 17.66 Mfloat/s 56.62 ns/f fastfloat (32) : 243.71 MB/s (+/- 1.8 %) 16.60 Mfloat/s 60.24 ns/f c:\Projects\fast_float\build\benchmarks\Release> --- benchmarks/benchmark.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 83493b9a..60009b00 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,3 +1,5 @@ +#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS #endif @@ -21,9 +23,11 @@ #include "fast_float/fast_float.h" +#ifdef USING_COUNTERS event_collector collector{}; - +#else std::chrono::high_resolution_clock::time_point t1, t2; +#endif template Value findmax_fastfloat(std::vector> &s, @@ -267,6 +271,7 @@ void fileload(std::string filename) { } int main(int argc, char **argv) { +#ifdef USING_COUNTERS if (collector.has_events()) { std::cout << "# Using hardware counters" << std::endl; } else { @@ -276,6 +281,8 @@ int main(int argc, char **argv) { << std::endl; #endif } +#endif + fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt"); fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt"); } From 785802344e9aff3aba0021dc59de7aad14acf5a2 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Mar 2025 05:40:27 +0300 Subject: [PATCH 019/252] Tests are updated: When FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is disabled: #### # reading C:/Projects/fast_float/build/benchmarks/data/canada.txt #### # read 111126 lines ASCII volume = 1.93374 MB fastfloat (64) : 228.57 MB/s (+/- 4.1 %) 13.14 Mfloat/s 76.13 ns/f fastfloat (32) : 226.19 MB/s (+/- 3.1 %) 13.00 Mfloat/s 76.93 ns/f UTF-16 volume = 3.86749 MB fastfloat (64) : 445.30 MB/s (+/- 2.8 %) 12.79 Mfloat/s 78.16 ns/f fastfloat (32) : 439.31 MB/s (+/- 2.1 %) 12.62 Mfloat/s 79.22 ns/f #### # reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt #### # read 73019 lines ASCII volume = 0.536009 MB fastfloat (64) : 123.40 MB/s (+/- 0.8 %) 16.81 Mfloat/s 59.49 ns/f fastfloat (32) : 117.22 MB/s (+/- 1.4 %) 15.97 Mfloat/s 62.62 ns/f UTF-16 volume = 1.07202 MB fastfloat (64) : 243.93 MB/s (+/- 2.6 %) 16.61 Mfloat/s 60.19 ns/f fastfloat (32) : 232.48 MB/s (+/- 2.5 %) 15.83 Mfloat/s 63.15 ns/f c:\Projects\fast_float\build\benchmarks\Release> When FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled: #### # reading C:/Projects/fast_float/build/benchmarks/data/canada.txt #### # read 111126 lines ASCII volume = 1.82777 MB fastfloat (64) : 233.01 MB/s (+/- 2.0 %) 14.17 Mfloat/s 70.59 ns/f fastfloat (32) : 221.31 MB/s (+/- 1.5 %) 13.46 Mfloat/s 74.32 ns/f UTF-16 volume = 3.65553 MB fastfloat (64) : 460.78 MB/s (+/- 1.4 %) 14.01 Mfloat/s 71.39 ns/f fastfloat (32) : 439.76 MB/s (+/- 2.1 %) 13.37 Mfloat/s 74.80 ns/f #### # reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt #### # read 73019 lines ASCII volume = 0.536009 MB fastfloat (64) : 131.38 MB/s (+/- 0.4 %) 17.90 Mfloat/s 55.87 ns/f fastfloat (32) : 123.03 MB/s (+/- 0.4 %) 16.76 Mfloat/s 59.67 ns/f UTF-16 volume = 1.07202 MB fastfloat (64) : 259.29 MB/s (+/- 1.5 %) 17.66 Mfloat/s 56.62 ns/f fastfloat (32) : 243.71 MB/s (+/- 1.8 %) 16.60 Mfloat/s 60.24 ns/f c:\Projects\fast_float\build\benchmarks\Release> P.S. tested on latest Windows 10 update with latest MSVC 2022 updates on older, but still powerful machine with Intel Xeon E5-2680 v2 --- benchmarks/benchmark.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 83493b9a..8ec86b8e 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,3 +1,5 @@ +//#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS #endif @@ -21,9 +23,11 @@ #include "fast_float/fast_float.h" +#ifdef USING_COUNTERS event_collector collector{}; - +#else std::chrono::high_resolution_clock::time_point t1, t2; +#endif template Value findmax_fastfloat(std::vector> &s, @@ -267,6 +271,7 @@ void fileload(std::string filename) { } int main(int argc, char **argv) { +#ifdef USING_COUNTERS if (collector.has_events()) { std::cout << "# Using hardware counters" << std::endl; } else { @@ -276,6 +281,8 @@ int main(int argc, char **argv) { << std::endl; #endif } +#endif + fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt"); fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt"); } From 3dd9a989265b3170265c597ff8e6d706bd225581 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 17:44:08 +0300 Subject: [PATCH 020/252] more const --- include/fast_float/fast_float.h | 4 ++-- include/fast_float/parse_number.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 8dfef020..73398477 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -34,7 +34,7 @@ template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - chars_format fmt = chars_format::general) noexcept; + chars_format const fmt = chars_format::general) noexcept; /** * Like from_chars, but accepts an `options` argument to govern number parsing. @@ -51,7 +51,7 @@ from_chars_advanced(UC const *first, UC const *last, T &value, template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept; +from_chars(UC const *first, UC const *last, T &value, int const base = 10) noexcept; } // namespace fast_float diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index ce3a2d42..554b7cfe 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -187,7 +187,7 @@ template <> struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - chars_format fmt /*= chars_format::general*/) noexcept { + chars_format const fmt /*= chars_format::general*/) noexcept { return from_chars_caller::call(first, last, value, parse_options_t(fmt)); } @@ -350,7 +350,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int base) noexcept { +from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); From 1899647146384501e342b9989645a51e81cb4271 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 17:56:01 +0300 Subject: [PATCH 021/252] GCC compilation fix. --- include/fast_float/constexpr_feature_detect.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 25a513d7..af6474bc 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -62,7 +62,7 @@ #if defined(__clang__) // needs testing #define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) #elif defined(__GNUC__) && !defined(__ICC) // needs testing -#define FASTFLOAT_ASSUME(expr) __attribute__((expr)) +#define FASTFLOAT_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } #elif defined(__ICC) // needs testing #define FASTFLOAT_ASSUME(expr) __assume(expr) #elif defined(_MSC_VER) From e84f289337816df8e26e270238ee2e1334d4a5cf Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 18:45:48 +0300 Subject: [PATCH 022/252] FASTFLOAT_IF_CONSTEXPR17 fix compilation when FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN isn't enabled. --- include/fast_float/ascii_number.h | 22 +++++++++++----------- include/fast_float/parse_number.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 4f4c9d99..dcaffca7 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -240,11 +240,15 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend, enum class parse_error { no_error, + // A sign must be followed by an integer or dot. + missing_integer_or_dot_after_sign, + // The mantissa must have at least one digit. + no_digits_in_mantissa, + // Scientific notation requires an exponential part. + missing_exponential_part, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // [JSON-only] The minus sign must be followed by an integer. missing_integer_after_sign, - // A sign must be followed by an integer or dot. - missing_integer_or_dot_after_sign, // [JSON-only] The integer part must not have leading zeros. leading_zeros_in_integer_part, // [JSON-only] The integer part must have at least one digit. @@ -253,10 +257,6 @@ enum class parse_error { // fractional part. no_digits_in_fractional_part, #endif - // The mantissa must have at least one digit. - no_digits_in_mantissa, - // Scientific notation requires an exponential part. - missing_exponential_part, }; template struct parsed_number_string_t { @@ -301,15 +301,15 @@ parse_number_string(UC const *p, UC const *pend, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || - (uint64_t(options.format & chars_format::allow_leading_plus) && - !uint64_t(options.format & detail::basic_json_fmt) && *p == UC('+'))) { + if (*p == UC('-') || + (uint64_t(options.format & chars_format::allow_leading_plus) && + *p == UC('+'))) { ++p; if (p == pend) { return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); + p, parse_error::missing_integer_or_dot_after_sign); } - if (uint64_t(options.format & detail::basic_json_fmt)) { + FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { if (!is_integer(*p)) { // a sign must be followed by an integer return report_parse_error(p, parse_error::missing_integer_after_sign); diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 554b7cfe..42de867f 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -225,7 +225,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { // We could check it first (before the previous branch), but // there might be performance advantages at having the check // be last. - if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { + FASTFLOAT_IF_CONSTEXPR17 (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { // We have that fegetround() == FE_TONEAREST. // Next is Clinger's fast path. if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { From 07ab87ca2b3ee6351e9dd9abd974f17d1b1aa209 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 20:05:34 +0300 Subject: [PATCH 023/252] compilation fix in some cases. --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index dcaffca7..c995069f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -513,7 +513,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, return answer; } if ((*p == UC('-')) || - (uint64_t(options.fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { + (uint64_t(options.format & chars_format::allow_leading_plus) && (*p == UC('+')))) { ++p; } #endif From 3dd3712782cb132c40244d1eeec85c7de1467885 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 20:11:11 +0300 Subject: [PATCH 024/252] lint --- benchmarks/benchmark.cpp | 38 +++++++++---------- include/fast_float/constexpr_feature_detect.h | 6 ++- include/fast_float/float_common.h | 21 +++++----- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 54d96d92..25108224 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -34,7 +34,7 @@ Value findmax_fastfloat(std::vector> &s, #ifdef USING_COUNTERS std::vector &aggregate #else - std::chrono::nanoseconds& time + std::chrono::nanoseconds &time #endif ) { Value answer = 0; @@ -55,7 +55,7 @@ Value findmax_fastfloat(std::vector> &s, t2 = std::chrono::high_resolution_clock::now(); time += t2 - t1; #endif - + if (ec != std::errc{}) { throw std::runtime_error("bug in findmax_fastfloat"); } @@ -71,7 +71,7 @@ time_it_ns(std::vector> &lines, T const &function, size_t repeat) { std::vector aggregate; bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { + for (size_t i = 0; i < repeat; i++) { double ts = function(lines, aggregate); if (ts == 0 && !printed_bug) { printf("bug\n"); @@ -155,7 +155,8 @@ time_it_ns(std::vector> &lines, T const &function, printf("bug\n"); printed_bug = true; } - double dif = std::chrono::duration_cast(time).count(); + double dif = + std::chrono::duration_cast(time).count(); average += dif; min_value = min_value < dif ? min_value : dif; } @@ -206,8 +207,9 @@ void process(std::vector &lines, size_t volume) { volume = 2 * volume; volumeMB = volume / (1024. * 1024.); std::cout << "UTF-16 volume = " << volumeMB << " MB " << std::endl; - pretty_print(volume, lines.size(), "fastfloat (64)", - time_it_ns(lines16, findmax_fastfloat, repeat)); + pretty_print( + volume, lines.size(), "fastfloat (64)", + time_it_ns(lines16, findmax_fastfloat, repeat)); pretty_print(volume, lines.size(), "fastfloat (32)", time_it_ns(lines16, findmax_fastfloat, repeat)); } @@ -229,29 +231,23 @@ void fileload(std::string filename) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN /* This code is a simple parser emulator */ for (size_t n = 0; n < line.size(); ++n) { - if ((line[n] >= '0' && line[n] <= '9')) - { + if ((line[n] >= '0' && line[n] <= '9')) { /* in the real parser we don't check anything else and call the from_chars function immediately */ const auto s = n; for (++n; n < line.size() && - ((line[n] >= '0' && line[n] <= '9') || - line[n] == 'e' || line[n] == 'E' || - line[n] == '.' || - line[n] == '-' || line[n] == '+' - /* last line for exponent sign*/ - ); - ++n) - { - + ((line[n] >= '0' && line[n] <= '9') || line[n] == 'e' || + line[n] == 'E' || line[n] == '.' || line[n] == '-' || + line[n] == '+' + /* last line for exponent sign*/ + ); + ++n) { } /*~ in the real parser we don't check anything else and call the from_chars function immediately */ volume += lines.emplace_back(line.substr(s, n)).size(); - } - else - { + } else { /* for the test we simplify skipped all other symbols, in real application this should be a full parser, that parse also any mathematical operations like + and - @@ -261,7 +257,7 @@ void fileload(std::string filename) { continue; } } - // in the real parser this part of code should return end token + // in the real parser this part of code should return end token #else volume += lines.emplace_back(line).size(); #endif diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index af6474bc..0a982542 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -62,7 +62,11 @@ #if defined(__clang__) // needs testing #define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) #elif defined(__GNUC__) && !defined(__ICC) // needs testing -#define FASTFLOAT_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +#define FASTFLOAT_ASSUME(expr) \ + if (expr) { \ + } else { \ + __builtin_unreachable(); \ + } #elif defined(__ICC) // needs testing #define FASTFLOAT_ASSUME(expr) __assume(expr) #elif defined(_MSC_VER) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 3f1c8fca..18094832 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -67,8 +67,9 @@ template struct from_chars_result_t { using from_chars_result = from_chars_result_t; template struct parse_options_t { - FASTFLOAT_CONSTEXPR20 explicit parse_options_t(chars_format fmt = chars_format::general, - UC dot = UC('.'), const int b = 10) noexcept + FASTFLOAT_CONSTEXPR20 explicit parse_options_t( + chars_format fmt = chars_format::general, UC dot = UC('.'), + const int b = 10) noexcept : format(fmt), decimal_point(dot), base(static_cast(b)) {} /** Which number formats are accepted */ @@ -216,7 +217,8 @@ using parse_options = parse_options_t; namespace fast_float { -fastfloat_really_inline FASTFLOAT_CONSTEVAL20 bool cpp20_and_in_constexpr() noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEVAL20 bool +cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED return std::is_constant_evaluated(); #else @@ -304,7 +306,8 @@ struct value128 { uint64_t low; uint64_t high; - constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} + constexpr value128(uint64_t _low, uint64_t _high) noexcept + : low(_low), high(_high) {} constexpr value128() noexcept : low(0), high(0) {} }; @@ -362,7 +365,8 @@ leading_zeroes(uint64_t input_num) noexcept { } // slow emulation routine for 32-bit -fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) noexcept { +fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, + uint32_t y) noexcept { return x * (uint64_t)y; } @@ -995,12 +999,11 @@ binary_format::hidden_bit_mask() { } template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -to_float( +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - bool const negative, + bool const negative, #endif - adjusted_mantissa const &am, T &value) noexcept { + adjusted_mantissa const &am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) From f3c60527d5595c637126fdde02a28af64faaf7a4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 20:15:29 +0300 Subject: [PATCH 025/252] more constexpr. --- include/fast_float/parse_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 74ac3616..baa225f0 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -79,7 +79,7 @@ from_chars_result_t * It is the default on most system. This function is meant to be inexpensive. * Credit : @mwalcott3 */ -fastfloat_really_inline bool rounds_to_nearest() noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool rounds_to_nearest() noexcept { // https://lemire.me/blog/2020/06/26/gcc-not-nearest/ #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return false; From 27c0cd581c040403dc726bd13e8b008cb9a0d257 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 20:23:05 +0300 Subject: [PATCH 026/252] lint --- include/fast_float/ascii_number.h | 72 ++++++++++++++------------- include/fast_float/digit_comparison.h | 13 ++--- include/fast_float/fast_float.h | 3 +- 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index c995069f..978c3896 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -60,11 +60,11 @@ read8_to_u64(UC const *chars) { ::memcpy(&val, chars, sizeof(uint64_t)); #if FASTFLOAT_IS_BIG_ENDIAN == 1 // Need to read as-if the number was in little-endian order. - val = + val = #if FASTFLOAT_HAS_BYTESWAP == 1 - std:: + std:: #endif - byteswap(val); + byteswap(val); #endif return val; } @@ -208,7 +208,8 @@ template template ()) = 0> #endif // dummy for compile -FASTFLOAT_CONSTEVAL20 bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { +FASTFLOAT_CONSTEVAL20 bool simd_parse_if_eight_digits_unrolled(UC const *, + uint64_t &) { return 0; } @@ -302,12 +303,12 @@ parse_number_string(UC const *p, UC const *pend, answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if (*p == UC('-') || - (uint64_t(options.format & chars_format::allow_leading_plus) && - *p == UC('+'))) { + (uint64_t(options.format & chars_format::allow_leading_plus) && + *p == UC('+'))) { ++p; if (p == pend) { return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); + p, parse_error::missing_integer_or_dot_after_sign); } FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { if (!is_integer(*p)) { // a sign must be followed by an integer @@ -317,8 +318,8 @@ parse_number_string(UC const *p, UC const *pend, } else { if (!is_integer(*p) && - (*p != - options.decimal_point)) { // a sign must be followed by an integer or the dot + (*p != options.decimal_point)) { // a sign must be followed by an + // integer or the dot return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } @@ -385,26 +386,27 @@ parse_number_string(UC const *p, UC const *pend, ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN || (uint64_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || - (UC('d') == *p) || (UC('D') == *p))) + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) #endif - ) { + ) { UC const *location_of_e = p; if (((UC('e') == *p) || (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (UC('d') == *p) || (UC('D') == *p) + || (UC('d') == *p) || (UC('D') == *p) #endif - ) { + ) { ++p; } bool neg_exp = false; if (p != pend) { - if ( UC('-') == *p) { - neg_exp = true; - ++p; - } else if (UC('+') == *p) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) - ++p; - } + if (UC('-') == *p) { + neg_exp = true; + ++p; + } else if (UC('+') == + *p) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + ++p; + } } if ((p == pend) || !is_integer(*p)) { if (!uint64_t(options.format & chars_format::fixed)) { @@ -449,8 +451,8 @@ parse_number_string(UC const *p, UC const *pend, // We need to be mindful of the case where we only have zeroes... // E.g., 0.000000000...000. UC const *start = start_digits; - while ((start != pend) && (*start == UC('0') || - *start == options.decimal_point)) { + while ((start != pend) && + (*start == UC('0') || *start == options.decimal_point)) { if (*start == UC('0')) { digit_count--; } @@ -504,18 +506,19 @@ parse_int_string(UC const *p, UC const *pend, T &value, #pragma warning(push) #pragma warning(disable : 4127) #endif - if (!std::is_signed::value && negative) { + if (!std::is_signed::value && negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(pop) #endif - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - if ((*p == UC('-')) || - (uint64_t(options.format & chars_format::allow_leading_plus) && (*p == UC('+')))) { - ++p; - } + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + if ((*p == UC('-')) || + (uint64_t(options.format & chars_format::allow_leading_plus) && + (*p == UC('+')))) { + ++p; + } #endif UC const *const start_num = p; @@ -538,7 +541,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, if (digit >= options.base) { break; } - i = static_cast(options.base) * i + digit; // might overflow, check this later + i = static_cast(options.base) * i + + digit; // might overflow, check this later p++; } @@ -575,9 +579,9 @@ parse_int_string(UC const *p, UC const *pend, T &value, if (!std::is_same::value) { if (i > uint64_t(std::numeric_limits::max()) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - + uint64_t(negative) + + uint64_t(negative) #endif - ) { + ) { answer.ec = std::errc::result_out_of_range; return answer; } diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index a8d4eeca..5f74a12c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -369,8 +369,9 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, const adjusted_mantissa& am, const int32_t exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +negative_digit_comp(bigint &bigmant, const adjusted_mantissa &am, + const int32_t exponent) noexcept { bigint &real_digits = bigmant; const int32_t &real_exp = exponent; @@ -383,9 +384,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( T b; to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - false, + false, #endif - am_b, b); + am_b, b); adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); int32_t theor_exp = theor.power2; @@ -437,8 +438,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // the actual digits. we then compare the big integer representations // of both, and use that to direct rounding. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -digit_comp(const parsed_number_string_t &num, adjusted_mantissa& am) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( + const parsed_number_string_t &num, adjusted_mantissa &am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 73398477..4ca1a0ae 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -51,7 +51,8 @@ from_chars_advanced(UC const *first, UC const *last, T &value, template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int const base = 10) noexcept; +from_chars(UC const *first, UC const *last, T &value, + int const base = 10) noexcept; } // namespace fast_float From 2db26df2b8efe57ca40d5db816a3722784b22d84 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 20:35:28 +0300 Subject: [PATCH 027/252] Remove consexpr/consteval from code that probably assumed to run in the runtime and not be optimized (strange crutch actually). --- include/fast_float/parse_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index baa225f0..4d8aa88c 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -79,7 +79,7 @@ from_chars_result_t * It is the default on most system. This function is meant to be inexpensive. * Credit : @mwalcott3 */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool rounds_to_nearest() noexcept { +fastfloat_really_inline bool rounds_to_nearest() noexcept { // https://lemire.me/blog/2020/06/26/gcc-not-nearest/ #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return false; @@ -225,7 +225,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { // We could check it first (before the previous branch), but // there might be performance advantages at having the check // be last. - FASTFLOAT_IF_CONSTEXPR17 (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { + if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { // We have that fegetround() == FE_TONEAREST. // Next is Clinger's fast path. if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { From 1ab438cf7a5bda355458781208a9289f8dcb5d6f Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 21:03:53 +0300 Subject: [PATCH 028/252] Tests are updated. --- tests/basictest.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 552d6f15..f2cba7f8 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -644,19 +644,20 @@ TEST_CASE("check_behavior") { TEST_CASE("decimal_point_parsing") { double result; - fast_float::parse_options options{}; { std::string const input = "1,25"; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options{}); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at comma"); CHECK_EQ(result, 1.0); - options.decimal_point = ','; answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options(fast_float::chars_format::general, ',', 10) + ); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -665,15 +666,18 @@ TEST_CASE("decimal_point_parsing") { { std::string const input = "1.25"; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options(fast_float::chars_format::general, ',', 10) + ); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at dot"); CHECK_EQ(result, 1.0); - options.decimal_point = '.'; answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options{} + ); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); From 929e98182e68b0293f13335811e762f4463a2792 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 21:13:20 +0300 Subject: [PATCH 029/252] lint --- include/fast_float/parse_number.h | 15 ++++++++------- tests/basictest.cpp | 9 +++------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 4d8aa88c..e5c08bea 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -23,10 +23,11 @@ namespace detail { template from_chars_result_t FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, - T &value, const chars_format fmt) noexcept { + T &value, + const chars_format fmt) noexcept { from_chars_result_t answer{}; answer.ptr = first; - answer.ec = std::errc(); // be optimistic + answer.ec = std::errc(); // be optimistic FASTFLOAT_ASSUME(first < last); // so dereference without checks bool const minusSign = (*first == UC('-')); @@ -254,9 +255,9 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { if (pns.mantissa == 0) { value = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - pns.negative ? T(-0.) : + pns.negative ? T(-0.) : #endif - T(0.); + T(0.); return answer; } #endif @@ -286,9 +287,9 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { } to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - pns.negative, + pns.negative, #endif - am, value); + am, value); // Test for over/underflow. if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || am.power2 == binary_format::infinite_power()) { @@ -329,7 +330,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, ? parse_number_string(first, last, options) : #endif - parse_number_string(first, last, options); + parse_number_string(first, last, options); if (!pns.valid) { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint64_t(options.format & chars_format::no_infnan)) { diff --git a/tests/basictest.cpp b/tests/basictest.cpp index f2cba7f8..cbeb11ee 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -656,8 +656,7 @@ TEST_CASE("decimal_point_parsing") { answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options(fast_float::chars_format::general, ',', 10) - ); + fast_float::parse_options(fast_float::chars_format::general, ',', 10)); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -667,8 +666,7 @@ TEST_CASE("decimal_point_parsing") { std::string const input = "1.25"; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options(fast_float::chars_format::general, ',', 10) - ); + fast_float::parse_options(fast_float::chars_format::general, ',', 10)); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at dot"); @@ -676,8 +674,7 @@ TEST_CASE("decimal_point_parsing") { answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options{} - ); + fast_float::parse_options{}); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); From c08b7b12a636cb78ffa4291f92bc99c2c6e23f74 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 21:26:31 +0300 Subject: [PATCH 030/252] tests updated --- tests/basictest.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index cbeb11ee..0859c468 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1323,9 +1323,7 @@ TEST_CASE("double.general") { TEST_CASE("double.decimal_point") { constexpr auto options = [] { - fast_float::parse_options ret{}; - ret.decimal_point = ','; - return ret; + return fast_float::parse_options(fast_float::chars_format::general, ',', 10); }(); // infinities @@ -1642,9 +1640,7 @@ TEST_CASE("float.general") { TEST_CASE("float.decimal_point") { constexpr auto options = [] { - fast_float::parse_options ret{}; - ret.decimal_point = ','; - return ret; + return fast_float::parse_options(fast_float::chars_format::general, ',', 10); }(); // infinity From cd5db6f5e9e84c0db63eec403097dd0725533d6b Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Mar 2025 21:34:31 +0300 Subject: [PATCH 031/252] lint --- tests/basictest.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 0859c468..d1b377af 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1323,7 +1323,8 @@ TEST_CASE("double.general") { TEST_CASE("double.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options(fast_float::chars_format::general, ',', 10); + return fast_float::parse_options(fast_float::chars_format::general, ',', + 10); }(); // infinities @@ -1640,7 +1641,8 @@ TEST_CASE("float.general") { TEST_CASE("float.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options(fast_float::chars_format::general, ',', 10); + return fast_float::parse_options(fast_float::chars_format::general, ',', + 10); }(); // infinity From 0188112c8f9016fb8ebeec42f2e72f27f8bc3240 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 13 Mar 2025 00:37:46 +0300 Subject: [PATCH 032/252] compilation fix in some old compilers. --- include/fast_float/ascii_number.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 978c3896..30c7e165 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -342,6 +342,7 @@ parse_number_string(UC const *p, UC const *pend, UC const *const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in integer part, without leading zeros if (digit_count == 0) { @@ -352,6 +353,7 @@ parse_number_string(UC const *p, UC const *pend, parse_error::leading_zeros_in_integer_part); } } +#endif int64_t exponent = 0; bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); @@ -371,6 +373,7 @@ parse_number_string(UC const *p, UC const *pend, answer.fraction = span(before, size_t(p - before)); digit_count -= exponent; } +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in fractional part if (has_decimal_point && exponent == 0) { @@ -378,6 +381,7 @@ parse_number_string(UC const *p, UC const *pend, parse_error::no_digits_in_fractional_part); } } +#endif else if (digit_count == 0) { // we must have encountered at least one integer! return report_parse_error(p, parse_error::no_digits_in_mantissa); } From ffd3590a42719a49fbfca8571007efa0fd64dae3 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 10:35:55 +0300 Subject: [PATCH 033/252] benchmarks are improved: back to the cycle metering because when USING_COUNTERS is enabled it's consumed to much resources. --- benchmarks/benchmark.cpp | 64 +++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 25108224..fddcc420 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,4 +1,51 @@ -#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +/* +#### +# reading C:/Projects/fast_float/build/benchmarks/data/canada.txt +#### +# read 111126 lines +ASCII volume = 1.93374 MB +fastfloat (64) : 188.96 MB/s (+/- 3.1 %) 10.86 Mfloat/s 92.09 ns/f +fastfloat (32) : 229.56 MB/s (+/- 5.6 %) 13.19 Mfloat/s 75.80 ns/f +UTF-16 volume = 3.86749 MB +fastfloat (64) : 446.29 MB/s (+/- 5.5 %) 12.82 Mfloat/s 77.98 ns/f +fastfloat (32) : 440.58 MB/s (+/- 5.4 %) 12.66 Mfloat/s 78.99 ns/f +#### +# reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt +#### +# read 73019 lines +ASCII volume = 0.536009 MB +fastfloat (64) : 125.54 MB/s (+/- 2.6 %) 17.10 Mfloat/s 58.47 ns/f +fastfloat (32) : 118.63 MB/s (+/- 2.9 %) 16.16 Mfloat/s 61.88 ns/f +UTF-16 volume = 1.07202 MB +fastfloat (64) : 246.08 MB/s (+/- 2.3 %) 16.76 Mfloat/s 59.66 ns/f +fastfloat (32) : 234.03 MB/s (+/- 2.9 %) 15.94 Mfloat/s 62.73 ns/f +*/ + +//#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + +/* +#### +# reading C:/Projects/fast_float/build/benchmarks/data/canada.txt +#### +# read 111126 lines +ASCII volume = 1.82777 MB +fastfloat (64) : 232.92 MB/s (+/- 4.3 %) 14.16 Mfloat/s 70.62 ns/f +fastfloat (32) : 221.19 MB/s (+/- 3.8 %) 13.45 Mfloat/s 74.36 ns/f +UTF-16 volume = 3.65553 MB +fastfloat (64) : 460.42 MB/s (+/- 5.2 %) 14.00 Mfloat/s 71.45 ns/f +fastfloat (32) : 438.06 MB/s (+/- 5.6 %) 13.32 Mfloat/s 75.09 ns/f +#### +# reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt +#### +# read 73019 lines +ASCII volume = 0.536009 MB +fastfloat (64) : 131.35 MB/s (+/- 1.5 %) 17.89 Mfloat/s 55.89 ns/f +fastfloat (32) : 123.21 MB/s (+/- 1.2 %) 16.78 Mfloat/s 59.58 ns/f +UTF-16 volume = 1.07202 MB +fastfloat (64) : 259.51 MB/s (+/- 1.7 %) 17.68 Mfloat/s 56.57 ns/f +fastfloat (32) : 244.28 MB/s (+/- 2.0 %) 16.64 Mfloat/s 60.10 ns/f +*/ + #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS @@ -39,28 +86,25 @@ Value findmax_fastfloat(std::vector> &s, ) { Value answer = 0; Value x = 0; - for (auto &st : s) { - #ifdef USING_COUNTERS collector.start(); #else t1 = std::chrono::high_resolution_clock::now(); #endif - + for (auto &st : s) { auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); + if (ec != std::errc{}) { + throw std::runtime_error("bug in findmax_fastfloat"); + } + answer = answer > x ? answer : x; + } #ifdef USING_COUNTERS aggregate.push_back(collector.end()); #else t2 = std::chrono::high_resolution_clock::now(); time += t2 - t1; #endif - - if (ec != std::errc{}) { - throw std::runtime_error("bug in findmax_fastfloat"); - } - answer = answer > x ? answer : x; - } return answer; } From c598a994e62366ccf2c1cd39f1a6d92ca691592c Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 11:15:24 +0300 Subject: [PATCH 034/252] fix a warning. --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 18094832..84f076f0 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -217,7 +217,7 @@ using parse_options = parse_options_t; namespace fast_float { -fastfloat_really_inline FASTFLOAT_CONSTEVAL20 bool +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED return std::is_constant_evaluated(); From 9688b3bdf74e3074ab159ea92e7176fd08b1ec17 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 11:31:44 +0300 Subject: [PATCH 035/252] improvements in benchmark. added support for free license for PVS-Studio for open source project (needs recheck by team, I found some strange errors in library, but not fully understand it) --- benchmarks/benchmark.cpp | 68 +++++++------------------------------- benchmarks/event_counter.h | 31 +++++++++-------- 2 files changed, 27 insertions(+), 72 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index fddcc420..e84b1fce 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,51 +1,5 @@ -/* -#### -# reading C:/Projects/fast_float/build/benchmarks/data/canada.txt -#### -# read 111126 lines -ASCII volume = 1.93374 MB -fastfloat (64) : 188.96 MB/s (+/- 3.1 %) 10.86 Mfloat/s 92.09 ns/f -fastfloat (32) : 229.56 MB/s (+/- 5.6 %) 13.19 Mfloat/s 75.80 ns/f -UTF-16 volume = 3.86749 MB -fastfloat (64) : 446.29 MB/s (+/- 5.5 %) 12.82 Mfloat/s 77.98 ns/f -fastfloat (32) : 440.58 MB/s (+/- 5.4 %) 12.66 Mfloat/s 78.99 ns/f -#### -# reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt -#### -# read 73019 lines -ASCII volume = 0.536009 MB -fastfloat (64) : 125.54 MB/s (+/- 2.6 %) 17.10 Mfloat/s 58.47 ns/f -fastfloat (32) : 118.63 MB/s (+/- 2.9 %) 16.16 Mfloat/s 61.88 ns/f -UTF-16 volume = 1.07202 MB -fastfloat (64) : 246.08 MB/s (+/- 2.3 %) 16.76 Mfloat/s 59.66 ns/f -fastfloat (32) : 234.03 MB/s (+/- 2.9 %) 15.94 Mfloat/s 62.73 ns/f -*/ - -//#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - -/* -#### -# reading C:/Projects/fast_float/build/benchmarks/data/canada.txt -#### -# read 111126 lines -ASCII volume = 1.82777 MB -fastfloat (64) : 232.92 MB/s (+/- 4.3 %) 14.16 Mfloat/s 70.62 ns/f -fastfloat (32) : 221.19 MB/s (+/- 3.8 %) 13.45 Mfloat/s 74.36 ns/f -UTF-16 volume = 3.65553 MB -fastfloat (64) : 460.42 MB/s (+/- 5.2 %) 14.00 Mfloat/s 71.45 ns/f -fastfloat (32) : 438.06 MB/s (+/- 5.6 %) 13.32 Mfloat/s 75.09 ns/f -#### -# reading C:/Projects/fast_float/build/benchmarks/data/mesh.txt -#### -# read 73019 lines -ASCII volume = 0.536009 MB -fastfloat (64) : 131.35 MB/s (+/- 1.5 %) 17.89 Mfloat/s 55.89 ns/f -fastfloat (32) : 123.21 MB/s (+/- 1.2 %) 16.78 Mfloat/s 59.58 ns/f -UTF-16 volume = 1.07202 MB -fastfloat (64) : 259.51 MB/s (+/- 1.7 %) 17.68 Mfloat/s 56.57 ns/f -fastfloat (32) : 244.28 MB/s (+/- 2.0 %) 16.64 Mfloat/s 60.10 ns/f -*/ - +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: https://pvs-studio.com #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS @@ -88,11 +42,16 @@ Value findmax_fastfloat(std::vector> &s, Value x = 0; #ifdef USING_COUNTERS collector.start(); -#else - t1 = std::chrono::high_resolution_clock::now(); #endif for (auto &st : s) { +#ifndef USING_COUNTERS + t1 = std::chrono::high_resolution_clock::now(); +#endif auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); +#ifndef USING_COUNTERS + t2 = std::chrono::high_resolution_clock::now(); + time += std::chrono::duration_cast(t2 - t1); +#endif if (ec != std::errc{}) { throw std::runtime_error("bug in findmax_fastfloat"); @@ -101,9 +60,6 @@ Value findmax_fastfloat(std::vector> &s, } #ifdef USING_COUNTERS aggregate.push_back(collector.end()); -#else - t2 = std::chrono::high_resolution_clock::now(); - time += t2 - t1; #endif return answer; } @@ -208,7 +164,7 @@ time_it_ns(std::vector> &lines, T const &function, return std::make_pair(min_value, average); } -void pretty_print(double volume, size_t number_of_floats, std::string name, +void pretty_print(double volume, size_t number_of_floats, std::string const &name, std::pair result) { double volumeMB = volume / (1024. * 1024.); printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), @@ -220,7 +176,7 @@ void pretty_print(double volume, size_t number_of_floats, std::string name, #endif // this is okay, all chars are ASCII -inline std::u16string widen(std::string line) { +inline std::u16string widen(std::string const &line) { std::u16string u16line; u16line.resize(line.size()); for (size_t i = 0; i < line.size(); ++i) { @@ -233,7 +189,7 @@ std::vector widen(const std::vector &lines) { std::vector u16lines; u16lines.reserve(lines.size()); for (auto const &line : lines) { - u16lines.push_back(widen(line)); + u16lines.emplace_back(widen(line)); } return u16lines; } diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index cd594787..c45f7681 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include "linux-perf-events.h" #ifdef __linux__ @@ -22,26 +22,27 @@ #endif struct event_count { + // The types of counters (so we can read the getter more easily) + enum event_counter_types { + CPU_CYCLES = 0, + INSTRUCTIONS = 1, + BRANCHES = 2, + MISSED_BRANCHES = 3, + event_counter_types_size = 4 + }; + std::chrono::duration elapsed; - std::vector event_counts; + std::array event_counts; - event_count() : elapsed(0), event_counts{0, 0, 0, 0, 0} {} + event_count() : elapsed(0), event_counts{0, 0, 0, 0} {} - event_count(const std::chrono::duration _elapsed, - const std::vector _event_counts) + event_count(const std::chrono::duration &_elapsed, + const std::array &_event_counts) : elapsed(_elapsed), event_counts(_event_counts) {} event_count(const event_count &other) : elapsed(other.elapsed), event_counts(other.event_counts) {} - // The types of counters (so we can read the getter more easily) - enum event_counter_types { - CPU_CYCLES = 0, - INSTRUCTIONS = 1, - BRANCHES = 2, - MISSED_BRANCHES = 3 - }; - double elapsed_sec() const { return std::chrono::duration(elapsed).count(); } @@ -79,7 +80,6 @@ struct event_count { event_counts[1] + other.event_counts[1], event_counts[2] + other.event_counts[2], event_counts[3] + other.event_counts[3], - event_counts[4] + other.event_counts[4], }); } @@ -142,7 +142,7 @@ struct event_collector { bool has_events() { return setup_performance_counters(); } #else - event_collector() {} + event_collector() = default; bool has_events() { return false; } #endif @@ -171,7 +171,6 @@ struct event_collector { count.event_counts[1] = diff.instructions; count.event_counts[2] = diff.branches; count.event_counts[3] = diff.missed_branches; - count.event_counts[4] = 0; #endif count.elapsed = end_clock - start_clock; return count; From 1e3a135b8d24c4dab62c366258195e8f635978e7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 11:45:33 +0300 Subject: [PATCH 036/252] reduce register pressure. --- benchmarks/benchmark.cpp | 3 +++ include/fast_float/digit_comparison.h | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index e84b1fce..0eedab97 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,6 +1,9 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check it. // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: https://pvs-studio.com + +//#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS #endif diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 5f74a12c..a2869f8d 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -223,8 +223,8 @@ is_truncated(span s) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, size_t &counter, - size_t &count) noexcept { +parse_eight_digits(UC const *&p, limb &value, unsigned int &counter, + unsigned int &count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; counter += 8; @@ -233,8 +233,8 @@ parse_eight_digits(UC const *&p, limb &value, size_t &counter, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, size_t &counter, - size_t &count) noexcept { +parse_one_digit(UC const *&p, limb &value, unsigned int &counter, + unsigned int &count) noexcept { value = value * 10 + limb(*p - UC('0')); p++; counter++; @@ -248,7 +248,7 @@ add_native(bigint &big, limb power, limb value) noexcept { } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -round_up_bigint(bigint &big, size_t &count) noexcept { +round_up_bigint(bigint &big, unsigned int &count) noexcept { // need to round-up the digits, but need to avoid rounding // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); @@ -259,17 +259,17 @@ round_up_bigint(bigint &big, size_t &count) noexcept { template inline FASTFLOAT_CONSTEXPR20 void parse_mantissa(bigint &result, const parsed_number_string_t &num, - size_t max_digits, size_t &digits) noexcept { + unsigned int max_digits, unsigned int &digits) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - size_t counter = 0; + unsigned int counter = 0; digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - size_t step = 19; + unsigned int step = 19; #else - size_t step = 9; + unsigned int step = 9; #endif // process all integer digits. @@ -444,8 +444,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am.power2 -= invalid_am_bias; int32_t sci_exp = scientific_exponent(num); - size_t max_digits = binary_format::max_digits(); - size_t digits = 0; + unsigned int max_digits = binary_format::max_digits(); + unsigned int digits = 0; bigint bigmant; parse_mantissa(bigmant, num, max_digits, digits); // can't underflow, since digits is at most max_digits. From 23395e4f10a33ef9c646abcda82ea70f1155a135 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 12:38:49 +0300 Subject: [PATCH 037/252] try to compilation fix on Linux --- benchmarks/event_counter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index c45f7681..18695bc8 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -129,7 +129,7 @@ struct event_collector { LinuxEvents linux_events; event_collector() - : linux_events(std::vector{ + : linux_events(std::array{ PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_MISSES}) {} From a2437735b1396415372b571188609746c925a170 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 12:38:49 +0300 Subject: [PATCH 038/252] try to compilation fix on Linux --- benchmarks/event_counter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index c45f7681..de846539 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -129,7 +129,7 @@ struct event_collector { LinuxEvents linux_events; event_collector() - : linux_events(std::vector{ + : linux_events(std::array{ PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_MISSES}) {} From 3eaa7d76682a9765f6f6ce7b07a35763ae0cf9b4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 12:51:43 +0300 Subject: [PATCH 039/252] compilation fix. --- benchmarks/event_counter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index de846539..24c21a81 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -129,7 +129,7 @@ struct event_collector { LinuxEvents linux_events; event_collector() - : linux_events(std::array{ + : linux_events(std::array{ PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_MISSES}) {} From 0340e8bb25871ee0eb59fc836538512523c36f6e Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 12:57:32 +0300 Subject: [PATCH 040/252] build fix. --- benchmarks/linux-perf-events.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/linux-perf-events.h b/benchmarks/linux-perf-events.h index 0a9e5538..99e4ef19 100644 --- a/benchmarks/linux-perf-events.h +++ b/benchmarks/linux-perf-events.h @@ -10,7 +10,7 @@ #include // for memset #include -#include +#include #include template class LinuxEvents { @@ -22,7 +22,7 @@ template class LinuxEvents { std::vector ids{}; public: - explicit LinuxEvents(std::vector config_vec) : fd(0), working(true) { + explicit LinuxEvents(std::array config_vec) : fd(0), working(true) { memset(&attribs, 0, sizeof(attribs)); attribs.type = TYPE; attribs.size = sizeof(attribs); From edb51b3e68649e1d38fcd6dd0d67bf2d758cc811 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 24 Mar 2025 12:59:52 +0300 Subject: [PATCH 041/252] . --- benchmarks/linux-perf-events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/linux-perf-events.h b/benchmarks/linux-perf-events.h index 99e4ef19..88460da8 100644 --- a/benchmarks/linux-perf-events.h +++ b/benchmarks/linux-perf-events.h @@ -75,7 +75,7 @@ template class LinuxEvents { } } - inline void end(std::vector &results) { + inline void end(std::array &results) { if (fd != -1) { if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) { report_error("ioctl(PERF_EVENT_IOC_DISABLE)"); From 67aeda07ad2d1d45f55bf3754ed5ff631fda6d12 Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Thu, 27 Mar 2025 21:50:52 +0300 Subject: [PATCH 042/252] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 9155c268..21768319 100644 --- a/README.md +++ b/README.md @@ -386,8 +386,7 @@ the code size and improve performance: int main() { std::string input = "23.14069263277926900572"; double result; - fast_float::parse_options options{chars_format::allow_leading_plus | chars_format::skip_white_space}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); + auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result); if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } input = "-23.14069263277926900572"; From 82477e93101064e7a1a75cc8f1a9f1bd8001daaa Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Thu, 27 Mar 2025 22:05:43 +0300 Subject: [PATCH 043/252] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 21768319..a0a792ea 100644 --- a/README.md +++ b/README.md @@ -386,7 +386,7 @@ the code size and improve performance: int main() { std::string input = "23.14069263277926900572"; double result; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result); + auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } input = "-23.14069263277926900572"; From 01e9d3545503cbbb81965dde62082e39819f2230 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 16:21:59 +0300 Subject: [PATCH 044/252] Tests updated and fixed. --- benchmarks/benchmark.cpp | 44 ++++++++++------------------------------ 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 0eedab97..50907526 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -56,7 +56,7 @@ Value findmax_fastfloat(std::vector> &s, time += std::chrono::duration_cast(t2 - t1); #endif - if (ec != std::errc{}) { + if (p == st.data()) { throw std::runtime_error("bug in findmax_fastfloat"); } answer = answer > x ? answer : x; @@ -171,7 +171,7 @@ void pretty_print(double volume, size_t number_of_floats, std::string const &nam std::pair result) { double volumeMB = volume / (1024. * 1024.); printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), - volumeMB * 1'000'000'000 / result.first, + volumeMB * 1000000000 / result.first, (result.second - result.first) * 100.0 / result.second); printf("%8.2f Mfloat/s ", number_of_floats * 1000 / result.first); printf(" %8.2f ns/f \n", double(result.first) / number_of_floats); @@ -198,7 +198,7 @@ std::vector widen(const std::vector &lines) { } void process(std::vector &lines, size_t volume) { - size_t repeat = 1000; + size_t const repeat = 1000; double volumeMB = volume / (1024. * 1024.); std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl; pretty_print(volume, lines.size(), "fastfloat (64)", @@ -232,44 +232,20 @@ void fileload(std::string filename) { size_t volume = 0; while (getline(inputfile, line)) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - /* This code is a simple parser emulator */ - for (size_t n = 0; n < line.size(); ++n) { - if ((line[n] >= '0' && line[n] <= '9')) { - /* in the real parser we don't check anything else - and call the from_chars function immediately */ - const auto s = n; - for (++n; n < line.size() && - ((line[n] >= '0' && line[n] <= '9') || line[n] == 'e' || - line[n] == 'E' || line[n] == '.' || line[n] == '-' || - line[n] == '+' - /* last line for exponent sign*/ - ); - ++n) { - } - /*~ in the real parser we don't check anything else - and call the from_chars function immediately */ - - volume += lines.emplace_back(line.substr(s, n)).size(); - } else { - /* for the test we simplify skipped all other symbols, - in real application this should be a full parser, - that parse also any mathematical operations like + and - - and this is the reason why we don't need to check a sign - when FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled. */ - ++n; - continue; - } + if (line[0] == '-') { + line.erase(0, 1); } - // in the real parser this part of code should return end token -#else - volume += lines.emplace_back(line).size(); #endif + volume += lines.emplace_back(line).size(); } std::cout << "# read " << lines.size() << " lines " << std::endl; process(lines, volume); } int main(int argc, char **argv) { +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled" << std::endl; +#endif #ifdef USING_COUNTERS if (collector.has_events()) { std::cout << "# Using hardware counters" << std::endl; @@ -285,6 +261,8 @@ int main(int argc, char **argv) { fileload(argv[1]); return EXIT_SUCCESS; } + fileload(std::string(BENCHMARK_DATA_DIR) + "/contrived.txt"); + fileload(std::string(BENCHMARK_DATA_DIR) + "/canada_short.txt"); fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt"); fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt"); return EXIT_SUCCESS; From 6687e734b09961493100541adadc4a2dc3497be3 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 17:49:40 +0300 Subject: [PATCH 045/252] Tests are updated. --- benchmarks/benchmark.cpp | 42 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 50907526..1e06e30a 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -27,59 +27,39 @@ #include "fast_float/fast_float.h" -#ifdef USING_COUNTERS -event_collector collector{}; -#else -std::chrono::high_resolution_clock::time_point t1, t2; -#endif - template -Value findmax_fastfloat(std::vector> &s, -#ifdef USING_COUNTERS - std::vector &aggregate -#else - std::chrono::nanoseconds &time -#endif -) { +Value findmax_fastfloat(std::vector> &s) { Value answer = 0; Value x = 0; -#ifdef USING_COUNTERS - collector.start(); -#endif for (auto &st : s) { -#ifndef USING_COUNTERS - t1 = std::chrono::high_resolution_clock::now(); -#endif auto [p, ec] = fast_float::from_chars(st.data(), st.data() + st.size(), x); -#ifndef USING_COUNTERS - t2 = std::chrono::high_resolution_clock::now(); - time += std::chrono::duration_cast(t2 - t1); -#endif if (p == st.data()) { throw std::runtime_error("bug in findmax_fastfloat"); } answer = answer > x ? answer : x; } -#ifdef USING_COUNTERS - aggregate.push_back(collector.end()); -#endif return answer; } #ifdef USING_COUNTERS + +event_collector collector{}; + template std::vector time_it_ns(std::vector> &lines, T const &function, size_t repeat) { std::vector aggregate; + collector.start(); bool printed_bug = false; for (size_t i = 0; i < repeat; i++) { - double ts = function(lines, aggregate); + double ts = function(lines); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; } + aggregate.push_back(collector.end()); } return aggregate; } @@ -148,18 +128,20 @@ template std::pair time_it_ns(std::vector> &lines, T const &function, size_t repeat) { + std::chrono::high_resolution_clock::time_point t1, t2; double average = 0; double min_value = DBL_MAX; bool printed_bug = false; for (size_t i = 0; i < repeat; i++) { - std::chrono::nanoseconds time{}; - const auto ts = function(lines, time); + t1 = std::chrono::high_resolution_clock::now(); + const auto ts = function(lines); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; } + t2 = std::chrono::high_resolution_clock::now(); double dif = - std::chrono::duration_cast(time).count(); + std::chrono::duration_cast(t2 - t1).count(); average += dif; min_value = min_value < dif ? min_value : dif; } From 34df2fc76b5bc17c51a8dd99cc91c86c679c5e10 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 17:54:06 +0300 Subject: [PATCH 046/252] Tests are updated. --- benchmarks/benchmark.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 1e06e30a..48b7cd25 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -51,10 +51,10 @@ std::vector time_it_ns(std::vector> &lines, T const &function, size_t repeat) { std::vector aggregate; - collector.start(); bool printed_bug = false; for (size_t i = 0; i < repeat; i++) { - double ts = function(lines); + collector.start(); + auto const ts = function(lines); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; @@ -134,7 +134,7 @@ time_it_ns(std::vector> &lines, T const &function, bool printed_bug = false; for (size_t i = 0; i < repeat; i++) { t1 = std::chrono::high_resolution_clock::now(); - const auto ts = function(lines); + auto const ts = function(lines); if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; From 8ebc89e1b5f9a9094296ae477bfd3f113260a292 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 18:31:01 +0300 Subject: [PATCH 047/252] Reduce registers pressure. --- include/fast_float/ascii_number.h | 10 ++++++---- include/fast_float/float_common.h | 14 +++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 30c7e165..83f9e1d3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -294,7 +294,9 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, parse_options_t const &options) noexcept { - + // V2008 Cyclomatic complexity: 59. + // Consider refactoring the 'parse_number_string' function. + // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. parsed_number_string_t answer; answer.valid = false; answer.too_many_digits = false; @@ -541,7 +543,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { - const uint8_t digit = ch_to_digit(*p); + uint8_t const digit = ch_to_digit(*p); if (digit >= options.base) { break; } @@ -550,7 +552,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, p++; } - size_t digit_count = size_t(p - start_digits); + uint8_t const digit_count = size_t(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { @@ -567,7 +569,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, answer.ptr = p; // check u64 overflow - size_t const max_digits = max_digits_u64(options.base); + uint8_t const max_digits = max_digits_u64(options.base); if (digit_count > max_digits) { answer.ec = std::errc::result_out_of_range; return answer; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 84f076f0..0a03a3a5 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -73,11 +73,11 @@ template struct parse_options_t { : format(fmt), decimal_point(dot), base(static_cast(b)) {} /** Which number formats are accepted */ - const chars_format format; + chars_format format; /** The character used as decimal point */ - const UC decimal_point; + UC decimal_point; /** The base used for integers */ - const uint8_t base; /* only allowed from 2 to 36 */ + uint8_t base; /* only allowed from 2 to 36 */ }; using parse_options = parse_options_t; @@ -1129,7 +1129,7 @@ template struct int_luts { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - static constexpr size_t maxdigits_u64[] = { + static constexpr uint8_t maxdigits_u64[] = { 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; @@ -1152,7 +1152,7 @@ template struct int_luts { template constexpr uint8_t int_luts::chdigit[]; -template constexpr size_t int_luts::maxdigits_u64[]; +template constexpr uint8_t int_luts::maxdigits_u64[]; template constexpr uint64_t int_luts::min_safe_u64[]; @@ -1163,13 +1163,13 @@ fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr size_t max_digits_u64(int base) { +fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { +fastfloat_really_inline constexpr uint8_t min_safe_u64(uint8_t base) { return int_luts<>::min_safe_u64[base - 2]; } From fc9f61efc92d267f69a183f0cc2901a109d1d1eb Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 18:55:57 +0300 Subject: [PATCH 048/252] Cleanup initialization of the adjusted_mantissa. --- include/fast_float/decimal_to_binary.h | 6 +++--- include/fast_float/float_common.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 028fbdce..94d0a000 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -103,15 +103,15 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept { adjusted_mantissa answer; if ((w == 0) || (q < binary::smallest_power_of_ten())) { - // answer.power2 = 0; already set - // answer.mantissa = 0; already set + answer.power2 = 0; + answer.mantissa = 0; // result should be zero return answer; } if (q > binary::largest_power_of_ten()) { // we want to get infinity: answer.power2 = binary::infinite_power(); - // answer.mantissa = 0; already set + answer.mantissa = 0; return answer; } // At this point in time q is in [powers::smallest_power_of_five, diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 0a03a3a5..6ca6beb9 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -423,8 +423,8 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { } struct adjusted_mantissa { - uint64_t mantissa{0}; - int32_t power2{0}; // a negative value indicates an invalid result + uint64_t mantissa; + int32_t power2; // a negative value indicates an invalid result adjusted_mantissa() noexcept = default; constexpr bool operator==(adjusted_mantissa const &o) const noexcept { From ed871096ade2e34aa8336ebbdc8fc94acdaeb4ee Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 18:57:37 +0300 Subject: [PATCH 049/252] Remove FASTFLOAT_CONSTEVAL20 that I was added before and cleanup diff. --- include/fast_float/ascii_number.h | 12 +++++------- include/fast_float/constexpr_feature_detect.h | 2 -- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 83f9e1d3..5ca52f5f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -208,8 +208,7 @@ template template ()) = 0> #endif // dummy for compile -FASTFLOAT_CONSTEVAL20 bool simd_parse_if_eight_digits_unrolled(UC const *, - uint64_t &) { +bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { return 0; } @@ -304,9 +303,8 @@ parse_number_string(UC const *p, UC const *pend, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if (*p == UC('-') || - (uint64_t(options.format & chars_format::allow_leading_plus) && - *p == UC('+'))) { + if ((*p == UC('-')) || (uint64_t(options.format & chars_format::allow_leading_plus) && + !basic_json_fmt && *p == UC('+'))) { ++p; if (p == pend) { return report_parse_error( @@ -320,8 +318,8 @@ parse_number_string(UC const *p, UC const *pend, } else { if (!is_integer(*p) && - (*p != options.decimal_point)) { // a sign must be followed by an - // integer or the dot + (*p != + options.decimal_point)) { // a sign must be followed by an integer or the dot return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 0a982542..0b5ca2de 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -44,11 +44,9 @@ defined(__cpp_lib_constexpr_algorithms) && \ __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ #define FASTFLOAT_CONSTEXPR20 constexpr -#define FASTFLOAT_CONSTEVAL20 consteval #define FASTFLOAT_IS_CONSTEXPR 1 #else #define FASTFLOAT_CONSTEXPR20 -#define FASTFLOAT_CONSTEVAL20 FASTFLOAT_CONSTEXPR14 #define FASTFLOAT_IS_CONSTEXPR 0 #endif From 91e6c4d440647c3427fc2942ec74fb4c9a59b182 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 19:39:10 +0300 Subject: [PATCH 050/252] . --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 6ca6beb9..9a716d98 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1169,7 +1169,7 @@ fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint8_t min_safe_u64(uint8_t base) { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) { return int_luts<>::min_safe_u64[base - 2]; } From afb54a595e0c9657f50161690b5d2074d1b0b898 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 20:15:19 +0300 Subject: [PATCH 051/252] Disable FASTFLOAT_ASSUME by default. --- include/fast_float/constexpr_feature_detect.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 0b5ca2de..57b7d529 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -56,8 +56,13 @@ #define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 #endif + // For support attribute [[assume]] is declared in P1774 -#if defined(__clang__) // needs testing +#if 1 // TODO needs platform specific tests for this +#define FASTFLOAT_ASSUME(expr) +#elif defined(__cpp_attrubute_assume) +#define FASTFLOAT_ASSUME(expr) [[assume(expr)]] +#elif defined(__clang__) // needs testing #define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) #elif defined(__GNUC__) && !defined(__ICC) // needs testing #define FASTFLOAT_ASSUME(expr) \ @@ -67,7 +72,7 @@ } #elif defined(__ICC) // needs testing #define FASTFLOAT_ASSUME(expr) __assume(expr) -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) // needs testing /* currently disable, because MSVC is generated slower code when enabled, it's probably reason why MSVC doesnt have [[assume]] */ #define FASTFLOAT_ASSUME(expr) /*__assume(expr)*/ From 6aea2fb2e5bbffb657fa22337ec47e6be37e2594 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 20:27:39 +0300 Subject: [PATCH 052/252] initialization cleanup. --- include/fast_float/ascii_number.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 5ca52f5f..1edfc421 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -297,8 +297,6 @@ parse_number_string(UC const *p, UC const *pend, // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. parsed_number_string_t answer; - answer.valid = false; - answer.too_many_digits = false; FASTFLOAT_ASSUME(p < pend); // assume p < pend, so dereference without checks; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); From ee620a029dcc3f1ac736174f9bf5f44620ab3645 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 28 Mar 2025 20:29:25 +0300 Subject: [PATCH 053/252] reduce registers pressure. --- include/fast_float/float_common.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 9a716d98..37761183 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -427,10 +427,12 @@ struct adjusted_mantissa { int32_t power2; // a negative value indicates an invalid result adjusted_mantissa() noexcept = default; + fastfloat_really_inline constexpr bool operator==(adjusted_mantissa const &o) const noexcept { return mantissa == o.mantissa && power2 == o.power2; } + fastfloat_really_inline constexpr bool operator!=(adjusted_mantissa const &o) const noexcept { return mantissa != o.mantissa || power2 != o.power2; } @@ -447,10 +449,10 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - static constexpr int mantissa_explicit_bits(); + static constexpr unsigned int mantissa_explicit_bits(); static constexpr int minimum_exponent(); static constexpr int infinite_power(); - static constexpr int sign_index(); + static constexpr unsigned int sign_index(); static constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr int max_exponent_fast_path(); @@ -462,7 +464,7 @@ template struct binary_format : binary_format_lookup_tables { static constexpr int largest_power_of_ten(); static constexpr int smallest_power_of_ten(); static constexpr T exact_power_of_ten(int64_t power); - static constexpr size_t max_digits(); + static constexpr unsigned int max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); static constexpr equiv_uint hidden_bit_mask(); @@ -570,12 +572,12 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr unsigned int binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr unsigned int binary_format::mantissa_explicit_bits() { return 23; } @@ -617,11 +619,11 @@ template <> inline constexpr int binary_format::infinite_power() { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr unsigned int binary_format::sign_index() { return 63; } -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr unsigned int binary_format::sign_index() { return 31; } @@ -706,7 +708,7 @@ inline constexpr int binary_format::max_exponent_fast_path() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr unsigned int binary_format::mantissa_explicit_bits() { return 10; } @@ -755,7 +757,7 @@ inline constexpr int binary_format::infinite_power() { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr unsigned int binary_format::sign_index() { return 15; } @@ -772,7 +774,7 @@ inline constexpr int binary_format::smallest_power_of_ten() { } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr unsigned int binary_format::max_digits() { return 22; } #endif // __STDCPP_FLOAT16_T__ @@ -833,7 +835,7 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr unsigned int binary_format::mantissa_explicit_bits() { return 7; } @@ -899,7 +901,7 @@ inline constexpr int binary_format::smallest_power_of_ten() { } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr unsigned int binary_format::max_digits() { return 98; } #endif // __STDCPP_BFLOAT16_T__ @@ -954,11 +956,11 @@ template <> inline constexpr int binary_format::smallest_power_of_ten() { return -64; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr unsigned int binary_format::max_digits() { return 769; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr unsigned int binary_format::max_digits() { return 114; } From 1651c2b0f854828305f60e51439b08481e9b0277 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 7 Apr 2025 23:10:38 +0300 Subject: [PATCH 054/252] Readded FASTFLOAT_CONSTEVAL, but not used currently. Cleanup for FASTFLOAT_ASSUME. --- include/fast_float/constexpr_feature_detect.h | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 57b7d529..d4399b0b 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -23,8 +23,10 @@ #if defined(__cpp_lib_is_constant_evaluated) && \ __cpp_lib_is_constant_evaluated >= 201811L #define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 +#define FASTFLOAT_CONSTEVAL consteval #else #define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 +#define FASTFLOAT_CONSTEVAL FASTFLOAT_CONSTEXPR14 #endif #if defined(__cpp_lib_byteswap) @@ -58,24 +60,10 @@ // For support attribute [[assume]] is declared in P1774 -#if 1 // TODO needs platform specific tests for this -#define FASTFLOAT_ASSUME(expr) -#elif defined(__cpp_attrubute_assume) +#if defined(__cpp_attrubute_assume) #define FASTFLOAT_ASSUME(expr) [[assume(expr)]] -#elif defined(__clang__) // needs testing -#define FASTFLOAT_ASSUME(expr) __builtin_assume(expr) -#elif defined(__GNUC__) && !defined(__ICC) // needs testing -#define FASTFLOAT_ASSUME(expr) \ - if (expr) { \ - } else { \ - __builtin_unreachable(); \ - } -#elif defined(__ICC) // needs testing -#define FASTFLOAT_ASSUME(expr) __assume(expr) -#elif defined(_MSC_VER) // needs testing -/* currently disable, because MSVC is generated slower code when enabled, -it's probably reason why MSVC doesnt have [[assume]] */ -#define FASTFLOAT_ASSUME(expr) /*__assume(expr)*/ +#else +#define FASTFLOAT_ASSUME(expr) #endif #endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H From 3faba016afee8705b59cd342f136d5846f80b194 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 7 Apr 2025 23:14:49 +0300 Subject: [PATCH 055/252] Remove PVS. --- benchmarks/benchmark.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 48b7cd25..a493cfbd 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: https://pvs-studio.com - //#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 4f0615b4b423683db0456ff9024e3f09b34b8436 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 7 Apr 2025 23:21:29 +0300 Subject: [PATCH 056/252] Reduce register pressure and cleanup interface for standard. --- include/fast_float/ascii_number.h | 39 +++++++++++++-------------- include/fast_float/digit_comparison.h | 32 +++++++++++----------- include/fast_float/float_common.h | 38 ++++++++++++++------------ 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 1edfc421..9236eca9 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -260,7 +260,7 @@ enum class parse_error { }; template struct parsed_number_string_t { - int64_t exponent{0}; + int16_t exponent{0}; uint64_t mantissa{0}; UC const *lastmatch{nullptr}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -293,11 +293,11 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, parse_options_t const &options) noexcept { - // V2008 Cyclomatic complexity: 59. + // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. parsed_number_string_t 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 answer.negative = (*p == UC('-')); // 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; } 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(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -353,7 +353,7 @@ parse_number_string(UC const *p, UC const *pend, } #endif - int64_t exponent = 0; + int16_t exponent = 0; bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); if (has_decimal_point) { ++p; @@ -363,11 +363,11 @@ parse_number_string(UC const *p, UC const *pend, loop_parse_if_eight_digits(p, pend, i); while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - UC('0')); - ++p; + uint8_t const digit = uint8_t(*p - UC('0')); i = i * 10 + digit; // in rare cases, this will overflow, but that's ok + ++p; } - exponent = before - p; + exponent = static_cast(before - p); answer.fraction = span(before, size_t(p - before)); 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! return report_parse_error(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) && ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint64_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) + || (uint64_t(options.format & chars_format::fortran) && + ((UC('+') == *p) || (UC('-') == *p) + || (UC('d') == *p) || (UC('D') == *p))) #endif ) { UC const *location_of_e = p; if (((UC('e') == *p) || (UC('E') == *p)) #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 ) { ++p; @@ -421,10 +422,8 @@ parse_number_string(UC const *p, UC const *pend, p = location_of_e; } else { while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - UC('0')); - if (exp_number < 0x10000000) { - exp_number = 10 * exp_number + digit; - } + uint8_t const digit = uint8_t(*p - UC('0')); + exp_number = 10 * exp_number + digit; ++p; } if (neg_exp) { @@ -475,7 +474,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } if (i >= minimal_nineteen_digit_integer) { // We have a big integers - exponent = end_of_integer_part - p + exp_number; + exponent = static_cast(end_of_integer_part - p) + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; 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')); ++p; } - exponent = answer.fraction.ptr - p + exp_number; + exponent = static_cast(answer.fraction.ptr - p) + exp_number; } // 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++; } - uint8_t const digit_count = size_t(p - start_digits); + uint8_t const digit_count = static_cast(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index a2869f8d..ffac7fd1 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -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 // to slow down performance for faster algorithms, and this is still fast. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t scientific_exponent(const parsed_number_string_t &num) noexcept { uint64_t mantissa = num.mantissa; - int32_t exponent = int32_t(num.exponent); + int16_t exponent = num.exponent; while (mantissa >= 10000) { mantissa /= 10000; exponent += 4; @@ -223,8 +223,8 @@ is_truncated(span s) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, unsigned int &counter, - unsigned int &count) noexcept { +parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, + uint16_t &count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; counter += 8; @@ -233,8 +233,8 @@ parse_eight_digits(UC const *&p, limb &value, unsigned int &counter, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, unsigned int &counter, - unsigned int &count) noexcept { +parse_one_digit(UC const *&p, limb &value, uint16_t &counter, + uint16_t &count) noexcept { value = value * 10 + limb(*p - UC('0')); p++; counter++; @@ -248,7 +248,7 @@ add_native(bigint &big, limb power, limb value) noexcept { } 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 // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); @@ -259,17 +259,17 @@ round_up_bigint(bigint &big, unsigned int &count) noexcept { template inline FASTFLOAT_CONSTEXPR20 void parse_mantissa(bigint &result, const parsed_number_string_t &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. // therefore, try to parse 8 digits at a time, and multiply by the largest // scalar value (9 or 19 digits) for each step. - unsigned int counter = 0; + uint16_t counter = 0; digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - unsigned int step = 19; + uint16_t const step = 19; #else - unsigned int step = 9; + uint16_t const step = 9; #endif // process all integer digits. @@ -370,7 +370,7 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { // are of the same magnitude. template 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 { bigint &real_digits = bigmant; const int32_t &real_exp = exponent; @@ -443,13 +443,13 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( // remove the invalid exponent bias am.power2 -= invalid_am_bias; - int32_t sci_exp = scientific_exponent(num); - unsigned int max_digits = binary_format::max_digits(); - unsigned int digits = 0; + int16_t sci_exp = scientific_exponent(num); + uint16_t const max_digits = static_cast(binary_format::max_digits()); + uint16_t digits = 0; bigint bigmant; parse_mantissa(bigmant, num, max_digits, 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) { return positive_digit_comp(bigmant, exponent); } else { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 37761183..adb56a3e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -69,7 +69,7 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( 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(b)) {} /** Which number formats are accepted */ @@ -427,12 +427,10 @@ struct adjusted_mantissa { int32_t power2; // a negative value indicates an invalid result adjusted_mantissa() noexcept = default; - fastfloat_really_inline constexpr bool operator==(adjusted_mantissa const &o) const noexcept { return mantissa == o.mantissa && power2 == o.power2; } - fastfloat_really_inline constexpr bool operator!=(adjusted_mantissa const &o) const noexcept { return mantissa != o.mantissa || power2 != o.power2; } @@ -449,10 +447,10 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - static constexpr unsigned int mantissa_explicit_bits(); + static constexpr int mantissa_explicit_bits(); static constexpr int minimum_exponent(); static constexpr int infinite_power(); - static constexpr unsigned int sign_index(); + static constexpr int sign_index(); static constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr int max_exponent_fast_path(); @@ -464,7 +462,7 @@ template struct binary_format : binary_format_lookup_tables { static constexpr int largest_power_of_ten(); static constexpr int smallest_power_of_ten(); 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 mantissa_mask(); static constexpr equiv_uint hidden_bit_mask(); @@ -572,12 +570,12 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr unsigned int binary_format::mantissa_explicit_bits() { +inline constexpr int binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr unsigned int binary_format::mantissa_explicit_bits() { +inline constexpr int binary_format::mantissa_explicit_bits() { return 23; } @@ -619,11 +617,11 @@ template <> inline constexpr int binary_format::infinite_power() { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr unsigned int binary_format::sign_index() { +template <> inline constexpr int binary_format::sign_index() { return 63; } -template <> inline constexpr unsigned int binary_format::sign_index() { +template <> inline constexpr int binary_format::sign_index() { return 31; } @@ -708,7 +706,7 @@ inline constexpr int binary_format::max_exponent_fast_path() { } template <> -inline constexpr unsigned int binary_format::mantissa_explicit_bits() { +inline constexpr int binary_format::mantissa_explicit_bits() { return 10; } @@ -835,7 +833,7 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr unsigned int binary_format::mantissa_explicit_bits() { +inline constexpr int binary_format::mantissa_explicit_bits() { return 7; } @@ -910,7 +908,7 @@ template <> inline constexpr uint64_t binary_format::max_mantissa_fast_path(int64_t power) { // 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 return (void)max_mantissa[0], max_mantissa[power]; @@ -920,7 +918,7 @@ template <> inline constexpr uint64_t binary_format::max_mantissa_fast_path(int64_t power) { // 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 return (void)max_mantissa[0], max_mantissa[power]; @@ -929,12 +927,18 @@ binary_format::max_mantissa_fast_path(int64_t power) { template <> inline constexpr double binary_format::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 return (void)powers_of_ten[0], powers_of_ten[power]; } template <> inline constexpr float binary_format::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 return (void)powers_of_ten[0], powers_of_ten[power]; } @@ -956,11 +960,11 @@ template <> inline constexpr int binary_format::smallest_power_of_ten() { return -64; } -template <> inline constexpr unsigned int binary_format::max_digits() { +template <> inline constexpr size_t binary_format::max_digits() { return 769; } -template <> inline constexpr unsigned int binary_format::max_digits() { +template <> inline constexpr size_t binary_format::max_digits() { return 114; } @@ -1005,7 +1009,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool const negative, #endif - adjusted_mantissa const &am, T &value) noexcept { + adjusted_mantissa const am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) From 8212e9e919dd53006567c2404f064257c4fd9d2c Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 01:14:45 +0300 Subject: [PATCH 057/252] fix warnings in the benchmark. --- benchmarks/benchmark.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index a493cfbd..0d045bd5 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -61,7 +61,7 @@ time_it_ns(std::vector> &lines, T const &function, return aggregate; } -void pretty_print(double volume, size_t number_of_floats, std::string name, +void pretty_print(size_t volume, size_t number_of_floats, std::string name, std::vector events) { double volumeMB = volume / (1024. * 1024.); double average_ns{0}; @@ -137,8 +137,8 @@ time_it_ns(std::vector> &lines, T const &function, printed_bug = true; } t2 = std::chrono::high_resolution_clock::now(); - double dif = - std::chrono::duration_cast(t2 - t1).count(); + double const dif = static_cast( + std::chrono::duration_cast(t2 - t1).count()); average += dif; min_value = min_value < dif ? min_value : dif; } @@ -146,7 +146,7 @@ time_it_ns(std::vector> &lines, T const &function, return std::make_pair(min_value, average); } -void pretty_print(double volume, size_t number_of_floats, std::string const &name, +void pretty_print(size_t volume, size_t number_of_floats, std::string const &name, std::pair result) { double volumeMB = volume / (1024. * 1024.); printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), From b261492ae7423ba8333be36fcf2c7858d7f2eea9 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 01:22:14 +0300 Subject: [PATCH 058/252] reduce register pressure. --- include/fast_float/digit_comparison.h | 61 +++++++++++++-------------- include/fast_float/float_common.h | 6 +-- include/fast_float/parse_number.h | 2 +- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index ffac7fd1..6229653c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -40,7 +40,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, // to slow down performance for faster algorithms, and this is still fast. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t -scientific_exponent(const parsed_number_string_t &num) noexcept { +scientific_exponent(parsed_number_string_t const &num) noexcept { uint64_t mantissa = num.mantissa; int16_t exponent = num.exponent; while (mantissa >= 10000) { @@ -61,7 +61,7 @@ scientific_exponent(const parsed_number_string_t &num) noexcept { // this converts a native floating-point number to an extended-precision float. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended(T value) noexcept { +to_extended(T const &value) noexcept { using equiv_uint = equiv_uint_t; constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); @@ -96,7 +96,7 @@ to_extended(T value) noexcept { // halfway between b and b+u. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended_halfway(T value) noexcept { +to_extended_halfway(T const &value) noexcept { adjusted_mantissa am = to_extended(value); am.mantissa <<= 1; am.mantissa += 1; @@ -341,17 +341,17 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, } template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 void +positive_digit_comp(bigint &bigmant, adjusted_mantissa &am, + int32_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); - adjusted_mantissa answer; bool truncated; - answer.mantissa = bigmant.hi64(truncated); - int bias = binary_format::mantissa_explicit_bits() - + am.mantissa = bigmant.hi64(truncated); + int32_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - answer.power2 = bigmant.bit_length() - 64 + bias; + am.power2 = bigmant.bit_length() - 64 + bias; - round(answer, [truncated](adjusted_mantissa &a, int32_t shift) { + round(am, [truncated](adjusted_mantissa &a, int32_t shift) { round_nearest_tie_even( a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { @@ -359,8 +359,6 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { (is_odd && is_halfway); }); }); - - return answer; } // the scaling here is quite simple: we have, for the real digits `m * 10^e`, @@ -369,24 +367,26 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -negative_digit_comp(bigint &bigmant, const adjusted_mantissa am, - const int32_t exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 void +negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, + int32_t const exponent) noexcept { bigint &real_digits = bigmant; const int32_t &real_exp = exponent; - // get the value of `b`, rounded down, and get a bigint representation of b+h - adjusted_mantissa am_b = am; - // gcc7 buf: use a lambda to remove the noexcept qualifier bug with - // -Wnoexcept-type. - round(am_b, - [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); T b; - to_float( + { + // get the value of `b`, rounded down, and get a bigint representation of b+h + adjusted_mantissa am_b = am; + // gcc7 bug: use a lambda to remove the noexcept qualifier bug with + // -Wnoexcept-type. + round(am_b, + [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); + to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - false, + false, #endif - am_b, b); + am_b, b); + } adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); int32_t theor_exp = theor.power2; @@ -405,8 +405,7 @@ negative_digit_comp(bigint &bigmant, const adjusted_mantissa am, // compare digits, and use it to director rounding int ord = real_digits.compare(theor_digits); - adjusted_mantissa answer = am; - round(answer, [ord](adjusted_mantissa &a, int32_t shift) { + round(am, [ord](adjusted_mantissa &a, int32_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { (void)_; // not needed, since we've done our comparison @@ -420,8 +419,6 @@ negative_digit_comp(bigint &bigmant, const adjusted_mantissa am, } }); }); - - return answer; } // parse the significant digits as a big integer to unambiguously round the @@ -438,8 +435,8 @@ negative_digit_comp(bigint &bigmant, const adjusted_mantissa am, // the actual digits. we then compare the big integer representations // of both, and use that to direct rounding. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( - const parsed_number_string_t &num, adjusted_mantissa &am) noexcept { +inline FASTFLOAT_CONSTEXPR20 void digit_comp( + parsed_number_string_t const &num, adjusted_mantissa &am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; @@ -451,9 +448,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( // can't underflow, since digits is at most max_digits. int16_t exponent = sci_exp + 1 - digits; if (exponent >= 0) { - return positive_digit_comp(bigmant, exponent); + positive_digit_comp(bigmant, am, exponent); } else { - return negative_digit_comp(bigmant, am, exponent); + negative_digit_comp(bigmant, am, exponent); } } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index adb56a3e..5153b30b 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -772,7 +772,7 @@ inline constexpr int binary_format::smallest_power_of_ten() { } template <> -inline constexpr unsigned int binary_format::max_digits() { +inline constexpr size_t binary_format::max_digits() { return 22; } #endif // __STDCPP_FLOAT16_T__ @@ -899,7 +899,7 @@ inline constexpr int binary_format::smallest_power_of_ten() { } template <> -inline constexpr unsigned int binary_format::max_digits() { +inline constexpr size_t binary_format::max_digits() { return 98; } #endif // __STDCPP_BFLOAT16_T__ @@ -1009,7 +1009,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool const negative, #endif - adjusted_mantissa const am, T &value) noexcept { + adjusted_mantissa const &am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index e5c08bea..677a1461 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -283,7 +283,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { // and we have an invalid power (am.power2 < 0), then we need to go the long // way around again. This is very uncommon. if (am.power2 < 0) { - am = digit_comp(pns, am); + digit_comp(pns, am); } to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From a133b72fa803afc19be5bc9bf0275f27778372ba Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 03:24:11 +0300 Subject: [PATCH 059/252] FASTFLOAT_ASSUME --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 5153b30b..143df1be 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -197,12 +197,12 @@ using parse_options = parse_options_t; #ifndef FASTFLOAT_ASSERT #define FASTFLOAT_ASSERT(x) \ - { ((void)(x)); } + { ((void)(x)); FASTFLOAT_ASSUME(x); } #endif #ifndef FASTFLOAT_DEBUG_ASSERT #define FASTFLOAT_DEBUG_ASSERT(x) \ - { ((void)(x)); } + { ((void)(x)); FASTFLOAT_ASSUME(x); } #endif // rust style `try!()` macro, or `?` operator From b121f533160ff6be21471f49ea4f15d0fa14bf40 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 03:55:12 +0300 Subject: [PATCH 060/252] reduce register pressure. --- include/fast_float/bigint.h | 18 +++++++++--------- include/fast_float/decimal_to_binary.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index e609f69f..4e3e06c3 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -37,10 +37,10 @@ constexpr size_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. -template struct stackvec { +template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint16_t length{0}; + uint8_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; @@ -72,14 +72,14 @@ template struct stackvec { // set the length, without bounds checking. FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { - length = uint16_t(len); + length = uint8_t(len); } - constexpr size_t len() const noexcept { return length; } + constexpr uint8_t len() const noexcept { return length; } constexpr bool is_empty() const noexcept { return length == 0; } - constexpr size_t capacity() const noexcept { return size; } + constexpr uint8_t capacity() const noexcept { return size; } // append item to vector, without bounds checking FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { @@ -375,7 +375,7 @@ FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { } template struct pow5_tables { - static constexpr uint32_t large_step = 135; + static constexpr uint8_t large_step = 135; static constexpr uint64_t small_power_of_5[] = { 1UL, 5UL, @@ -419,7 +419,7 @@ template struct pow5_tables { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint32_t pow5_tables::large_step; +template constexpr uint8_t pow5_tables::large_step; template constexpr uint64_t pow5_tables::small_power_of_5[]; @@ -605,10 +605,10 @@ struct bigint : pow5_tables<> { exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - uint32_t small_step = 27; + uint8_t small_step = 27; limb max_native = 7450580596923828125UL; #else - uint32_t small_step = 13; + uint8_t small_step = 13; limb max_native = 1220703125U; #endif while (exp >= small_step) { diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 94d0a000..cdff8469 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); From 5c610807de3a32e97abf9be943f7fe03ea998f8e Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 04:04:26 +0300 Subject: [PATCH 061/252] improvements of memory layout of parsed_number_string_t. fix for FORTRAN parsing (needs to be merge to main) improvement in the debug build. code cleanup. --- include/fast_float/ascii_number.h | 38 +++++++++++++------------------ 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9236eca9..cc4bd2ad 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -260,9 +260,8 @@ enum class parse_error { }; template struct parsed_number_string_t { - int16_t exponent{0}; uint64_t mantissa{0}; - UC const *lastmatch{nullptr}; + int16_t exponent{0}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif @@ -271,6 +270,7 @@ template struct parsed_number_string_t { // contains the range of the significant digits span integer{}; // non-nullable span fraction{}; // nullable + UC const *lastmatch{nullptr}; parse_error error{parse_error::no_error}; }; @@ -338,7 +338,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } UC const *const end_of_integer_part = p; - int16_t digit_count = static_cast(end_of_integer_part - start_digits); + uint16_t digit_count = uint16_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -384,30 +384,24 @@ parse_number_string(UC const *p, UC const *pend, return report_parse_error(p, parse_error::no_digits_in_mantissa); } int16_t exp_number = 0; // explicit exponential part - if ((uint64_t(options.format & chars_format::scientific) && (p != pend) && + if (p != pend && + (uint64_t(options.format & chars_format::scientific) && ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint64_t(options.format & chars_format::fortran) && - ((UC('+') == *p) || (UC('-') == *p) - || (UC('d') == *p) || (UC('D') == *p))) + || (uint64_t(options.format & detail::basic_fortran_fmt) && + (UC('d') == *p) || (UC('D') == *p)) #endif ) { UC const *location_of_e = p; - if (((UC('e') == *p) || (UC('E') == *p)) -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint64_t(options.format & chars_format::fortran) && - ((UC('d') == *p) || (UC('D') == *p))) -#endif - ) { - ++p; - } + ++p; + bool neg_exp = false; if (p != pend) { if (UC('-') == *p) { neg_exp = true; ++p; - } else if (UC('+') == - *p) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + } else if (UC('+') == *p) { + // '+' on exponent is allowed by C++17 20.19.3.(7.1) ++p; } } @@ -455,9 +449,9 @@ parse_number_string(UC const *p, UC const *pend, while ((start != pend) && (*start == UC('0') || *start == options.decimal_point)) { if (*start == UC('0')) { - digit_count--; + --digit_count; } - start++; + ++start; } if (digit_count > 19) { @@ -524,7 +518,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_num = p; - // use SIMD if possible + // use SIMD here? while (p != pend && *p == UC('0')) { ++p; } @@ -542,12 +536,12 @@ parse_int_string(UC const *p, UC const *pend, T &value, if (digit >= options.base) { break; } - i = static_cast(options.base) * i + + i = uint64_t(options.base) * i + digit; // might overflow, check this later p++; } - uint8_t const digit_count = static_cast(p - start_digits); + uint8_t const digit_count = uint8_t(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { From 27f02654fe930717b34df71720ac83c0c35b3a10 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 04:06:30 +0300 Subject: [PATCH 062/252] style cleanup. --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index cc4bd2ad..016aec18 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -367,7 +367,7 @@ parse_number_string(UC const *p, UC const *pend, i = i * 10 + digit; // in rare cases, this will overflow, but that's ok ++p; } - exponent = static_cast(before - p); + exponent = int16_t(before - p); answer.fraction = span(before, size_t(p - before)); digit_count -= exponent; } From 97bfec6ea3560d5b74997e882df4fe7d01bb9337 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 15:01:25 +0300 Subject: [PATCH 063/252] style fix. --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 016aec18..04a9e017 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -468,7 +468,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } if (i >= minimal_nineteen_digit_integer) { // We have a big integers - exponent = static_cast(end_of_integer_part - p) + exp_number; + exponent = uint16_t(end_of_integer_part - p) + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); @@ -476,7 +476,7 @@ parse_number_string(UC const *p, UC const *pend, i = i * 10 + uint64_t(*p - UC('0')); ++p; } - exponent = static_cast(answer.fraction.ptr - p) + exp_number; + exponent = uint16_t(answer.fraction.ptr - p) + exp_number; } // We have now corrected both exponent and i, to a truncated value } From b8f77719d1a6bc641299abf0a497bbe7fb5a092c Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 18:23:27 +0300 Subject: [PATCH 064/252] after all sized checks is done I return the minimum registers size possible for the counter. Because the library only support 32 and 64 bit platform we only need 32 bit as a small counter. --- include/fast_float/ascii_number.h | 8 +-- include/fast_float/bigint.h | 96 +++++++++++++++---------------- include/fast_float/float_common.h | 17 +++--- 3 files changed, 61 insertions(+), 60 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 04a9e017..53e3b638 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -338,8 +338,8 @@ parse_number_string(UC const *p, UC const *pend, ++p; } UC const *const end_of_integer_part = p; - uint16_t digit_count = uint16_t(end_of_integer_part - start_digits); - answer.integer = span(start_digits, size_t(digit_count)); + uint32_t digit_count = uint32_t(end_of_integer_part - start_digits); + answer.integer = span(start_digits, digit_count); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in integer part, without leading zeros @@ -368,7 +368,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } exponent = int16_t(before - p); - answer.fraction = span(before, size_t(p - before)); + answer.fraction = span(before, uint32_t(p - before)); digit_count -= exponent; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -541,7 +541,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, p++; } - uint8_t const digit_count = uint8_t(p - start_digits); + uint32_t const digit_count = uint32_t(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 4e3e06c3..7a481b4c 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -19,11 +19,11 @@ namespace fast_float { #if defined(FASTFLOAT_64BIT) && !defined(__sparc) #define FASTFLOAT_64BIT_LIMB 1 typedef uint64_t limb; -constexpr size_t limb_bits = 64; +constexpr uint32_t limb_bits = 64; #else #define FASTFLOAT_32BIT_LIMB typedef uint32_t limb; -constexpr size_t limb_bits = 32; +constexpr uint32_t limb_bits = 32; #endif typedef span limb_span; @@ -32,15 +32,15 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -constexpr size_t bigint_bits = 4000; -constexpr size_t bigint_limbs = bigint_bits / limb_bits; +constexpr uint32_t bigint_bits = 4000; +constexpr uint32_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. -template struct stackvec { +template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint8_t length{0}; + uint32_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; @@ -53,38 +53,38 @@ template struct stackvec { FASTFLOAT_ASSERT(try_extend(s)); } - FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept { + FASTFLOAT_CONSTEXPR14 limb &operator[](uint32_t index) noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } - FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &operator[](uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } // index from the end of the container - FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &rindex(uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - size_t rindex = length - index - 1; + uint32_t rindex = length - index - 1; return data[rindex]; } // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { - length = uint8_t(len); + FASTFLOAT_CONSTEXPR14 void set_len(uint32_t len) noexcept { + length = len; } - constexpr uint8_t len() const noexcept { return length; } + constexpr uint32_t len() const noexcept { return length; } constexpr bool is_empty() const noexcept { return length == 0; } - constexpr uint8_t capacity() const noexcept { return size; } + constexpr uint32_t capacity() const noexcept { return size; } // append item to vector, without bounds checking FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { data[length] = value; - length++; + ++length; } // append item to vector, returning if item was added @@ -118,9 +118,9 @@ template struct stackvec { // if the new size is longer than the vector, assign value to each // appended item. FASTFLOAT_CONSTEXPR20 - void resize_unchecked(size_t new_len, limb value) noexcept { + void resize_unchecked(uint32_t new_len, limb value) noexcept { if (new_len > len()) { - size_t count = new_len - len(); + uint32_t count = new_len - len(); limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); @@ -131,7 +131,7 @@ template struct stackvec { } // try to resize the vector, returning if the vector was resized. - FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { + FASTFLOAT_CONSTEXPR20 bool try_resize(uint32_t new_len, limb value) noexcept { if (new_len > capacity()) { return false; } else { @@ -143,12 +143,12 @@ template struct stackvec { // check if any limbs are non-zero after the given index. // this needs to be done in reverse order, since the index // is relative to the most significant limbs. - FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 bool nonzero(uint32_t index) const noexcept { while (index < len()) { if (rindex(index) != 0) { return true; } - index++; + ++index; } return false; } @@ -156,7 +156,7 @@ template struct stackvec { // normalize the big integer, so most-significant zero limbs are removed. FASTFLOAT_CONSTEXPR14 void normalize() noexcept { while (len() > 0 && rindex(0) == 0) { - length--; + --length; } } }; @@ -258,16 +258,16 @@ scalar_mul(limb x, limb y, limb &carry) noexcept { // add scalar value to bigint starting from offset. // used in grade school multiplication -template +template inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, - size_t start) noexcept { - size_t index = start; + uint32_t start) noexcept { + uint32_t index = start; limb carry = y; bool overflow; while (carry != 0 && index < vec.len()) { vec[index] = scalar_add(vec[index], carry, overflow); carry = limb(overflow); - index += 1; + ++index; } if (carry != 0) { FASTFLOAT_TRY(vec.try_push(carry)); @@ -276,18 +276,18 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, } // add scalar value to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool small_add(stackvec &vec, limb y) noexcept { return small_add_from(vec, y, 0); } // multiply bigint by scalar value. -template +template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (size_t index = 0; index < vec.len(); index++) { + for (uint32_t index = 0; index != vec.len(); ++index) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -298,9 +298,9 @@ inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, // add bigint to bigint starting from index. // used in grade school multiplication -template +template FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, - size_t start) noexcept { + uint32_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { @@ -308,7 +308,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } bool carry = false; - for (size_t index = 0; index < y.len(); index++) { + for (uint32_t index = 0; index < y.len(); ++index) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -329,14 +329,14 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } // add bigint to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y) noexcept { return large_add_from(x, y, 0); } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { limb_span xs = limb_span(x.data, x.len()); stackvec z(xs); @@ -345,7 +345,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { if (y.len() != 0) { limb y0 = y[0]; FASTFLOAT_TRY(small_mul(x, y0)); - for (size_t index = 1; index < y.len(); index++) { + for (uint32_t index = 1; index != y.len(); ++index) { limb yi = y[index]; stackvec zi; if (yi != 0) { @@ -364,7 +364,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { if (y.len() == 1) { FASTFLOAT_TRY(small_mul(x, y[0])); @@ -493,7 +493,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (size_t index = vec.len(); index > 0; index--) { + for (uint32_t index = vec.len(); index > 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -508,7 +508,7 @@ struct bigint : pow5_tables<> { // shift left each limb n bits, carrying over to the new limb // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_bits(uint32_t n) noexcept { // Internally, for each item, we shift left by n, and add the previous // right shifted limb-bits. // For example, we transform (for u8) shifted left 2, to: @@ -517,10 +517,10 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - size_t const shl = n; - size_t const shr = limb_bits - shl; + uint32_t const shl = n; + uint32_t const shr = limb_bits - shl; limb prev = 0; - for (size_t index = 0; index < vec.len(); index++) { + for (uint32_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; @@ -534,7 +534,7 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_limbs(uint32_t n) noexcept { FASTFLOAT_DEBUG_ASSERT(n != 0); if (n + vec.len() > vec.capacity()) { return false; @@ -555,9 +555,9 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` bits. - FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { - size_t const rem = n % limb_bits; - size_t const div = n / limb_bits; + FASTFLOAT_CONSTEXPR20 bool shl(uint32_t n) noexcept { + uint32_t const rem = n % limb_bits; + uint32_t const div = n / limb_bits; if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -605,11 +605,11 @@ struct bigint : pow5_tables<> { exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - uint8_t small_step = 27; - limb max_native = 7450580596923828125UL; + uint32_t const small_step = 27; + limb const max_native = 7450580596923828125UL; #else - uint8_t small_step = 13; - limb max_native = 1220703125U; + uint32_t const small_step = 13; + limb const max_native = 1220703125U; #endif while (exp >= small_step) { FASTFLOAT_TRY(small_mul(vec, max_native)); diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 143df1be..1b4362d4 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -70,14 +70,15 @@ template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format fmt = chars_format::general, UC dot = UC('.'), int const b = 10) noexcept - : format(fmt), decimal_point(dot), base(static_cast(b)) {} + : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ - uint8_t base; /* only allowed from 2 to 36 */ + uint32_t base; /* only allowed from 2 to 36 */ + FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; using parse_options = parse_options_t; @@ -288,15 +289,15 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - size_t length; + uint32_t length; - constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} + constexpr span(T const *_ptr, uint32_t _length) : ptr(_ptr), length(_length) {} constexpr span() : ptr(nullptr), length(0) {} - constexpr size_t len() const noexcept { return length; } + constexpr uint32_t len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T &operator[](uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -1169,13 +1170,13 @@ fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { +fastfloat_really_inline constexpr uint8_t max_digits_u64(uint32_t base) { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint32_t base) { return int_luts<>::min_safe_u64[base - 2]; } From f1b7f493aaaf866dc24597ecc860c61789586e1a Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 8 Apr 2025 18:23:27 +0300 Subject: [PATCH 065/252] after all sized checks is done I return the minimum registers size possible for the counter. Because the library only support 32 and 64 bit platform we only need 32 bit as a small counter. --- include/fast_float/ascii_number.h | 20 +++--- include/fast_float/bigint.h | 96 +++++++++++++------------- include/fast_float/decimal_to_binary.h | 2 +- include/fast_float/digit_comparison.h | 30 ++++---- include/fast_float/float_common.h | 17 ++--- 5 files changed, 83 insertions(+), 82 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 04a9e017..fcbbfe9b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -261,7 +261,7 @@ enum class parse_error { template struct parsed_number_string_t { uint64_t mantissa{0}; - int16_t exponent{0}; + int32_t exponent{0}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif @@ -338,8 +338,8 @@ parse_number_string(UC const *p, UC const *pend, ++p; } UC const *const end_of_integer_part = p; - uint16_t digit_count = uint16_t(end_of_integer_part - start_digits); - answer.integer = span(start_digits, size_t(digit_count)); + uint32_t digit_count = uint32_t(end_of_integer_part - start_digits); + answer.integer = span(start_digits, digit_count); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in integer part, without leading zeros @@ -353,7 +353,7 @@ parse_number_string(UC const *p, UC const *pend, } #endif - int16_t exponent = 0; + int32_t exponent = 0; bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); if (has_decimal_point) { ++p; @@ -367,8 +367,8 @@ parse_number_string(UC const *p, UC const *pend, i = i * 10 + digit; // in rare cases, this will overflow, but that's ok ++p; } - exponent = int16_t(before - p); - answer.fraction = span(before, size_t(p - before)); + exponent = int32_t(before - p); + answer.fraction = span(before, uint32_t(p - before)); digit_count -= exponent; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -383,7 +383,7 @@ parse_number_string(UC const *p, UC const *pend, else if (digit_count == 0) { // we must have encountered at least one integer! return report_parse_error(p, parse_error::no_digits_in_mantissa); } - int16_t exp_number = 0; // explicit exponential part + int32_t exp_number = 0; // explicit exponential part if (p != pend && (uint64_t(options.format & chars_format::scientific) && ((UC('e') == *p) || (UC('E') == *p))) @@ -468,7 +468,7 @@ parse_number_string(UC const *p, UC const *pend, ++p; } if (i >= minimal_nineteen_digit_integer) { // We have a big integers - exponent = uint16_t(end_of_integer_part - p) + exp_number; + exponent = uint32_t(end_of_integer_part - p) + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); @@ -476,7 +476,7 @@ parse_number_string(UC const *p, UC const *pend, i = i * 10 + uint64_t(*p - UC('0')); ++p; } - exponent = uint16_t(answer.fraction.ptr - p) + exp_number; + exponent = uint32_t(answer.fraction.ptr - p) + exp_number; } // We have now corrected both exponent and i, to a truncated value } @@ -541,7 +541,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, p++; } - uint8_t const digit_count = uint8_t(p - start_digits); + uint32_t const digit_count = uint32_t(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 4e3e06c3..7a481b4c 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -19,11 +19,11 @@ namespace fast_float { #if defined(FASTFLOAT_64BIT) && !defined(__sparc) #define FASTFLOAT_64BIT_LIMB 1 typedef uint64_t limb; -constexpr size_t limb_bits = 64; +constexpr uint32_t limb_bits = 64; #else #define FASTFLOAT_32BIT_LIMB typedef uint32_t limb; -constexpr size_t limb_bits = 32; +constexpr uint32_t limb_bits = 32; #endif typedef span limb_span; @@ -32,15 +32,15 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -constexpr size_t bigint_bits = 4000; -constexpr size_t bigint_limbs = bigint_bits / limb_bits; +constexpr uint32_t bigint_bits = 4000; +constexpr uint32_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. -template struct stackvec { +template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint8_t length{0}; + uint32_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; @@ -53,38 +53,38 @@ template struct stackvec { FASTFLOAT_ASSERT(try_extend(s)); } - FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept { + FASTFLOAT_CONSTEXPR14 limb &operator[](uint32_t index) noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } - FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &operator[](uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } // index from the end of the container - FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &rindex(uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - size_t rindex = length - index - 1; + uint32_t rindex = length - index - 1; return data[rindex]; } // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { - length = uint8_t(len); + FASTFLOAT_CONSTEXPR14 void set_len(uint32_t len) noexcept { + length = len; } - constexpr uint8_t len() const noexcept { return length; } + constexpr uint32_t len() const noexcept { return length; } constexpr bool is_empty() const noexcept { return length == 0; } - constexpr uint8_t capacity() const noexcept { return size; } + constexpr uint32_t capacity() const noexcept { return size; } // append item to vector, without bounds checking FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { data[length] = value; - length++; + ++length; } // append item to vector, returning if item was added @@ -118,9 +118,9 @@ template struct stackvec { // if the new size is longer than the vector, assign value to each // appended item. FASTFLOAT_CONSTEXPR20 - void resize_unchecked(size_t new_len, limb value) noexcept { + void resize_unchecked(uint32_t new_len, limb value) noexcept { if (new_len > len()) { - size_t count = new_len - len(); + uint32_t count = new_len - len(); limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); @@ -131,7 +131,7 @@ template struct stackvec { } // try to resize the vector, returning if the vector was resized. - FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { + FASTFLOAT_CONSTEXPR20 bool try_resize(uint32_t new_len, limb value) noexcept { if (new_len > capacity()) { return false; } else { @@ -143,12 +143,12 @@ template struct stackvec { // check if any limbs are non-zero after the given index. // this needs to be done in reverse order, since the index // is relative to the most significant limbs. - FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 bool nonzero(uint32_t index) const noexcept { while (index < len()) { if (rindex(index) != 0) { return true; } - index++; + ++index; } return false; } @@ -156,7 +156,7 @@ template struct stackvec { // normalize the big integer, so most-significant zero limbs are removed. FASTFLOAT_CONSTEXPR14 void normalize() noexcept { while (len() > 0 && rindex(0) == 0) { - length--; + --length; } } }; @@ -258,16 +258,16 @@ scalar_mul(limb x, limb y, limb &carry) noexcept { // add scalar value to bigint starting from offset. // used in grade school multiplication -template +template inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, - size_t start) noexcept { - size_t index = start; + uint32_t start) noexcept { + uint32_t index = start; limb carry = y; bool overflow; while (carry != 0 && index < vec.len()) { vec[index] = scalar_add(vec[index], carry, overflow); carry = limb(overflow); - index += 1; + ++index; } if (carry != 0) { FASTFLOAT_TRY(vec.try_push(carry)); @@ -276,18 +276,18 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, } // add scalar value to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool small_add(stackvec &vec, limb y) noexcept { return small_add_from(vec, y, 0); } // multiply bigint by scalar value. -template +template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (size_t index = 0; index < vec.len(); index++) { + for (uint32_t index = 0; index != vec.len(); ++index) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -298,9 +298,9 @@ inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, // add bigint to bigint starting from index. // used in grade school multiplication -template +template FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, - size_t start) noexcept { + uint32_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { @@ -308,7 +308,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } bool carry = false; - for (size_t index = 0; index < y.len(); index++) { + for (uint32_t index = 0; index < y.len(); ++index) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -329,14 +329,14 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } // add bigint to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y) noexcept { return large_add_from(x, y, 0); } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { limb_span xs = limb_span(x.data, x.len()); stackvec z(xs); @@ -345,7 +345,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { if (y.len() != 0) { limb y0 = y[0]; FASTFLOAT_TRY(small_mul(x, y0)); - for (size_t index = 1; index < y.len(); index++) { + for (uint32_t index = 1; index != y.len(); ++index) { limb yi = y[index]; stackvec zi; if (yi != 0) { @@ -364,7 +364,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { if (y.len() == 1) { FASTFLOAT_TRY(small_mul(x, y[0])); @@ -493,7 +493,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (size_t index = vec.len(); index > 0; index--) { + for (uint32_t index = vec.len(); index > 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -508,7 +508,7 @@ struct bigint : pow5_tables<> { // shift left each limb n bits, carrying over to the new limb // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_bits(uint32_t n) noexcept { // Internally, for each item, we shift left by n, and add the previous // right shifted limb-bits. // For example, we transform (for u8) shifted left 2, to: @@ -517,10 +517,10 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - size_t const shl = n; - size_t const shr = limb_bits - shl; + uint32_t const shl = n; + uint32_t const shr = limb_bits - shl; limb prev = 0; - for (size_t index = 0; index < vec.len(); index++) { + for (uint32_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; @@ -534,7 +534,7 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_limbs(uint32_t n) noexcept { FASTFLOAT_DEBUG_ASSERT(n != 0); if (n + vec.len() > vec.capacity()) { return false; @@ -555,9 +555,9 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` bits. - FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { - size_t const rem = n % limb_bits; - size_t const div = n / limb_bits; + FASTFLOAT_CONSTEXPR20 bool shl(uint32_t n) noexcept { + uint32_t const rem = n % limb_bits; + uint32_t const div = n / limb_bits; if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -605,11 +605,11 @@ struct bigint : pow5_tables<> { exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - uint8_t small_step = 27; - limb max_native = 7450580596923828125UL; + uint32_t const small_step = 27; + limb const max_native = 7450580596923828125UL; #else - uint8_t small_step = 13; - limb max_native = 1220703125U; + uint32_t const small_step = 13; + limb const max_native = 1220703125U; #endif while (exp >= small_step) { FASTFLOAT_TRY(small_mul(vec, max_native)); diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index cdff8469..22557162 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 6229653c..ad62f73b 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -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 // to slow down performance for faster algorithms, and this is still fast. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t scientific_exponent(parsed_number_string_t const &num) noexcept { uint64_t mantissa = num.mantissa; - int16_t exponent = num.exponent; + int32_t exponent = num.exponent; while (mantissa >= 10000) { mantissa /= 10000; exponent += 4; @@ -223,8 +223,8 @@ is_truncated(span s) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, - uint16_t &count) noexcept { +parse_eight_digits(UC const *&p, limb &value, uint32_t &counter, + uint32_t &count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; counter += 8; @@ -233,8 +233,8 @@ parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, uint16_t &counter, - uint16_t &count) noexcept { +parse_one_digit(UC const *&p, limb &value, uint32_t &counter, + uint32_t &count) noexcept { value = value * 10 + limb(*p - UC('0')); p++; counter++; @@ -248,7 +248,7 @@ add_native(bigint &big, limb power, limb value) noexcept { } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -round_up_bigint(bigint &big, uint16_t &count) noexcept { +round_up_bigint(bigint &big, uint32_t &count) noexcept { // need to round-up the digits, but need to avoid rounding // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); @@ -259,17 +259,17 @@ round_up_bigint(bigint &big, uint16_t &count) noexcept { template inline FASTFLOAT_CONSTEXPR20 void parse_mantissa(bigint &result, const parsed_number_string_t &num, - uint16_t const max_digits, uint16_t &digits) noexcept { + uint32_t const max_digits, uint32_t &digits) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - uint16_t counter = 0; + uint32_t counter = 0; digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - uint16_t const step = 19; + uint32_t const step = 19; #else - uint16_t const step = 9; + uint32_t const step = 9; #endif // process all integer digits. @@ -440,13 +440,13 @@ inline FASTFLOAT_CONSTEXPR20 void digit_comp( // remove the invalid exponent bias am.power2 -= invalid_am_bias; - int16_t sci_exp = scientific_exponent(num); - uint16_t const max_digits = static_cast(binary_format::max_digits()); - uint16_t digits = 0; + int32_t sci_exp = scientific_exponent(num); + uint32_t const max_digits = uint32_t(binary_format::max_digits()); + uint32_t digits = 0; bigint bigmant; parse_mantissa(bigmant, num, max_digits, digits); // can't underflow, since digits is at most max_digits. - int16_t exponent = sci_exp + 1 - digits; + int32_t exponent = sci_exp + 1 - digits; if (exponent >= 0) { positive_digit_comp(bigmant, am, exponent); } else { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 143df1be..1b4362d4 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -70,14 +70,15 @@ template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format fmt = chars_format::general, UC dot = UC('.'), int const b = 10) noexcept - : format(fmt), decimal_point(dot), base(static_cast(b)) {} + : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ - uint8_t base; /* only allowed from 2 to 36 */ + uint32_t base; /* only allowed from 2 to 36 */ + FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; using parse_options = parse_options_t; @@ -288,15 +289,15 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - size_t length; + uint32_t length; - constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} + constexpr span(T const *_ptr, uint32_t _length) : ptr(_ptr), length(_length) {} constexpr span() : ptr(nullptr), length(0) {} - constexpr size_t len() const noexcept { return length; } + constexpr uint32_t len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T &operator[](uint32_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -1169,13 +1170,13 @@ fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { +fastfloat_really_inline constexpr uint8_t max_digits_u64(uint32_t base) { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint32_t base) { return int_luts<>::min_safe_u64[base - 2]; } From 7c96e3a8be4b5222e83be46061f56990d9004700 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 9 Apr 2025 15:22:10 +0300 Subject: [PATCH 066/252] reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN. --- include/fast_float/ascii_number.h | 6 +++--- include/fast_float/float_common.h | 26 +++++++++++++++----------- include/fast_float/parse_number.h | 14 +++++--------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index fcbbfe9b..94d47f02 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -582,7 +582,9 @@ parse_int_string(UC const *p, UC const *pend, T &value, } } -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + value = T(i); +#else if (negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -600,9 +602,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, #pragma warning(pop) #endif } else { -#endif value = T(i); -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN } #endif diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 1b4362d4..667f8198 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,29 +33,29 @@ namespace fast_float { -enum class chars_format : uint64_t; +enum class chars_format : uint8_t; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN namespace detail { -constexpr chars_format basic_json_fmt = chars_format(1 << 5); -constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); +constexpr chars_format basic_json_fmt = chars_format(1 << 4); +constexpr chars_format basic_fortran_fmt = chars_format(1 << 5); } // namespace detail #endif -enum class chars_format : uint64_t { +enum class chars_format : uint8_t { scientific = 1 << 0, - fixed = 1 << 2, + fixed = 1 << 1, general = fixed | scientific, - hex = 1 << 3, + hex = 1 << 2, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - no_infnan = 1 << 4, + no_infnan = 1 << 3, // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 json = uint64_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. json_or_infnan = uint64_t(detail::basic_json_fmt) | general, fortran = uint64_t(detail::basic_fortran_fmt) | general, - allow_leading_plus = 1 << 7, - skip_white_space = 1 << 8, + allow_leading_plus = 1 << 6, + skip_white_space = 1 << 7, #endif }; @@ -70,14 +70,18 @@ template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format fmt = chars_format::general, UC dot = UC('.'), int const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) {} + : format(fmt), decimal_point(dot), base(uint8_t(b)) { +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + assert(b >= 2 && b <= 36); +#endif + } /** Which number formats are accepted */ chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ - uint32_t base; /* only allowed from 2 to 36 */ + uint8_t base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 677a1461..46b71ecf 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -378,20 +378,16 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, first++; } } -#else - // We are in parser code with external loop that checks bounds. - FASTFLOAT_ASSUME(first < last); -#endif - if ( -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - first == last || -#endif - options.base < 2 || options.base > 36) { + if (first == last || options.base < 2 || options.base > 36) { from_chars_result_t answer; answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } +#else + // We are in parser code with external loop that checks bounds. + FASTFLOAT_ASSUME(first < last); +#endif return parse_int_string(first, last, value, options); } From a081ebe6ce25daaeec092e8bff3a4e905772d9d1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 9 Apr 2025 15:22:10 +0300 Subject: [PATCH 067/252] reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN. --- include/fast_float/ascii_number.h | 10 +++++----- include/fast_float/float_common.h | 26 +++++++++++++++----------- include/fast_float/parse_number.h | 30 +++++++++++++----------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index fcbbfe9b..d26b7f49 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -292,7 +292,7 @@ report_parse_error(UC const *p, parse_error error) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. @@ -489,7 +489,7 @@ parse_number_string(UC const *p, UC const *pend, template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_int_string(UC const *p, UC const *pend, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { from_chars_result_t answer; @@ -582,7 +582,9 @@ parse_int_string(UC const *p, UC const *pend, T &value, } } -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + value = T(i); +#else if (negative) { #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -600,9 +602,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, #pragma warning(pop) #endif } else { -#endif value = T(i); -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN } #endif diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 1b4362d4..667f8198 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,29 +33,29 @@ namespace fast_float { -enum class chars_format : uint64_t; +enum class chars_format : uint8_t; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN namespace detail { -constexpr chars_format basic_json_fmt = chars_format(1 << 5); -constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); +constexpr chars_format basic_json_fmt = chars_format(1 << 4); +constexpr chars_format basic_fortran_fmt = chars_format(1 << 5); } // namespace detail #endif -enum class chars_format : uint64_t { +enum class chars_format : uint8_t { scientific = 1 << 0, - fixed = 1 << 2, + fixed = 1 << 1, general = fixed | scientific, - hex = 1 << 3, + hex = 1 << 2, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - no_infnan = 1 << 4, + no_infnan = 1 << 3, // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 json = uint64_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. json_or_infnan = uint64_t(detail::basic_json_fmt) | general, fortran = uint64_t(detail::basic_fortran_fmt) | general, - allow_leading_plus = 1 << 7, - skip_white_space = 1 << 8, + allow_leading_plus = 1 << 6, + skip_white_space = 1 << 7, #endif }; @@ -70,14 +70,18 @@ template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format fmt = chars_format::general, UC dot = UC('.'), int const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) {} + : format(fmt), decimal_point(dot), base(uint8_t(b)) { +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + assert(b >= 2 && b <= 36); +#endif + } /** Which number formats are accepted */ chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ - uint32_t base; /* only allowed from 2 to 36 */ + uint8_t base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 677a1461..3bc40a0a 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -146,7 +146,7 @@ template struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_advanced(first, last, value, options); } }; @@ -156,7 +156,7 @@ template <> struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, std::float32_t &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { // if std::float32_t is defined, and we are in C++23 mode; macro set for // float32; set value to float due to equivalence between float and // float32_t @@ -173,7 +173,7 @@ template <> struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, std::float64_t &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { // if std::float64_t is defined, and we are in C++23 mode; macro set for // float64; set value as double due to equivalence between double and // float64_t @@ -301,7 +301,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -365,7 +365,7 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); @@ -378,20 +378,16 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, first++; } } -#else - // We are in parser code with external loop that checks bounds. - FASTFLOAT_ASSUME(first < last); -#endif - if ( -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - first == last || -#endif - options.base < 2 || options.base > 36) { + if (first == last || options.base < 2 || options.base > 36) { from_chars_result_t answer; answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } +#else + // We are in parser code with external loop that checks bounds. + FASTFLOAT_ASSUME(first < last); +#endif return parse_int_string(first, last, value, options); } @@ -404,7 +400,7 @@ template <> struct from_chars_advanced_caller<1> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_float_advanced(first, last, value, options); } }; @@ -413,7 +409,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_int_advanced(first, last, value, options); } }; @@ -421,7 +417,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_advanced_caller< size_t(is_supported_float_type::value) + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, From d32ae04b1bc79cd64a3a49c5510ef10e415db5ee Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 9 Apr 2025 15:41:29 +0300 Subject: [PATCH 068/252] reduce size of from_chars_result_t to 4 bytes. Cleanup for usage FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN. --- include/fast_float/ascii_number.h | 14 +++++++------- include/fast_float/fast_float.h | 2 +- include/fast_float/parse_number.h | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index d26b7f49..a3dd7c49 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -301,7 +301,7 @@ parse_number_string(UC const *p, UC const *pend, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || (uint64_t(options.format & chars_format::allow_leading_plus) && + if ((*p == UC('-')) || (uint8_t(options.format & chars_format::allow_leading_plus) && !basic_json_fmt && *p == UC('+'))) { ++p; if (p == pend) { @@ -385,10 +385,10 @@ parse_number_string(UC const *p, UC const *pend, } int32_t exp_number = 0; // explicit exponential part if (p != pend && - (uint64_t(options.format & chars_format::scientific) && + (uint8_t(options.format & chars_format::scientific) && ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint64_t(options.format & detail::basic_fortran_fmt) && + || (uint8_t(options.format & detail::basic_fortran_fmt) && (UC('d') == *p) || (UC('D') == *p)) #endif ) { @@ -406,7 +406,7 @@ parse_number_string(UC const *p, UC const *pend, } } if ((p == pend) || !is_integer(*p)) { - if (!uint64_t(options.format & chars_format::fixed)) { + if (!uint8_t(options.format & chars_format::fixed)) { // The exponential part is invalid for scientific notation, so it must // be a trailing token for fixed notation. However, fixed notation is // disabled, so report a scientific notation error. @@ -427,8 +427,8 @@ parse_number_string(UC const *p, UC const *pend, } } else { // If it scientific and not fixed, we have to bail out. - if (uint64_t(options.format & chars_format::scientific) && - !uint64_t(options.format & chars_format::fixed)) { + if (uint8_t(options.format & chars_format::scientific) && + !uint8_t(options.format & chars_format::fixed)) { return report_parse_error(p, parse_error::missing_exponential_part); } } @@ -510,7 +510,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, return answer; } if ((*p == UC('-')) || - (uint64_t(options.format & chars_format::allow_leading_plus) && + (uint8_t(options.format & chars_format::allow_leading_plus) && (*p == UC('+')))) { ++p; } diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 4ca1a0ae..4c05c2dc 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -43,7 +43,7 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept; + parse_options_t const options) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 3bc40a0a..93c28a1e 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -310,7 +310,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, from_chars_result_t answer; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint64_t(options.format & chars_format::skip_white_space)) { + if (uint8_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } @@ -326,14 +326,14 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, #endif parsed_number_string_t const pns = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - uint64_t(options.format & detail::basic_json_fmt) + uint8_t(options.format & detail::basic_json_fmt) ? parse_number_string(first, last, options) : #endif parse_number_string(first, last, options); if (!pns.valid) { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint64_t(options.format & chars_format::no_infnan)) { + if (uint8_t(options.format & chars_format::no_infnan)) { #endif answer.ec = std::errc::invalid_argument; answer.ptr = first; @@ -373,7 +373,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, "only char, wchar_t, char16_t and char32_t are supported"); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint64_t(options.format & chars_format::skip_white_space)) { + if (uint8_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { first++; } @@ -387,6 +387,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, #else // We are in parser code with external loop that checks bounds. FASTFLOAT_ASSUME(first < last); + // base is already checked in the parse_options_t constructor. #endif return parse_int_string(first, last, value, options); From c7629365896280ff7a346922530789f47403f61d Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 9 Apr 2025 15:55:54 +0300 Subject: [PATCH 069/252] template interface cleanup for min_safe_u64 and max_digits_u64. --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 667f8198..53fc4b40 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1174,13 +1174,13 @@ fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t max_digits_u64(uint32_t base) { +fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint32_t base) { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) { return int_luts<>::min_safe_u64[base - 2]; } From bbf419333993b305676feb5e50de5b8536919bd1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 9 Apr 2025 21:44:30 +0300 Subject: [PATCH 070/252] cleanup code generation for parse_mantissa. --- include/fast_float/digit_comparison.h | 56 +++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index ad62f73b..4090a696 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -223,8 +223,8 @@ is_truncated(span s) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, uint32_t &counter, - uint32_t &count) noexcept { +parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, + uint16_t &count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; counter += 8; @@ -233,12 +233,12 @@ parse_eight_digits(UC const *&p, limb &value, uint32_t &counter, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, uint32_t &counter, - uint32_t &count) noexcept { +parse_one_digit(UC const *&p, limb &value, uint16_t &counter, + uint16_t &count) noexcept { value = value * 10 + limb(*p - UC('0')); - p++; - counter++; - count++; + ++p; + ++counter; + ++count; } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void @@ -248,28 +248,28 @@ add_native(bigint &big, limb power, limb value) noexcept { } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -round_up_bigint(bigint &big, uint32_t &count) noexcept { +round_up_bigint(bigint &big, uint16_t &count) noexcept { // need to round-up the digits, but need to avoid rounding // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); - count++; + ++count; } // parse the significant digits into a big integer -template -inline FASTFLOAT_CONSTEXPR20 void -parse_mantissa(bigint &result, const parsed_number_string_t &num, - uint32_t const max_digits, uint32_t &digits) noexcept { +template +inline FASTFLOAT_CONSTEXPR20 uint16_t +parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - uint32_t counter = 0; - digits = 0; + uint16_t const max_digits = uint16_t(binary_format::max_digits()); + uint16_t counter = 0; + uint16_t digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - uint32_t const step = 19; + uint16_t const step = 19; #else - uint32_t const step = 9; + uint16_t const step = 9; #endif // process all integer digits. @@ -280,10 +280,10 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, while (p != pend) { while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + parse_eight_digits(p, value, counter, digits); } while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); + parse_one_digit(p, value, counter, digits); } if (digits == max_digits) { // add the temporary value, then check if we've truncated any digits @@ -295,7 +295,7 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, if (truncated) { round_up_bigint(result, digits); } - return; + return digits; } else { add_native(result, limb(powers_of_ten_uint64[counter]), value); counter = 0; @@ -314,10 +314,10 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, while (p != pend) { while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + parse_eight_digits(p, value, counter, digits); } while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); + parse_one_digit(p, value, counter, digits); } if (digits == max_digits) { // add the temporary value, then check if we've truncated any digits @@ -326,7 +326,7 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, if (truncated) { round_up_bigint(result, digits); } - return; + return digits; } else { add_native(result, limb(powers_of_ten_uint64[counter]), value); counter = 0; @@ -338,6 +338,7 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num, if (counter != 0) { add_native(result, limb(powers_of_ten_uint64[counter]), value); } + return digits; } template @@ -440,13 +441,12 @@ inline FASTFLOAT_CONSTEXPR20 void digit_comp( // remove the invalid exponent bias am.power2 -= invalid_am_bias; - int32_t sci_exp = scientific_exponent(num); - uint32_t const max_digits = uint32_t(binary_format::max_digits()); - uint32_t digits = 0; bigint bigmant; - parse_mantissa(bigmant, num, max_digits, digits); + int32_t const sci_exp = scientific_exponent(num); + + uint16_t const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - int32_t exponent = sci_exp + 1 - digits; + int32_t const exponent = sci_exp + 1 - digits; if (exponent >= 0) { positive_digit_comp(bigmant, am, exponent); } else { From 2da25b51c83bdb7b1fb005ef490a031748d69e29 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 10 Apr 2025 00:49:16 +0300 Subject: [PATCH 071/252] trying to fix tests. --- CONTRIBUTORS | 1 + tests/example_comma_test.cpp | 4 ++-- tests/fortran.cpp | 26 ++++++++++++++++---------- tests/json_fmt.cpp | 25 ++++++++++++++----------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4b705554..400c89ff 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -9,3 +9,4 @@ Jan Pharago Maya Warrier Taha Khokhar Anders Dalvander +Elle Solomina diff --git a/tests/example_comma_test.cpp b/tests/example_comma_test.cpp index 79a8e1d0..40d6ec3b 100644 --- a/tests/example_comma_test.cpp +++ b/tests/example_comma_test.cpp @@ -7,9 +7,9 @@ int main() { std::string const input = "3,1416 xyz "; double result; - fast_float::parse_options options{fast_float::chars_format::general, ','}; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options{fast_float::chars_format::general, ','}); if ((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; diff --git a/tests/fortran.cpp b/tests/fortran.cpp index 9167593e..0c7477f7 100644 --- a/tests/fortran.cpp +++ b/tests/fortran.cpp @@ -9,11 +9,11 @@ int main_readme() { std::string const input = "1d+4"; double result; - fast_float::parse_options options{ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options { + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}); if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n" << result << "\n"; return EXIT_FAILURE; @@ -31,15 +31,15 @@ int main() { "1d-1", "1d-2", "1d-3", "1d-4"}; std::vector const fmt3{"+1+4", "+1+3", "+1+2", "+1+1", "+1+0", "+1-1", "+1-2", "+1-3", "+1-4"}; - fast_float::parse_options const options{ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}; for (auto const &f : fmt1) { auto d{std::distance(&fmt1[0], &f)}; double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; + result, + fast_float::parse_options { + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus})}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -50,7 +50,10 @@ int main() { auto d{std::distance(&fmt2[0], &f)}; double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; + result, + fast_float::parse_options { + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus})}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -61,7 +64,10 @@ int main() { auto d{std::distance(&fmt3[0], &f)}; double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, options)}; + result, + fast_float::parse_options { + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus})}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index 1ba0d5ae..10994db9 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -7,11 +7,12 @@ int main_readme() { std::string const input = "+.1"; // not valid double result; - fast_float::parse_options options{ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}; // should be ignored auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options options{ + fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus} // should be ignored + ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -22,11 +23,12 @@ int main_readme() { int main_readme2() { std::string const input = "inf"; // not valid in JSON double result; - fast_float::parse_options options{ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}; // should be ignored auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + input.data(), input.data() + input.size(), result, + fast_float::parse_options options{ + fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus} // should be ignored + ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -38,11 +40,12 @@ int main_readme3() { std::string const input = "inf"; // not valid in JSON but we allow it with json_or_infnan double result; - fast_float::parse_options options{ + auto answer = fast_float::from_chars_advanced( + input.data(), input.data() + input.size(), result, + fast_float::parse_options options{ fast_float::chars_format::json_or_infnan | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, options); + ); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; From 8e1fda5d08a3e0bce1bb0fe1ac1a4d14cb09342a Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 10 Apr 2025 17:18:08 +0300 Subject: [PATCH 072/252] fixes and cleanup for the parse_number_string function. exponent value is always less than in16_t. original main: Tests: time is: 44278ms. size of my tests 389.0k size of my program 164.0k my main: Tests: time is: 42015ms. size of my tests 389.0k size of my program 164.0k my main with FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN Tests: time is: 41282ms. size of my tests 386.5k size of my program 161.5k After this I'll try it on my partner Linux machine with the original tests and compare much better. --- include/fast_float/ascii_number.h | 77 +++++++++++---------- include/fast_float/bigint.h | 96 +++++++++++++------------- include/fast_float/decimal_to_binary.h | 12 ++-- include/fast_float/digit_comparison.h | 70 ++++++++++--------- include/fast_float/float_common.h | 24 +++---- include/fast_float/parse_number.h | 2 +- 6 files changed, 143 insertions(+), 138 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a3dd7c49..ec2b6b8a 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -50,7 +50,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t read8_to_u64(UC const *chars) { if (cpp20_and_in_constexpr() || !std::is_same::value) { uint64_t val = 0; - for (int i = 0; i < 8; ++i) { + for (uint8_t i = 0; i != 8; ++i) { val |= uint64_t(uint8_t(*chars)) << (i * 8); ++chars; } @@ -261,7 +261,7 @@ enum class parse_error { template struct parsed_number_string_t { uint64_t mantissa{0}; - int32_t exponent{0}; + int16_t exponent{0}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif @@ -327,18 +327,17 @@ parse_number_string(UC const *p, UC const *pend, UC const *const start_digits = p; - uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) - + // an unsigned int avoids signed overflows (which are bad) while ((p != pend) && is_integer(*p)) { // a multiplication by 10 is cheaper than an arbitrary integer // multiplication - i = 10 * i + + answer.mantissa = 10 * answer.mantissa + uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; - uint32_t digit_count = uint32_t(end_of_integer_part - start_digits); + uint16_t digit_count = uint16_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, digit_count); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -353,43 +352,46 @@ parse_number_string(UC const *p, UC const *pend, } #endif - int32_t exponent = 0; bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); if (has_decimal_point) { ++p; UC const *before = p; + uint16_t fraction = 0; // can occur at most twice without overflowing, but let it occur more, since // for integers with many digits, digit parsing is the primary bottleneck. - loop_parse_if_eight_digits(p, pend, i); + loop_parse_if_eight_digits(p, pend, answer.mantissa); while ((p != pend) && is_integer(*p)) { uint8_t const digit = uint8_t(*p - UC('0')); - i = i * 10 + digit; // in rare cases, this will overflow, but that's ok + answer.mantissa = answer.mantissa * 10 + digit; // in rare cases, this will overflow, but that's ok ++p; } - exponent = int32_t(before - p); - answer.fraction = span(before, uint32_t(p - before)); - digit_count -= exponent; - } + fraction = uint16_t(before - p); + answer.fraction = span(before, uint16_t(p - before)); + digit_count -= fraction; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { - // at least 1 digit in fractional part - if (has_decimal_point && exponent == 0) { - return report_parse_error(p, + FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { + // at least 1 digit in fractional part + if (has_decimal_point && fraction == 0) { + return report_parse_error(p, parse_error::no_digits_in_fractional_part); + } } - } #endif + } else if (digit_count == 0) { // we must have encountered at least one integer! return report_parse_error(p, parse_error::no_digits_in_mantissa); } - int32_t exp_number = 0; // explicit exponential part + // We have now parsed the integer and the fraction part of the mantissa. + + // Now we can parse the exponent part. if (p != pend && (uint8_t(options.format & chars_format::scientific) && - ((UC('e') == *p) || (UC('E') == *p))) + (UC('e') == *p) || (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN || (uint8_t(options.format & detail::basic_fortran_fmt) && - (UC('d') == *p) || (UC('D') == *p)) + ((UC('+') == *p) || (UC('-') == *p) || + (UC('d') == *p) || (UC('D') == *p))) #endif ) { UC const *location_of_e = p; @@ -416,14 +418,16 @@ parse_number_string(UC const *p, UC const *pend, p = location_of_e; } else { while ((p != pend) && is_integer(*p)) { - uint8_t const digit = uint8_t(*p - UC('0')); - exp_number = 10 * exp_number + digit; + if (answer.exponent < 0x1000) { + // check for exponent overflow if we have too many digits. + uint8_t const digit = uint8_t(*p - UC('0')); + answer.exponent = 10 * answer.exponent + digit; + } ++p; } if (neg_exp) { - exp_number = -exp_number; + answer.exponent = -answer.exponent; } - exponent += exp_number; } } else { // If it scientific and not fixed, we have to bail out. @@ -459,30 +463,28 @@ parse_number_string(UC const *p, UC const *pend, // Let us start again, this time, avoiding overflows. // We don't need to check if is_integer, since we use the // pre-tokenized spans from above. - i = 0; + answer.mantissa = 0; p = answer.integer.ptr; UC const *int_end = p + answer.integer.len(); uint64_t const minimal_nineteen_digit_integer{1000000000000000000}; - while ((i < minimal_nineteen_digit_integer) && (p != int_end)) { - i = i * 10 + uint64_t(*p - UC('0')); + while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != int_end)) { + answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); ++p; } - if (i >= minimal_nineteen_digit_integer) { // We have a big integers - exponent = uint32_t(end_of_integer_part - p) + exp_number; + if (answer.mantissa >= minimal_nineteen_digit_integer) { // We have a big integers + answer.exponent += int16_t(end_of_integer_part - p); } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); - while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) { - i = i * 10 + uint64_t(*p - UC('0')); + while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != frac_end)) { + answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); ++p; } - exponent = uint32_t(answer.fraction.ptr - p) + exp_number; + answer.exponent += int16_t(answer.fraction.ptr - p); } - // We have now corrected both exponent and i, to a truncated value + // We have now corrected both exponent and mantissa, to a truncated value } } - answer.exponent = exponent; - answer.mantissa = i; return answer; } @@ -518,7 +520,6 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_num = p; - // use SIMD here? while (p != pend && *p == UC('0')) { ++p; } @@ -541,7 +542,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, p++; } - uint32_t const digit_count = uint32_t(p - start_digits); + uint16_t const digit_count = uint16_t(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 7a481b4c..aa18c2f8 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -19,11 +19,11 @@ namespace fast_float { #if defined(FASTFLOAT_64BIT) && !defined(__sparc) #define FASTFLOAT_64BIT_LIMB 1 typedef uint64_t limb; -constexpr uint32_t limb_bits = 64; +constexpr uint16_t limb_bits = 64; #else #define FASTFLOAT_32BIT_LIMB typedef uint32_t limb; -constexpr uint32_t limb_bits = 32; +constexpr uint16_t limb_bits = 32; #endif typedef span limb_span; @@ -32,15 +32,15 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -constexpr uint32_t bigint_bits = 4000; -constexpr uint32_t bigint_limbs = bigint_bits / limb_bits; +constexpr uint16_t bigint_bits = 4000; +constexpr uint16_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. -template struct stackvec { +template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint32_t length{0}; + uint8_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; @@ -53,33 +53,33 @@ template struct stackvec { FASTFLOAT_ASSERT(try_extend(s)); } - FASTFLOAT_CONSTEXPR14 limb &operator[](uint32_t index) noexcept { + FASTFLOAT_CONSTEXPR14 limb &operator[](uint16_t index) noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } - FASTFLOAT_CONSTEXPR14 const limb &operator[](uint32_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &operator[](uint16_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } // index from the end of the container - FASTFLOAT_CONSTEXPR14 const limb &rindex(uint32_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &rindex(uint16_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - uint32_t rindex = length - index - 1; + uint16_t rindex = length - index - 1; return data[rindex]; } // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(uint32_t len) noexcept { + FASTFLOAT_CONSTEXPR14 void set_len(uint8_t len) noexcept { length = len; } - constexpr uint32_t len() const noexcept { return length; } + constexpr uint8_t len() const noexcept { return length; } constexpr bool is_empty() const noexcept { return length == 0; } - constexpr uint32_t capacity() const noexcept { return size; } + constexpr uint8_t capacity() const noexcept { return size; } // append item to vector, without bounds checking FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { @@ -118,9 +118,9 @@ template struct stackvec { // if the new size is longer than the vector, assign value to each // appended item. FASTFLOAT_CONSTEXPR20 - void resize_unchecked(uint32_t new_len, limb value) noexcept { + void resize_unchecked(uint8_t new_len, limb value) noexcept { if (new_len > len()) { - uint32_t count = new_len - len(); + uint8_t count = new_len - len(); limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); @@ -131,7 +131,7 @@ template struct stackvec { } // try to resize the vector, returning if the vector was resized. - FASTFLOAT_CONSTEXPR20 bool try_resize(uint32_t new_len, limb value) noexcept { + FASTFLOAT_CONSTEXPR20 bool try_resize(uint8_t new_len, limb value) noexcept { if (new_len > capacity()) { return false; } else { @@ -143,7 +143,7 @@ template struct stackvec { // check if any limbs are non-zero after the given index. // this needs to be done in reverse order, since the index // is relative to the most significant limbs. - FASTFLOAT_CONSTEXPR14 bool nonzero(uint32_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 bool nonzero(uint16_t index) const noexcept { while (index < len()) { if (rindex(index) != 0) { return true; @@ -258,10 +258,10 @@ scalar_mul(limb x, limb y, limb &carry) noexcept { // add scalar value to bigint starting from offset. // used in grade school multiplication -template +template inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, uint32_t start) noexcept { - uint32_t index = start; + uint8_t index = (uint8_t)start; limb carry = y; bool overflow; while (carry != 0 && index < vec.len()) { @@ -276,18 +276,18 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, } // add scalar value to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool small_add(stackvec &vec, limb y) noexcept { return small_add_from(vec, y, 0); } // multiply bigint by scalar value. -template +template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (uint32_t index = 0; index != vec.len(); ++index) { + for (uint8_t index = 0; index != vec.len(); ++index) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -298,9 +298,9 @@ inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, // add bigint to bigint starting from index. // used in grade school multiplication -template +template FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, - uint32_t start) noexcept { + uint8_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { @@ -308,7 +308,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } bool carry = false; - for (uint32_t index = 0; index < y.len(); ++index) { + for (uint8_t index = 0; index < y.len(); ++index) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -329,14 +329,14 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } // add bigint to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y) noexcept { return large_add_from(x, y, 0); } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { limb_span xs = limb_span(x.data, x.len()); stackvec z(xs); @@ -345,7 +345,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { if (y.len() != 0) { limb y0 = y[0]; FASTFLOAT_TRY(small_mul(x, y0)); - for (uint32_t index = 1; index != y.len(); ++index) { + for (uint8_t index = 1; index != y.len(); ++index) { limb yi = y[index]; stackvec zi; if (yi != 0) { @@ -364,7 +364,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { if (y.len() == 1) { FASTFLOAT_TRY(small_mul(x, y[0])); @@ -493,7 +493,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (uint32_t index = vec.len(); index > 0; --index) { + for (uint8_t index = vec.len(); index > 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -508,7 +508,7 @@ struct bigint : pow5_tables<> { // shift left each limb n bits, carrying over to the new limb // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(uint32_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_bits(uint16_t n) noexcept { // Internally, for each item, we shift left by n, and add the previous // right shifted limb-bits. // For example, we transform (for u8) shifted left 2, to: @@ -517,10 +517,10 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - uint32_t const shl = n; - uint32_t const shr = limb_bits - shl; + uint16_t const shl = n; + uint16_t const shr = limb_bits - shl; limb prev = 0; - for (uint32_t index = 0; index != vec.len(); ++index) { + for (uint8_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; @@ -534,7 +534,7 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(uint32_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_limbs(int16_t n) noexcept { FASTFLOAT_DEBUG_ASSERT(n != 0); if (n + vec.len() > vec.capacity()) { return false; @@ -555,9 +555,9 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` bits. - FASTFLOAT_CONSTEXPR20 bool shl(uint32_t n) noexcept { - uint32_t const rem = n % limb_bits; - uint32_t const div = n / limb_bits; + FASTFLOAT_CONSTEXPR20 bool shl(uint16_t n) noexcept { + uint16_t const rem = n % limb_bits; + uint16_t const div = n / limb_bits; if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -568,7 +568,7 @@ struct bigint : pow5_tables<> { } // get the number of leading zeros in the bigint. - FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept { + FASTFLOAT_CONSTEXPR20 uint8_t ctlz() const noexcept { if (vec.is_empty()) { return 0; } else { @@ -583,9 +583,9 @@ struct bigint : pow5_tables<> { } // get the number of bits in the bigint. - FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept { - int lz = ctlz(); - return int(limb_bits * vec.len()) - lz; + FASTFLOAT_CONSTEXPR20 uint16_t bit_length() const noexcept { + uint16_t lz = ctlz(); + return uint16_t(limb_bits * vec.len()) - lz; } FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } @@ -593,22 +593,22 @@ struct bigint : pow5_tables<> { FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } // multiply as if by 2 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); } + FASTFLOAT_CONSTEXPR20 bool pow2(int16_t exp) noexcept { return shl(exp); } // multiply as if by 5 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { + FASTFLOAT_CONSTEXPR20 bool pow5(int16_t exp) noexcept { // multiply by a power of 5 - size_t const large_length = sizeof(large_power_of_5) / sizeof(limb); + uint8_t const large_length = sizeof(large_power_of_5) / sizeof(limb); limb_span const large = limb_span(large_power_of_5, large_length); while (exp >= large_step) { FASTFLOAT_TRY(large_mul(vec, large)); exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - uint32_t const small_step = 27; + uint8_t const small_step = 27; limb const max_native = 7450580596923828125UL; #else - uint32_t const small_step = 13; + uint8_t const small_step = 13; limb const max_native = 1220703125U; #endif while (exp >= small_step) { @@ -627,7 +627,7 @@ struct bigint : pow5_tables<> { } // multiply as if by 10 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept { + FASTFLOAT_CONSTEXPR20 bool pow10(int16_t exp) noexcept { FASTFLOAT_TRY(pow5(exp)); return pow2(exp); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 22557162..a334e18d 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -71,12 +71,12 @@ constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept { - int hilz = int(w >> 63) ^ 1; +compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { + int32_t hilz = int32_t(w >> 63) ^ 1; adjusted_mantissa answer; answer.mantissa = w << hilz; - int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); - answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + + int32_t bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); + answer.power2 = int16_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + invalid_am_bias); return answer; } @@ -143,7 +143,7 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa = product.high >> shift; - answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - + answer.power2 = int16_t(detail::power(int32_t(q)) + upperbit - lz - binary::minimum_exponent()); if (answer.power2 <= 0) { // we have a subnormal? // Here have that answer.power2 <= 0 so -answer.power2 >= 0 @@ -196,7 +196,7 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa >>= 1; if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); - answer.power2++; // undo previous addition + ++answer.power2; // undo previous addition } answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 4090a696..82a2953c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -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 // to slow down performance for faster algorithms, and this is still fast. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t scientific_exponent(parsed_number_string_t const &num) noexcept { uint64_t mantissa = num.mantissa; - int32_t exponent = num.exponent; + int16_t exponent = num.exponent; while (mantissa >= 10000) { mantissa /= 10000; exponent += 4; @@ -68,7 +68,7 @@ to_extended(T const &value) noexcept { constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); adjusted_mantissa am; - int32_t bias = binary_format::mantissa_explicit_bits() - + int16_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); equiv_uint bits; #if FASTFLOAT_HAS_BIT_CAST @@ -82,7 +82,7 @@ to_extended(T const &value) noexcept { am.mantissa = bits & mantissa_mask; } else { // normal - am.power2 = int32_t((bits & exponent_mask) >> + am.power2 = int16_t((bits & exponent_mask) >> binary_format::mantissa_explicit_bits()); am.power2 -= bias; am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; @@ -108,11 +108,11 @@ to_extended_halfway(T const &value) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, callback cb) noexcept { - int32_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; + int16_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; if (-am.power2 >= mantissa_shift) { // have a denormal float - int32_t shift = -am.power2 + 1; - cb(am, std::min(shift, 64)); + int16_t shift = -am.power2 + 1; + cb(am, std::min(shift, 64)); // check for round-up: if rounding-nearest carried us to the hidden bit. am.power2 = (am.mantissa < (uint64_t(1) << binary_format::mantissa_explicit_bits())) @@ -128,7 +128,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, if (am.mantissa >= (uint64_t(2) << binary_format::mantissa_explicit_bits())) { am.mantissa = (uint64_t(1) << binary_format::mantissa_explicit_bits()); - am.power2++; + ++am.power2; } // check for infinite: we could have carried to an infinite power @@ -141,7 +141,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, +round_nearest_tie_even(adjusted_mantissa &am, int16_t shift, callback cb) noexcept { uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1; uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1); @@ -162,7 +162,7 @@ round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, } fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_down(adjusted_mantissa &am, int32_t shift) noexcept { +round_down(adjusted_mantissa &am, int16_t shift) noexcept { if (shift == 64) { am.mantissa = 0; } else { @@ -342,17 +342,17 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { } template -inline FASTFLOAT_CONSTEXPR20 void -positive_digit_comp(bigint &bigmant, adjusted_mantissa &am, - int32_t const exponent) noexcept { - FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +positive_digit_comp(bigint &bigmant, adjusted_mantissa am, + int16_t const exponent) noexcept { + FASTFLOAT_ASSERT(bigmant.pow10(exponent)); bool truncated; am.mantissa = bigmant.hi64(truncated); - int32_t bias = binary_format::mantissa_explicit_bits() - + int16_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); am.power2 = bigmant.bit_length() - 64 + bias; - round(am, [truncated](adjusted_mantissa &a, int32_t shift) { + round(am, [truncated](adjusted_mantissa &a, int16_t shift) { round_nearest_tie_even( a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { @@ -360,6 +360,8 @@ positive_digit_comp(bigint &bigmant, adjusted_mantissa &am, (is_odd && is_halfway); }); }); + + return am; } // the scaling here is quite simple: we have, for the real digits `m * 10^e`, @@ -368,11 +370,11 @@ positive_digit_comp(bigint &bigmant, adjusted_mantissa &am, // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 void -negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, - int32_t const exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +negative_digit_comp(bigint &bigmant, adjusted_mantissa am, + int16_t const exponent) noexcept { bigint &real_digits = bigmant; - const int32_t &real_exp = exponent; + int16_t const &real_exp = exponent; T b; { @@ -381,7 +383,7 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. round(am_b, - [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); + [](adjusted_mantissa &a, int16_t shift) { round_down(a, shift); }); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, @@ -390,23 +392,23 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, } adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); - int32_t theor_exp = theor.power2; + int16_t theor_exp = theor.power2; // scale real digits and theor digits to be same power. - int32_t pow2_exp = theor_exp - real_exp; - uint32_t pow5_exp = uint32_t(-real_exp); + int16_t pow2_exp = theor_exp - real_exp; + uint16_t pow5_exp = uint16_t(-real_exp); if (pow5_exp != 0) { FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); } if (pow2_exp > 0) { - FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp))); + FASTFLOAT_ASSERT(theor_digits.pow2(pow2_exp)); } else if (pow2_exp < 0) { - FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); + FASTFLOAT_ASSERT(real_digits.pow2(-pow2_exp)); } // compare digits, and use it to director rounding int ord = real_digits.compare(theor_digits); - round(am, [ord](adjusted_mantissa &a, int32_t shift) { + round(am, [ord](adjusted_mantissa &a, int16_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { (void)_; // not needed, since we've done our comparison @@ -420,6 +422,8 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, } }); }); + + return am; } // parse the significant digits as a big integer to unambiguously round the @@ -436,21 +440,21 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa &am, // the actual digits. we then compare the big integer representations // of both, and use that to direct rounding. template -inline FASTFLOAT_CONSTEXPR20 void digit_comp( - parsed_number_string_t const &num, adjusted_mantissa &am) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( + parsed_number_string_t const &num, adjusted_mantissa am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; bigint bigmant; - int32_t const sci_exp = scientific_exponent(num); + int16_t const sci_exp = scientific_exponent(num); uint16_t const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - int32_t const exponent = sci_exp + 1 - digits; + int16_t const exponent = sci_exp + 1 - digits; if (exponent >= 0) { - positive_digit_comp(bigmant, am, exponent); + return positive_digit_comp(bigmant, am, exponent); } else { - negative_digit_comp(bigmant, am, exponent); + return negative_digit_comp(bigmant, am, exponent); } } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 53fc4b40..7de83f5a 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -293,15 +293,15 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - uint32_t length; + uint16_t length; - constexpr span(T const *_ptr, uint32_t _length) : ptr(_ptr), length(_length) {} + constexpr span(T const *_ptr, uint16_t _length) : ptr(_ptr), length(_length) {} constexpr span() : ptr(nullptr), length(0) {} - constexpr uint32_t len() const noexcept { return length; } + constexpr uint16_t len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T &operator[](uint32_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T &operator[](uint16_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -318,8 +318,8 @@ struct value128 { }; /* Helper C++14 constexpr generic implementation of leading_zeroes */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int -leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint8_t +leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) { if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; last_bit |= 32; @@ -343,11 +343,11 @@ leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - last_bit; + return 63 - (uint8_t)last_bit; } /* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint8_t leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); @@ -360,12 +360,12 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return (int)(63 - leading_zero); + return (uint8_t)(63 - leading_zero); #else - return leading_zeroes_generic(input_num); + return (uint8_t)leading_zeroes_generic(input_num); #endif #else - return __builtin_clzll(input_num); + return (uint8_t)__builtin_clzll(input_num); #endif } @@ -429,7 +429,7 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { struct adjusted_mantissa { uint64_t mantissa; - int32_t power2; // a negative value indicates an invalid result + int16_t power2; // a negative value indicates an invalid result adjusted_mantissa() noexcept = default; constexpr bool operator==(adjusted_mantissa const &o) const noexcept { diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 93c28a1e..ca94b059 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -283,7 +283,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { // and we have an invalid power (am.power2 < 0), then we need to go the long // way around again. This is very uncommon. if (am.power2 < 0) { - digit_comp(pns, am); + am = digit_comp(pns, am); } to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 6cacae0782b59d2aa026db7078861d49cbf3b3e2 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 10 Apr 2025 17:37:09 +0300 Subject: [PATCH 073/252] trying to fix tests. --- tests/basictest.cpp | 13 +++++++------ tests/example_comma_test.cpp | 2 +- tests/fortran.cpp | 16 ++++++++-------- tests/json_fmt.cpp | 16 ++++++++-------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index d1b377af..8f269020 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -656,7 +656,7 @@ TEST_CASE("decimal_point_parsing") { answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options(fast_float::chars_format::general, ',', 10)); + fast_float::parse_options({fast_float::chars_format::general, ',', 10})); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -666,7 +666,8 @@ TEST_CASE("decimal_point_parsing") { std::string const input = "1.25"; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options(fast_float::chars_format::general, ',', 10)); + fast_float::parse_options({fast_float::chars_format::general, ',', + 10})); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at dot"); @@ -1323,8 +1324,8 @@ TEST_CASE("double.general") { TEST_CASE("double.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options(fast_float::chars_format::general, ',', - 10); + return fast_float::parse_options({fast_float::chars_format::general, ',', + 10}); }(); // infinities @@ -1641,8 +1642,8 @@ TEST_CASE("float.general") { TEST_CASE("float.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options(fast_float::chars_format::general, ',', - 10); + return fast_float::parse_options({fast_float::chars_format::general, ',', + 10}); }(); // infinity diff --git a/tests/example_comma_test.cpp b/tests/example_comma_test.cpp index 40d6ec3b..b77ad57e 100644 --- a/tests/example_comma_test.cpp +++ b/tests/example_comma_test.cpp @@ -9,7 +9,7 @@ int main() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options{fast_float::chars_format::general, ','}); + fast_float::parse_options({fast_float::chars_format::general, ','})); if ((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; diff --git a/tests/fortran.cpp b/tests/fortran.cpp index 0c7477f7..2f49946b 100644 --- a/tests/fortran.cpp +++ b/tests/fortran.cpp @@ -11,9 +11,9 @@ int main_readme() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options { + fast_float::parse_options ({ fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}); + fast_float::chars_format::allow_leading_plus})); if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n" << result << "\n"; return EXIT_FAILURE; @@ -37,9 +37,9 @@ int main() { double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), result, - fast_float::parse_options { + fast_float::parse_options ({ fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus})}; + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -51,9 +51,9 @@ int main() { double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), result, - fast_float::parse_options { + fast_float::parse_options ({ fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus})}; + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -65,9 +65,9 @@ int main() { double result; auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), result, - fast_float::parse_options { + fast_float::parse_options ({ fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus})}; + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index 10994db9..bf3b4022 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -9,9 +9,9 @@ int main_readme() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options{ + fast_float::parse_options options({ fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus} // should be ignored + fast_float::chars_format::allow_leading_plus}) // should be ignored ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -25,9 +25,9 @@ int main_readme2() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options{ + fast_float::parse_options options({ fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus} // should be ignored + fast_float::chars_format::allow_leading_plus}) // should be ignored ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -42,9 +42,9 @@ int main_readme3() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options{ + fast_float::parse_options options({ fast_float::chars_format::json_or_infnan | - fast_float::chars_format::allow_leading_plus}; // should be ignored + fast_float::chars_format::allow_leading_plus}); // should be ignored ); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; @@ -136,9 +136,9 @@ int main() { auto const &expected_reason = reject[i].reason; auto answer = fast_float::parse_number_string( f.data(), f.data() + f.size(), - fast_float::parse_options( + fast_float::parse_options({ fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus)); // should be ignored + fast_float::chars_format::allow_leading_plus})); // should be ignored if (answer.valid) { std::cerr << "json parse accepted invalid json " << f << std::endl; return EXIT_FAILURE; From 68fe735829583bbee2ea891a7b4c2c3a1c6f3c9f Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 10 Apr 2025 18:23:01 +0300 Subject: [PATCH 074/252] fix warnings. --- include/fast_float/bigint.h | 6 +- include/fast_float/float_common.h | 138 +++++++++++++++--------------- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index aa18c2f8..f9a4c038 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -101,7 +101,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { limb *ptr = data + length; std::copy_n(s.ptr, s.len(), ptr); - set_len(len() + s.len()); + set_len(uint8_t(len() + s.len())); } // try to add items to the vector, returning if items were added @@ -304,7 +304,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { - FASTFLOAT_TRY(x.try_resize(y.len() + start, 0)); + FASTFLOAT_TRY(x.try_resize(uint8_t(y.len() + start), 0)); } bool carry = false; @@ -547,7 +547,7 @@ struct bigint : pow5_tables<> { limb *first = vec.data; limb *last = first + n; ::std::fill(first, last, 0); - vec.set_len(n + vec.len()); + vec.set_len(uint8_t(n + vec.len())); return true; } else { return true; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7de83f5a..426ae1b3 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -451,23 +451,25 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - - static constexpr int mantissa_explicit_bits(); - static constexpr int minimum_exponent(); - static constexpr int infinite_power(); - static constexpr int sign_index(); - static constexpr int + // TODO add type for bit shift operations and use it. + // TODO add type for exponent operations and use it. + + static constexpr uint8_t mantissa_explicit_bits(); + static constexpr int16_t minimum_exponent(); + static constexpr int16_t infinite_power(); + static constexpr uint8_t sign_index(); + static constexpr int8_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int max_exponent_fast_path(); - static constexpr int max_exponent_round_to_even(); - static constexpr int min_exponent_round_to_even(); - static constexpr uint64_t max_mantissa_fast_path(int64_t power); - static constexpr uint64_t + static constexpr int8_t max_exponent_fast_path(); + static constexpr int16_t max_exponent_round_to_even(); + static constexpr int16_t min_exponent_round_to_even(); + static constexpr equiv_uint max_mantissa_fast_path(int64_t power); + static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int largest_power_of_ten(); - static constexpr int smallest_power_of_ten(); + static constexpr int16_t largest_power_of_ten(); + static constexpr int16_t smallest_power_of_ten(); static constexpr T exact_power_of_ten(int64_t power); - static constexpr size_t max_digits(); + static constexpr uint16_t max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); static constexpr equiv_uint hidden_bit_mask(); @@ -531,7 +533,7 @@ template struct binary_format_lookup_tables { // Largest integer value v so that (5**index * v) <= 1<<24. // 0x1000000 == 1<<24 - static constexpr uint64_t max_mantissa[] = { + static constexpr uint32_t max_mantissa[] = { 0x1000000, 0x1000000 / 5, 0x1000000 / (5 * 5), @@ -557,7 +559,7 @@ constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; #endif template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -566,7 +568,7 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -575,70 +577,70 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 23; } template <> -inline constexpr int binary_format::max_exponent_round_to_even() { +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr int binary_format::max_exponent_round_to_even() { +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr int binary_format::min_exponent_round_to_even() { +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr int binary_format::min_exponent_round_to_even() { +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -17; } -template <> inline constexpr int binary_format::minimum_exponent() { +template <> inline constexpr int16_t binary_format::minimum_exponent() { return -1023; } -template <> inline constexpr int binary_format::minimum_exponent() { +template <> inline constexpr int16_t binary_format::minimum_exponent() { return -127; } -template <> inline constexpr int binary_format::infinite_power() { +template <> inline constexpr int16_t binary_format::infinite_power() { return 0x7FF; } -template <> inline constexpr int binary_format::infinite_power() { +template <> inline constexpr int16_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 63; } -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 31; } #endif template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 22; } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 10; } @@ -648,8 +650,8 @@ inline constexpr uint64_t binary_format::max_mantissa_fast_path() { } template <> -inline constexpr uint64_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); +inline constexpr uint32_t binary_format::max_mantissa_fast_path() { + return uint32_t(2) << mantissa_explicit_bits(); } // credit: Jakub Jelínek @@ -660,7 +662,7 @@ template struct binary_format_lookup_tables { // Largest integer value v so that (5**index * v) <= 1<<11. // 0x800 == 1<<11 - static constexpr uint64_t max_mantissa[] = {0x800, + static constexpr uint16_t max_mantissa[] = {0x800, 0x800 / 5, 0x800 / (5 * 5), 0x800 / (5 * 5 * 5), @@ -675,7 +677,7 @@ constexpr std::float16_t binary_format_lookup_tables::powers_of_ten[]; template -constexpr uint64_t +constexpr uint16_t binary_format_lookup_tables::max_mantissa[]; #endif @@ -706,19 +708,19 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 4; } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 10; } template <> -inline constexpr uint64_t +inline constexpr int8_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); + return uint16_t(2) << mantissa_explicit_bits(); } template <> @@ -732,52 +734,52 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr int +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 5; } template <> -inline constexpr int +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -22; } template <> -inline constexpr int binary_format::minimum_exponent() { +inline constexpr int16_t binary_format::minimum_exponent() { return -15; } template <> -inline constexpr int binary_format::infinite_power() { +inline constexpr int16_t binary_format::infinite_power() { return 0x1F; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr unsigned int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr int binary_format::largest_power_of_ten() { +inline constexpr int16_t binary_format::largest_power_of_ten() { return 4; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t binary_format::smallest_power_of_ten() { return -27; } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr uint8_t binary_format::max_digits() { return 22; } #endif // __STDCPP_FLOAT16_T__ @@ -815,7 +817,7 @@ binary_format::exact_power_of_ten(int64_t power) { } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 3; } @@ -838,14 +840,14 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 7; } template <> -inline constexpr uint64_t +inline constexpr binary_format::equiv_uint binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); + return binary_format::equiv_uint(2) << mantissa_explicit_bits(); } template <> @@ -859,52 +861,52 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr int +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr int +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -24; } template <> -inline constexpr int binary_format::minimum_exponent() { +inline constexpr int16_t binary_format::minimum_exponent() { return -127; } template <> -inline constexpr int binary_format::infinite_power() { +inline constexpr int16_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr int binary_format::largest_power_of_ten() { +inline constexpr int16_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t binary_format::smallest_power_of_ten() { return -60; } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr uint16_t binary_format::max_digits() { return 98; } #endif // __STDCPP_BFLOAT16_T__ @@ -920,7 +922,7 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr uint64_t +inline constexpr uint32_t binary_format::max_mantissa_fast_path(int64_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 10); @@ -948,28 +950,28 @@ inline constexpr float binary_format::exact_power_of_ten(int64_t power) { return (void)powers_of_ten[0], powers_of_ten[power]; } -template <> inline constexpr int binary_format::largest_power_of_ten() { +template <> inline constexpr int16_t binary_format::largest_power_of_ten() { return 308; } -template <> inline constexpr int binary_format::largest_power_of_ten() { +template <> inline constexpr int16_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t binary_format::smallest_power_of_ten() { return -342; } -template <> inline constexpr int binary_format::smallest_power_of_ten() { +template <> inline constexpr int16_t binary_format::smallest_power_of_ten() { return -64; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr uint16_t binary_format::max_digits() { return 769; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr uint16_t binary_format::max_digits() { return 114; } From f8625b64164702e0b7d20b199383537a795799e5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 10 Apr 2025 18:23:01 +0300 Subject: [PATCH 075/252] fix warnings. --- benchmarks/benchmark.cpp | 9 +- benchmarks/event_counter.h | 3 +- benchmarks/linux-perf-events.h | 3 +- include/fast_float/ascii_number.h | 61 ++++--- include/fast_float/bigint.h | 14 +- include/fast_float/constexpr_feature_detect.h | 1 - include/fast_float/digit_comparison.h | 25 ++- include/fast_float/float_common.h | 166 ++++++++++-------- tests/basictest.cpp | 15 +- tests/fortran.cpp | 36 ++-- tests/json_fmt.cpp | 31 ++-- 11 files changed, 198 insertions(+), 166 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 0d045bd5..3a9c9651 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,5 +1,5 @@ -//#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +// #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS @@ -146,8 +146,8 @@ time_it_ns(std::vector> &lines, T const &function, return std::make_pair(min_value, average); } -void pretty_print(size_t volume, size_t number_of_floats, std::string const &name, - std::pair result) { +void pretty_print(size_t volume, size_t number_of_floats, + std::string const &name, std::pair result) { double volumeMB = volume / (1024. * 1024.); printf("%-40s: %8.2f MB/s (+/- %.1f %%) ", name.data(), volumeMB * 1000000000 / result.first, @@ -223,7 +223,8 @@ void fileload(std::string filename) { int main(int argc, char **argv) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled" << std::endl; + std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled" + << std::endl; #endif #ifdef USING_COUNTERS if (collector.has_events()) { diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index 24c21a81..ee37f08a 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -37,7 +37,8 @@ struct event_count { event_count() : elapsed(0), event_counts{0, 0, 0, 0} {} event_count(const std::chrono::duration &_elapsed, - const std::array &_event_counts) + const std::array + &_event_counts) : elapsed(_elapsed), event_counts(_event_counts) {} event_count(const event_count &other) diff --git a/benchmarks/linux-perf-events.h b/benchmarks/linux-perf-events.h index 88460da8..1076c6d0 100644 --- a/benchmarks/linux-perf-events.h +++ b/benchmarks/linux-perf-events.h @@ -22,7 +22,8 @@ template class LinuxEvents { std::vector ids{}; public: - explicit LinuxEvents(std::array config_vec) : fd(0), working(true) { + explicit LinuxEvents(std::array config_vec) + : fd(0), working(true) { memset(&attribs, 0, sizeof(attribs)); attribs.type = TYPE; attribs.size = sizeof(attribs); diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index ec2b6b8a..cef36b85 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -301,8 +301,9 @@ parse_number_string(UC const *p, UC const *pend, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || (uint8_t(options.format & chars_format::allow_leading_plus) && - !basic_json_fmt && *p == UC('+'))) { + if ((*p == UC('-')) || + (uint8_t(options.format & chars_format::allow_leading_plus) && + !basic_json_fmt && *p == UC('+'))) { ++p; if (p == pend) { return report_parse_error( @@ -316,8 +317,8 @@ parse_number_string(UC const *p, UC const *pend, } else { if (!is_integer(*p) && - (*p != - options.decimal_point)) { // a sign must be followed by an integer or the dot + (*p != options.decimal_point)) { // a sign must be followed by an + // integer or the dot return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } @@ -331,13 +332,15 @@ parse_number_string(UC const *p, UC const *pend, while ((p != pend) && is_integer(*p)) { // a multiplication by 10 is cheaper than an arbitrary integer // multiplication - answer.mantissa = 10 * answer.mantissa + + answer.mantissa = + 10 * answer.mantissa + uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; - uint16_t digit_count = uint16_t(end_of_integer_part - start_digits); + uint16_t digit_count = + static_cast(end_of_integer_part - start_digits); answer.integer = span(start_digits, digit_count); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -363,40 +366,42 @@ parse_number_string(UC const *p, UC const *pend, while ((p != pend) && is_integer(*p)) { uint8_t const digit = uint8_t(*p - UC('0')); - answer.mantissa = answer.mantissa * 10 + digit; // in rare cases, this will overflow, but that's ok + answer.mantissa = + answer.mantissa * 10 + + digit; // in rare cases, this will overflow, but that's ok ++p; } - fraction = uint16_t(before - p); - answer.fraction = span(before, uint16_t(p - before)); + fraction = static_cast(before - p); + answer.fraction = span(before, static_cast(p - before)); digit_count -= fraction; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in fractional part if (has_decimal_point && fraction == 0) { - return report_parse_error(p, - parse_error::no_digits_in_fractional_part); + return report_parse_error( + p, parse_error::no_digits_in_fractional_part); } } #endif - } - 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(p, parse_error::no_digits_in_mantissa); } // We have now parsed the integer and the fraction part of the mantissa. - + // Now we can parse the exponent part. - if (p != pend && - (uint8_t(options.format & chars_format::scientific) && - (UC('e') == *p) || (UC('E') == *p)) + if ((p != pend) && (uint8_t(options.format & chars_format::scientific) && + (UC('e') == *p) || + (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint8_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || - (UC('d') == *p) || (UC('D') == *p))) + || (uint8_t(options.format & detail::basic_fortran_fmt) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) #endif ) { UC const *location_of_e = p; ++p; - + bool neg_exp = false; if (p != pend) { if (UC('-') == *p) { @@ -467,16 +472,19 @@ parse_number_string(UC const *p, UC const *pend, p = answer.integer.ptr; UC const *int_end = p + answer.integer.len(); uint64_t const minimal_nineteen_digit_integer{1000000000000000000}; - while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != int_end)) { + while ((answer.mantissa < minimal_nineteen_digit_integer) && + (p != int_end)) { answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); ++p; } - if (answer.mantissa >= minimal_nineteen_digit_integer) { // We have a big integers + if (answer.mantissa >= + minimal_nineteen_digit_integer) { // We have a big integers answer.exponent += int16_t(end_of_integer_part - p); } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); - while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != frac_end)) { + while ((answer.mantissa < minimal_nineteen_digit_integer) && + (p != frac_end)) { answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); ++p; } @@ -537,12 +545,11 @@ parse_int_string(UC const *p, UC const *pend, T &value, if (digit >= options.base) { break; } - i = uint64_t(options.base) * i + - digit; // might overflow, check this later + i = uint64_t(options.base) * i + digit; // might overflow, check this later p++; } - uint16_t const digit_count = uint16_t(p - start_digits); + uint16_t const digit_count = static_cast(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index aa18c2f8..86c8a2b2 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -71,9 +71,7 @@ template struct stackvec { } // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(uint8_t len) noexcept { - length = len; - } + FASTFLOAT_CONSTEXPR14 void set_len(uint8_t len) noexcept { length = len; } constexpr uint8_t len() const noexcept { return length; } @@ -101,7 +99,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { limb *ptr = data + length; std::copy_n(s.ptr, s.len(), ptr); - set_len(len() + s.len()); + set_len(uint8_t(len() + s.len())); } // try to add items to the vector, returning if items were added @@ -304,7 +302,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { - FASTFLOAT_TRY(x.try_resize(y.len() + start, 0)); + FASTFLOAT_TRY(x.try_resize(uint8_t(y.len() + start), 0)); } bool carry = false; @@ -547,7 +545,7 @@ struct bigint : pow5_tables<> { limb *first = vec.data; limb *last = first + n; ::std::fill(first, last, 0); - vec.set_len(n + vec.len()); + vec.set_len(uint8_t(n + vec.len())); return true; } else { return true; @@ -584,8 +582,8 @@ struct bigint : pow5_tables<> { // get the number of bits in the bigint. FASTFLOAT_CONSTEXPR20 uint16_t bit_length() const noexcept { - uint16_t lz = ctlz(); - return uint16_t(limb_bits * vec.len()) - lz; + uint8_t lz = ctlz(); + return limb_bits * vec.len() - lz; } FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index d4399b0b..8d409dfc 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -58,7 +58,6 @@ #define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 #endif - // For support attribute [[assume]] is declared in P1774 #if defined(__cpp_attrubute_assume) #define FASTFLOAT_ASSUME(expr) [[assume(expr)]] diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 82a2953c..d772ca13 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -262,7 +262,7 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - uint16_t const max_digits = uint16_t(binary_format::max_digits()); + uint16_t const max_digits = binary_format::max_digits(); uint16_t counter = 0; uint16_t digits = 0; limb value = 0; @@ -342,14 +342,13 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { } template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -positive_digit_comp(bigint &bigmant, adjusted_mantissa am, - int16_t const exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( + bigint &bigmant, adjusted_mantissa am, int16_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(exponent)); bool truncated; am.mantissa = bigmant.hi64(truncated); int16_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); + binary_format::minimum_exponent(); am.power2 = bigmant.bit_length() - 64 + bias; round(am, [truncated](adjusted_mantissa &a, int16_t shift) { @@ -370,15 +369,15 @@ positive_digit_comp(bigint &bigmant, adjusted_mantissa am, // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -negative_digit_comp(bigint &bigmant, adjusted_mantissa am, - int16_t const exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( + bigint &bigmant, adjusted_mantissa am, int16_t const exponent) noexcept { bigint &real_digits = bigmant; int16_t const &real_exp = exponent; T b; { - // get the value of `b`, rounded down, and get a bigint representation of b+h + // get the value of `b`, rounded down, and get a bigint representation of + // b+h adjusted_mantissa am_b = am; // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. @@ -386,9 +385,9 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa am, [](adjusted_mantissa &a, int16_t shift) { round_down(a, shift); }); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - false, + false, #endif - am_b, b); + am_b, b); } adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); @@ -396,7 +395,7 @@ negative_digit_comp(bigint &bigmant, adjusted_mantissa am, // scale real digits and theor digits to be same power. int16_t pow2_exp = theor_exp - real_exp; - uint16_t pow5_exp = uint16_t(-real_exp); + uint16_t pow5_exp = -real_exp; if (pow5_exp != 0) { FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); } @@ -447,7 +446,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( bigint bigmant; int16_t const sci_exp = scientific_exponent(num); - + uint16_t const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. int16_t const exponent = sci_exp + 1 - digits; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7de83f5a..780f6d7b 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -202,12 +202,18 @@ using parse_options = parse_options_t; #ifndef FASTFLOAT_ASSERT #define FASTFLOAT_ASSERT(x) \ - { ((void)(x)); FASTFLOAT_ASSUME(x); } + { \ + ((void)(x)); \ + FASTFLOAT_ASSUME(x); \ + } #endif #ifndef FASTFLOAT_DEBUG_ASSERT #define FASTFLOAT_DEBUG_ASSERT(x) \ - { ((void)(x)); FASTFLOAT_ASSUME(x); } + { \ + ((void)(x)); \ + FASTFLOAT_ASSUME(x); \ + } #endif // rust style `try!()` macro, or `?` operator @@ -295,7 +301,8 @@ template struct span { T const *ptr; uint16_t length; - constexpr span(T const *_ptr, uint16_t _length) : ptr(_ptr), length(_length) {} + constexpr span(T const *_ptr, uint16_t _length) + : ptr(_ptr), length(_length) {} constexpr span() : ptr(nullptr), length(0) {} @@ -451,23 +458,25 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - - static constexpr int mantissa_explicit_bits(); - static constexpr int minimum_exponent(); - static constexpr int infinite_power(); - static constexpr int sign_index(); - static constexpr int + // TODO add type for bit shift operations and use it. + // TODO add type for exponent operations and use it. + + static constexpr uint8_t mantissa_explicit_bits(); + static constexpr int16_t minimum_exponent(); + static constexpr int16_t infinite_power(); + static constexpr uint8_t sign_index(); + static constexpr int8_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int max_exponent_fast_path(); - static constexpr int max_exponent_round_to_even(); - static constexpr int min_exponent_round_to_even(); - static constexpr uint64_t max_mantissa_fast_path(int64_t power); - static constexpr uint64_t + static constexpr int8_t max_exponent_fast_path(); + static constexpr int16_t max_exponent_round_to_even(); + static constexpr int16_t min_exponent_round_to_even(); + static constexpr equiv_uint max_mantissa_fast_path(int64_t power); + static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int largest_power_of_ten(); - static constexpr int smallest_power_of_ten(); + static constexpr int16_t largest_power_of_ten(); + static constexpr int16_t smallest_power_of_ten(); static constexpr T exact_power_of_ten(int64_t power); - static constexpr size_t max_digits(); + static constexpr uint16_t max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); static constexpr equiv_uint hidden_bit_mask(); @@ -531,7 +540,7 @@ template struct binary_format_lookup_tables { // Largest integer value v so that (5**index * v) <= 1<<24. // 0x1000000 == 1<<24 - static constexpr uint64_t max_mantissa[] = { + static constexpr uint32_t max_mantissa[] = { 0x1000000, 0x1000000 / 5, 0x1000000 / (5 * 5), @@ -557,7 +566,7 @@ constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; #endif template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -566,7 +575,7 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -575,70 +584,70 @@ inline constexpr int binary_format::min_exponent_fast_path() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t binary_format::mantissa_explicit_bits() { return 23; } template <> -inline constexpr int binary_format::max_exponent_round_to_even() { +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr int binary_format::max_exponent_round_to_even() { +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr int binary_format::min_exponent_round_to_even() { +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr int binary_format::min_exponent_round_to_even() { +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -17; } -template <> inline constexpr int binary_format::minimum_exponent() { +template <> inline constexpr int16_t binary_format::minimum_exponent() { return -1023; } -template <> inline constexpr int binary_format::minimum_exponent() { +template <> inline constexpr int16_t binary_format::minimum_exponent() { return -127; } -template <> inline constexpr int binary_format::infinite_power() { +template <> inline constexpr int16_t binary_format::infinite_power() { return 0x7FF; } -template <> inline constexpr int binary_format::infinite_power() { +template <> inline constexpr int16_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 63; } -template <> inline constexpr int binary_format::sign_index() { +template <> inline constexpr uint8_t binary_format::sign_index() { return 31; } #endif template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 22; } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t binary_format::max_exponent_fast_path() { return 10; } @@ -648,8 +657,8 @@ inline constexpr uint64_t binary_format::max_mantissa_fast_path() { } template <> -inline constexpr uint64_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); +inline constexpr uint32_t binary_format::max_mantissa_fast_path() { + return uint32_t(2) << mantissa_explicit_bits(); } // credit: Jakub Jelínek @@ -660,7 +669,7 @@ template struct binary_format_lookup_tables { // Largest integer value v so that (5**index * v) <= 1<<11. // 0x800 == 1<<11 - static constexpr uint64_t max_mantissa[] = {0x800, + static constexpr uint16_t max_mantissa[] = {0x800, 0x800 / 5, 0x800 / (5 * 5), 0x800 / (5 * 5 * 5), @@ -675,7 +684,7 @@ constexpr std::float16_t binary_format_lookup_tables::powers_of_ten[]; template -constexpr uint64_t +constexpr uint16_t binary_format_lookup_tables::max_mantissa[]; #endif @@ -706,19 +715,21 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t +binary_format::max_exponent_fast_path() { return 4; } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t +binary_format::mantissa_explicit_bits() { return 10; } template <> -inline constexpr uint64_t +inline constexpr int8_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); + return uint16_t(2) << mantissa_explicit_bits(); } template <> @@ -732,52 +743,55 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t +binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr int +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 5; } template <> -inline constexpr int +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -22; } template <> -inline constexpr int binary_format::minimum_exponent() { +inline constexpr int16_t binary_format::minimum_exponent() { return -15; } template <> -inline constexpr int binary_format::infinite_power() { +inline constexpr int16_t binary_format::infinite_power() { return 0x1F; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr unsigned int binary_format::sign_index() { +template <> +inline constexpr uint8_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr int binary_format::largest_power_of_ten() { +inline constexpr int16_t binary_format::largest_power_of_ten() { return 4; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t +binary_format::smallest_power_of_ten() { return -27; } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr uint8_t binary_format::max_digits() { return 22; } #endif // __STDCPP_FLOAT16_T__ @@ -815,7 +829,8 @@ binary_format::exact_power_of_ten(int64_t power) { } template <> -inline constexpr int binary_format::max_exponent_fast_path() { +inline constexpr int8_t +binary_format::max_exponent_fast_path() { return 3; } @@ -838,14 +853,16 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int binary_format::mantissa_explicit_bits() { +inline constexpr uint8_t +binary_format::mantissa_explicit_bits() { return 7; } template <> -inline constexpr uint64_t +inline constexpr binary_format::equiv_uint binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); + return binary_format::equiv_uint(2) + << mantissa_explicit_bits(); } template <> @@ -859,52 +876,56 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr int binary_format::min_exponent_fast_path() { +inline constexpr int8_t +binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr int +inline constexpr int16_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr int +inline constexpr int16_t binary_format::min_exponent_round_to_even() { return -24; } template <> -inline constexpr int binary_format::minimum_exponent() { +inline constexpr int16_t binary_format::minimum_exponent() { return -127; } template <> -inline constexpr int binary_format::infinite_power() { +inline constexpr int16_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr int binary_format::sign_index() { +template <> +inline constexpr uint8_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr int binary_format::largest_power_of_ten() { +inline constexpr int16_t +binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t +binary_format::smallest_power_of_ten() { return -60; } template <> -inline constexpr size_t binary_format::max_digits() { +inline constexpr uint16_t binary_format::max_digits() { return 98; } #endif // __STDCPP_BFLOAT16_T__ @@ -920,7 +941,7 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr uint64_t +inline constexpr uint32_t binary_format::max_mantissa_fast_path(int64_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 10); @@ -948,28 +969,31 @@ inline constexpr float binary_format::exact_power_of_ten(int64_t power) { return (void)powers_of_ten[0], powers_of_ten[power]; } -template <> inline constexpr int binary_format::largest_power_of_ten() { +template <> +inline constexpr int16_t binary_format::largest_power_of_ten() { return 308; } -template <> inline constexpr int binary_format::largest_power_of_ten() { +template <> +inline constexpr int16_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int binary_format::smallest_power_of_ten() { +inline constexpr int16_t binary_format::smallest_power_of_ten() { return -342; } -template <> inline constexpr int binary_format::smallest_power_of_ten() { +template <> +inline constexpr int16_t binary_format::smallest_power_of_ten() { return -64; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr uint16_t binary_format::max_digits() { return 769; } -template <> inline constexpr size_t binary_format::max_digits() { +template <> inline constexpr uint16_t binary_format::max_digits() { return 114; } diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 8f269020..9b61bdf4 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -656,7 +656,8 @@ TEST_CASE("decimal_point_parsing") { answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options({fast_float::chars_format::general, ',', 10})); + fast_float::parse_options( + {fast_float::chars_format::general, ',', 10})); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -666,8 +667,8 @@ TEST_CASE("decimal_point_parsing") { std::string const input = "1.25"; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options({fast_float::chars_format::general, ',', - 10})); + fast_float::parse_options( + {fast_float::chars_format::general, ',', 10})); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at dot"); @@ -1324,8 +1325,8 @@ TEST_CASE("double.general") { TEST_CASE("double.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options({fast_float::chars_format::general, ',', - 10}); + return fast_float::parse_options( + {fast_float::chars_format::general, ',', 10}); }(); // infinities @@ -1642,8 +1643,8 @@ TEST_CASE("float.general") { TEST_CASE("float.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options({fast_float::chars_format::general, ',', - 10}); + return fast_float::parse_options( + {fast_float::chars_format::general, ',', 10}); }(); // infinity diff --git a/tests/fortran.cpp b/tests/fortran.cpp index 2f49946b..ca419868 100644 --- a/tests/fortran.cpp +++ b/tests/fortran.cpp @@ -11,9 +11,9 @@ int main_readme() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options ({ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus})); + fast_float::parse_options( + {fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus})); if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n" << result << "\n"; return EXIT_FAILURE; @@ -35,11 +35,11 @@ int main() { for (auto const &f : fmt1) { auto d{std::distance(&fmt1[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, - fast_float::parse_options ({ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced( + f.data(), f.data() + f.size(), result, + fast_float::parse_options( + {fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -49,11 +49,11 @@ int main() { for (auto const &f : fmt2) { auto d{std::distance(&fmt2[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, - fast_float::parse_options ({ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced( + f.data(), f.data() + f.size(), result, + fast_float::parse_options( + {fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -63,11 +63,11 @@ int main() { for (auto const &f : fmt3) { auto d{std::distance(&fmt3[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), - result, - fast_float::parse_options ({ - fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced( + f.data(), f.data() + f.size(), result, + fast_float::parse_options( + {fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}))}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index bf3b4022..70fdef2c 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -9,10 +9,10 @@ int main_readme() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options({ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}) // should be ignored - ); + fast_float::parse_options options( + {fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus}) // should be ignored + ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -25,10 +25,10 @@ int main_readme2() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options({ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}) // should be ignored - ); + fast_float::parse_options options( + {fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus}) // should be ignored + ); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -42,10 +42,10 @@ int main_readme3() { double result; auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, - fast_float::parse_options options({ - fast_float::chars_format::json_or_infnan | - fast_float::chars_format::allow_leading_plus}); // should be ignored - ); + fast_float::parse_options options( + {fast_float::chars_format::json_or_infnan | + fast_float::chars_format::allow_leading_plus}); // should be ignored + ); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; @@ -136,9 +136,10 @@ int main() { auto const &expected_reason = reject[i].reason; auto answer = fast_float::parse_number_string( f.data(), f.data() + f.size(), - fast_float::parse_options({ - fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus})); // should be ignored + fast_float::parse_options( + {fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus})); // should be + // ignored if (answer.valid) { std::cerr << "json parse accepted invalid json " << f << std::endl; return EXIT_FAILURE; From e71bfff4a348ea1228e335672feb10bad5d43f65 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 18:05:08 +0300 Subject: [PATCH 076/252] additional improve for debug runtime. --- include/fast_float/float_common.h | 10 +++++----- include/fast_float/parse_number.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 780f6d7b..8ada34d5 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -68,20 +68,20 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( - chars_format fmt = chars_format::general, UC dot = UC('.'), + chars_format const fmt = chars_format::general, UC const dot = UC('.'), int const b = 10) noexcept : format(fmt), decimal_point(dot), base(uint8_t(b)) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - assert(b >= 2 && b <= 36); + //static_assert(b >= 2 && b <= 36); #endif } /** Which number formats are accepted */ - chars_format format; + chars_format const format; /** The character used as decimal point */ - UC decimal_point; + UC const decimal_point; /** The base used for integers */ - uint8_t base; /* only allowed from 2 to 36 */ + uint8_t const base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index ca94b059..7cece6b7 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -312,7 +312,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint8_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { - first++; + ++first; } } if (first == last) { @@ -375,7 +375,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (uint8_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { - first++; + ++first; } } if (first == last || options.base < 2 || options.base > 36) { From 88b3887b5200e481b1c570bbb1bb5b66217603dd Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 18:15:54 +0300 Subject: [PATCH 077/252] benchmark cleanup. --- benchmarks/benchmark.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 3a9c9651..0dd85e06 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -207,7 +207,7 @@ void fileload(std::string filename) { std::cout << "#### " << std::endl; std::string line; std::vector lines; - lines.reserve(10000); // let us reserve plenty of memory. + lines.reserve(120000); // let us reserve plenty of memory. size_t volume = 0; while (getline(inputfile, line)) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -241,8 +241,7 @@ int main(int argc, char **argv) { fileload(argv[1]); return EXIT_SUCCESS; } - fileload(std::string(BENCHMARK_DATA_DIR) + "/contrived.txt"); - fileload(std::string(BENCHMARK_DATA_DIR) + "/canada_short.txt"); + fileload(std::string(BENCHMARK_DATA_DIR) + "/canada.txt"); fileload(std::string(BENCHMARK_DATA_DIR) + "/mesh.txt"); return EXIT_SUCCESS; From 563648f76d1b4efb95691750c49b79fd9b6074dc Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 22:52:18 +0300 Subject: [PATCH 078/252] * fix errors in the parse_number_string. --- include/fast_float/ascii_number.h | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index cef36b85..89a311d2 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -260,6 +260,7 @@ enum class parse_error { }; template struct parsed_number_string_t { + // an unsigned int avoids signed overflows (which are bad) uint64_t mantissa{0}; int16_t exponent{0}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -328,7 +329,6 @@ parse_number_string(UC const *p, UC const *pend, UC const *const start_digits = p; - // an unsigned int avoids signed overflows (which are bad) while ((p != pend) && is_integer(*p)) { // a multiplication by 10 is cheaper than an arbitrary integer // multiplication @@ -359,7 +359,6 @@ parse_number_string(UC const *p, UC const *pend, if (has_decimal_point) { ++p; UC const *before = p; - uint16_t fraction = 0; // can occur at most twice without overflowing, but let it occur more, since // for integers with many digits, digit parsing is the primary bottleneck. loop_parse_if_eight_digits(p, pend, answer.mantissa); @@ -371,13 +370,13 @@ parse_number_string(UC const *p, UC const *pend, digit; // in rare cases, this will overflow, but that's ok ++p; } - fraction = static_cast(before - p); + answer.exponent = static_cast(before - p); answer.fraction = span(before, static_cast(p - before)); - digit_count -= fraction; + digit_count -= answer.exponent; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in fractional part - if (has_decimal_point && fraction == 0) { + if (has_decimal_point && answer.exponent == 0) { return report_parse_error( p, parse_error::no_digits_in_fractional_part); } @@ -389,7 +388,8 @@ parse_number_string(UC const *p, UC const *pend, } // We have now parsed the integer and the fraction part of the mantissa. - // Now we can parse the exponent part. + // Now we can parse the explicit exponential part. + int16_t exp_number = 0; // explicit exponential part if ((p != pend) && (uint8_t(options.format & chars_format::scientific) && (UC('e') == *p) || (UC('E') == *p)) @@ -400,8 +400,14 @@ parse_number_string(UC const *p, UC const *pend, #endif ) { UC const *location_of_e = p; +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; - +#else + if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || + (UC('D') == *p)) { + ++p; + } +#endif bool neg_exp = false; if (p != pend) { if (UC('-') == *p) { @@ -423,16 +429,17 @@ parse_number_string(UC const *p, UC const *pend, p = location_of_e; } else { while ((p != pend) && is_integer(*p)) { - if (answer.exponent < 0x1000) { + if (exp_number < 0x1000) { // check for exponent overflow if we have too many digits. uint8_t const digit = uint8_t(*p - UC('0')); - answer.exponent = 10 * answer.exponent + digit; + exp_number = 10 * exp_number + digit; } ++p; } if (neg_exp) { - answer.exponent = -answer.exponent; + exp_number = -exp_number; } + answer.exponent += exp_number; } } else { // If it scientific and not fixed, we have to bail out. @@ -479,7 +486,7 @@ parse_number_string(UC const *p, UC const *pend, } if (answer.mantissa >= minimal_nineteen_digit_integer) { // We have a big integers - answer.exponent += int16_t(end_of_integer_part - p); + answer.exponent = int16_t(end_of_integer_part - p) + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); @@ -488,7 +495,7 @@ parse_number_string(UC const *p, UC const *pend, answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); ++p; } - answer.exponent += int16_t(answer.fraction.ptr - p); + answer.exponent = int16_t(answer.fraction.ptr - p) + exp_number; } // We have now corrected both exponent and mantissa, to a truncated value } From 0daee75decddbad3903da2e485d7c23339e0f0d5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 22:56:15 +0300 Subject: [PATCH 079/252] # format --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 8ada34d5..2ca4f3a6 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -72,7 +72,7 @@ template struct parse_options_t { int const b = 10) noexcept : format(fmt), decimal_point(dot), base(uint8_t(b)) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - //static_assert(b >= 2 && b <= 36); + // static_assert(b >= 2 && b <= 36); #endif } From 1aed8ee6ddc2ffd32a24d9cfe50dca455e471334 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 23:10:26 +0300 Subject: [PATCH 080/252] try reordering again. --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 89a311d2..86b0982e 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -263,6 +263,8 @@ template struct parsed_number_string_t { // an unsigned int avoids signed overflows (which are bad) uint64_t mantissa{0}; int16_t exponent{0}; + UC const *lastmatch{nullptr}; + parse_error error{parse_error::no_error}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif @@ -271,8 +273,6 @@ template struct parsed_number_string_t { // contains the range of the significant digits span integer{}; // non-nullable span fraction{}; // nullable - UC const *lastmatch{nullptr}; - parse_error error{parse_error::no_error}; }; using byte_span = span; From f3db77a07c25f0440b1f76cb48a176103025b166 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 23:21:26 +0300 Subject: [PATCH 081/252] try reordering again. --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 86b0982e..c4b4da76 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -264,7 +264,6 @@ template struct parsed_number_string_t { uint64_t mantissa{0}; int16_t exponent{0}; UC const *lastmatch{nullptr}; - parse_error error{parse_error::no_error}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif @@ -273,6 +272,7 @@ template struct parsed_number_string_t { // contains the range of the significant digits span integer{}; // non-nullable span fraction{}; // nullable + parse_error error{parse_error::no_error}; }; using byte_span = span; From b0bae17b10eb9afc65ad985528fe28002242c6ef Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 11 Apr 2025 23:49:27 +0300 Subject: [PATCH 082/252] * added chars_format_t for performance reason. --- include/fast_float/ascii_number.h | 14 +++++++------- include/fast_float/float_common.h | 14 +++++++++----- include/fast_float/parse_number.h | 10 +++++----- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index c4b4da76..98e22233 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -303,7 +303,7 @@ parse_number_string(UC const *p, UC const *pend, answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*p == UC('-')) || - (uint8_t(options.format & chars_format::allow_leading_plus) && + (chars_format_t(options.format & chars_format::allow_leading_plus) && !basic_json_fmt && *p == UC('+'))) { ++p; if (p == pend) { @@ -390,11 +390,11 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. int16_t exp_number = 0; // explicit exponential part - if ((p != pend) && (uint8_t(options.format & chars_format::scientific) && + if ((p != pend) && (chars_format_t(options.format & chars_format::scientific) && (UC('e') == *p) || (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (uint8_t(options.format & detail::basic_fortran_fmt) && + || (chars_format_t(options.format & detail::basic_fortran_fmt) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || (UC('D') == *p))) #endif @@ -419,7 +419,7 @@ parse_number_string(UC const *p, UC const *pend, } } if ((p == pend) || !is_integer(*p)) { - if (!uint8_t(options.format & chars_format::fixed)) { + if (!chars_format_t(options.format & chars_format::fixed)) { // The exponential part is invalid for scientific notation, so it must // be a trailing token for fixed notation. However, fixed notation is // disabled, so report a scientific notation error. @@ -443,8 +443,8 @@ parse_number_string(UC const *p, UC const *pend, } } else { // If it scientific and not fixed, we have to bail out. - if (uint8_t(options.format & chars_format::scientific) && - !uint8_t(options.format & chars_format::fixed)) { + if (chars_format_t(options.format & chars_format::scientific) && + !chars_format_t(options.format & chars_format::fixed)) { return report_parse_error(p, parse_error::missing_exponential_part); } } @@ -527,7 +527,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, return answer; } if ((*p == UC('-')) || - (uint8_t(options.format & chars_format::allow_leading_plus) && + (chars_format_t(options.format & chars_format::allow_leading_plus) && (*p == UC('+')))) { ++p; } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2ca4f3a6..6e5fa92a 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,7 +33,11 @@ namespace fast_float { -enum class chars_format : uint8_t; +// because library only support 32 and 64 bit architectures, +// we should use 32 bit value here +typedef uint32_t chars_format_t; + +enum class chars_format : chars_format_t; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN namespace detail { @@ -42,7 +46,7 @@ constexpr chars_format basic_fortran_fmt = chars_format(1 << 5); } // namespace detail #endif -enum class chars_format : uint8_t { +enum class chars_format : chars_format_t { scientific = 1 << 0, fixed = 1 << 1, general = fixed | scientific, @@ -69,8 +73,8 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), - int const b = 10) noexcept - : format(fmt), decimal_point(dot), base(uint8_t(b)) { + chars_format_t const b = 10) noexcept + : format(fmt), decimal_point(dot), base(b) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // static_assert(b >= 2 && b <= 36); #endif @@ -81,7 +85,7 @@ template struct parse_options_t { /** The character used as decimal point */ UC const decimal_point; /** The base used for integers */ - uint8_t const base; /* only allowed from 2 to 36 */ + uint32_t const base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 7cece6b7..1b964648 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -33,7 +33,7 @@ from_chars_result_t bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*first == UC('-')) || - (uint64_t(fmt & chars_format::allow_leading_plus) && + (chars_format_t(fmt & chars_format::allow_leading_plus) && (*first == UC('+')))) { ++first; } @@ -310,7 +310,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, from_chars_result_t answer; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint8_t(options.format & chars_format::skip_white_space)) { + if (chars_format_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { ++first; } @@ -326,14 +326,14 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, #endif parsed_number_string_t const pns = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - uint8_t(options.format & detail::basic_json_fmt) + chars_format_t(options.format & detail::basic_json_fmt) ? parse_number_string(first, last, options) : #endif parse_number_string(first, last, options); if (!pns.valid) { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint8_t(options.format & chars_format::no_infnan)) { + if (chars_format_t(options.format & chars_format::no_infnan)) { #endif answer.ec = std::errc::invalid_argument; answer.ptr = first; @@ -373,7 +373,7 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, "only char, wchar_t, char16_t and char32_t are supported"); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (uint8_t(options.format & chars_format::skip_white_space)) { + if (chars_format_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { ++first; } From 69fbbff0623812285470cb0749c86d48ee67f14b Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 12 Apr 2025 00:47:18 +0300 Subject: [PATCH 083/252] try additional part... --- include/fast_float/bigint.h | 6 +++--- include/fast_float/float_common.h | 24 +++++++++++------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 86c8a2b2..0dba6239 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -19,11 +19,11 @@ namespace fast_float { #if defined(FASTFLOAT_64BIT) && !defined(__sparc) #define FASTFLOAT_64BIT_LIMB 1 typedef uint64_t limb; -constexpr uint16_t limb_bits = 64; +constexpr uint8_t limb_bits = 64; #else #define FASTFLOAT_32BIT_LIMB typedef uint32_t limb; -constexpr uint16_t limb_bits = 32; +constexpr uint8_t limb_bits = 32; #endif typedef span limb_span; @@ -33,7 +33,7 @@ typedef span limb_span; // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. constexpr uint16_t bigint_bits = 4000; -constexpr uint16_t bigint_limbs = bigint_bits / limb_bits; +constexpr uint8_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 6e5fa92a..5ed55adb 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,9 +33,7 @@ namespace fast_float { -// because library only support 32 and 64 bit architectures, -// we should use 32 bit value here -typedef uint32_t chars_format_t; +typedef uint8_t chars_format_t; enum class chars_format : chars_format_t; @@ -56,8 +54,8 @@ enum class chars_format : chars_format_t { // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 json = uint64_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. - json_or_infnan = uint64_t(detail::basic_json_fmt) | general, - fortran = uint64_t(detail::basic_fortran_fmt) | general, + json_or_infnan = chars_format_t(detail::basic_json_fmt) | general, + fortran = chars_format_t(detail::basic_fortran_fmt) | general, allow_leading_plus = 1 << 6, skip_white_space = 1 << 7, #endif @@ -85,7 +83,7 @@ template struct parse_options_t { /** The character used as decimal point */ UC const decimal_point; /** The base used for integers */ - uint32_t const base; /* only allowed from 2 to 36 */ + uint8_t const base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; @@ -305,10 +303,10 @@ template struct span { T const *ptr; uint16_t length; - constexpr span(T const *_ptr, uint16_t _length) + constexpr span(T const *_ptr, uint16_t _length) noexcept : ptr(_ptr), length(_length) {} - constexpr span() : ptr(nullptr), length(0) {} + constexpr span() noexcept : ptr(nullptr), length(0) {} constexpr uint16_t len() const noexcept { return length; } @@ -330,7 +328,7 @@ struct value128 { /* Helper C++14 constexpr generic implementation of leading_zeroes */ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint8_t -leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) { +leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) noexcept { if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; last_bit |= 32; @@ -404,7 +402,7 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { #if !defined(__MINGW64__) fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, uint64_t cd, - uint64_t *hi) { + uint64_t *hi) noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ @@ -1198,17 +1196,17 @@ template constexpr uint64_t int_luts::min_safe_u64[]; #endif template -fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { +fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) noexcept { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) { +fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) noexcept { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) noexcept { return int_luts<>::min_safe_u64[base - 2]; } From ba1344c0302165fc20df35bedf7b12922f8e95b8 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 12 Apr 2025 17:06:38 +0300 Subject: [PATCH 084/252] * carefully work with types in the library. * fix for some types errors. * fix small amount of not optimized code. * add more comments to the code. * unified of function binary_format::max_mantissa_fast_path() because it's do the same. --- include/fast_float/ascii_number.h | 30 ++--- include/fast_float/bigint.h | 153 +++++++++++----------- include/fast_float/decimal_to_binary.h | 7 +- include/fast_float/digit_comparison.h | 86 +++++++------ include/fast_float/float_common.h | 171 ++++++++++++------------- 5 files changed, 224 insertions(+), 223 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 98e22233..a2c84dd3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -261,8 +261,8 @@ enum class parse_error { template struct parsed_number_string_t { // an unsigned int avoids signed overflows (which are bad) - uint64_t mantissa{0}; - int16_t exponent{0}; + am_mant_t mantissa{0}; + am_pow_t exponent{0}; UC const *lastmatch{nullptr}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; @@ -334,13 +334,13 @@ parse_number_string(UC const *p, UC const *pend, // multiplication answer.mantissa = 10 * answer.mantissa + - uint64_t(*p - + UC(*p - UC('0')); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; - uint16_t digit_count = - static_cast(end_of_integer_part - start_digits); + am_digits digit_count = + static_cast(end_of_integer_part - start_digits); answer.integer = span(start_digits, digit_count); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -364,14 +364,14 @@ parse_number_string(UC const *p, UC const *pend, loop_parse_if_eight_digits(p, pend, answer.mantissa); while ((p != pend) && is_integer(*p)) { - uint8_t const digit = uint8_t(*p - UC('0')); + UC const digit = UC(*p - UC('0')); answer.mantissa = answer.mantissa * 10 + digit; // in rare cases, this will overflow, but that's ok ++p; } - answer.exponent = static_cast(before - p); - answer.fraction = span(before, static_cast(p - before)); + answer.exponent = static_cast(before - p); + answer.fraction = span(before, static_cast(p - before)); digit_count -= answer.exponent; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -389,7 +389,7 @@ parse_number_string(UC const *p, UC const *pend, // We have now parsed the integer and the fraction part of the mantissa. // Now we can parse the explicit exponential part. - int16_t exp_number = 0; // explicit exponential part + am_pow_t exp_number = 0; // explicit exponential part if ((p != pend) && (chars_format_t(options.format & chars_format::scientific) && (UC('e') == *p) || (UC('E') == *p)) @@ -431,7 +431,7 @@ parse_number_string(UC const *p, UC const *pend, while ((p != pend) && is_integer(*p)) { if (exp_number < 0x1000) { // check for exponent overflow if we have too many digits. - uint8_t const digit = uint8_t(*p - UC('0')); + UC const digit = UC(*p - UC('0')); exp_number = 10 * exp_number + digit; } ++p; @@ -478,24 +478,24 @@ parse_number_string(UC const *p, UC const *pend, answer.mantissa = 0; p = answer.integer.ptr; UC const *int_end = p + answer.integer.len(); - uint64_t const minimal_nineteen_digit_integer{1000000000000000000}; + am_mant_t const minimal_nineteen_digit_integer{1000000000000000000}; while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != int_end)) { - answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); + answer.mantissa = answer.mantissa * 10 + UC(*p - UC('0')); ++p; } if (answer.mantissa >= minimal_nineteen_digit_integer) { // We have a big integers - answer.exponent = int16_t(end_of_integer_part - p) + exp_number; + answer.exponent = am_pow_t(end_of_integer_part - p) + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; UC const *frac_end = p + answer.fraction.len(); while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != frac_end)) { - answer.mantissa = answer.mantissa * 10 + uint64_t(*p - UC('0')); + answer.mantissa = answer.mantissa * 10 + UC(*p - UC('0')); ++p; } - answer.exponent = int16_t(answer.fraction.ptr - p) + exp_number; + answer.exponent = am_pow_t(answer.fraction.ptr - p) + exp_number; } // We have now corrected both exponent and mantissa, to a truncated value } diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 0dba6239..489ad116 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -19,11 +19,11 @@ namespace fast_float { #if defined(FASTFLOAT_64BIT) && !defined(__sparc) #define FASTFLOAT_64BIT_LIMB 1 typedef uint64_t limb; -constexpr uint8_t limb_bits = 64; +constexpr limb_t limb_bits = 64; #else #define FASTFLOAT_32BIT_LIMB typedef uint32_t limb; -constexpr uint8_t limb_bits = 32; +constexpr limb_t limb_bits = 32; #endif typedef span limb_span; @@ -32,12 +32,13 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -constexpr uint16_t bigint_bits = 4000; -constexpr uint8_t bigint_limbs = bigint_bits / limb_bits; +typedef uint16_t bigint_bits_t; +constexpr bigint_bits_t bigint_bits = 4000; +constexpr limb_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. -template struct stackvec { +template struct stackvec { limb data[size]; // we never need more than 150 limbs uint8_t length{0}; @@ -53,31 +54,31 @@ template struct stackvec { FASTFLOAT_ASSERT(try_extend(s)); } - FASTFLOAT_CONSTEXPR14 limb &operator[](uint16_t index) noexcept { + FASTFLOAT_CONSTEXPR14 limb &operator[](limb_t index) noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } - FASTFLOAT_CONSTEXPR14 const limb &operator[](uint16_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &operator[](limb_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return data[index]; } // index from the end of the container - FASTFLOAT_CONSTEXPR14 const limb &rindex(uint16_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const limb &rindex(limb_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - uint16_t rindex = length - index - 1; + limb_t rindex = length - index - 1; return data[rindex]; } // set the length, without bounds checking. - FASTFLOAT_CONSTEXPR14 void set_len(uint8_t len) noexcept { length = len; } + FASTFLOAT_CONSTEXPR14 void set_len(limb_t len) noexcept { length = len; } - constexpr uint8_t len() const noexcept { return length; } + constexpr limb_t len() const noexcept { return length; } constexpr bool is_empty() const noexcept { return length == 0; } - constexpr uint8_t capacity() const noexcept { return size; } + constexpr limb_t capacity() const noexcept { return size; } // append item to vector, without bounds checking FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { @@ -99,7 +100,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { limb *ptr = data + length; std::copy_n(s.ptr, s.len(), ptr); - set_len(uint8_t(len() + s.len())); + set_len(limb_t(len() + s.len())); } // try to add items to the vector, returning if items were added @@ -116,32 +117,29 @@ template struct stackvec { // if the new size is longer than the vector, assign value to each // appended item. FASTFLOAT_CONSTEXPR20 - void resize_unchecked(uint8_t new_len, limb value) noexcept { + void resize_unchecked(limb_t new_len, limb value) noexcept { if (new_len > len()) { - uint8_t count = new_len - len(); + limb_t count = new_len - len(); limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); - set_len(new_len); - } else { - set_len(new_len); } + set_len(new_len); } // try to resize the vector, returning if the vector was resized. - FASTFLOAT_CONSTEXPR20 bool try_resize(uint8_t new_len, limb value) noexcept { + FASTFLOAT_CONSTEXPR20 bool try_resize(limb_t new_len, limb value) noexcept { if (new_len > capacity()) { return false; - } else { - resize_unchecked(new_len, value); - return true; } + resize_unchecked(new_len, value); + return true; } // check if any limbs are non-zero after the given index. // this needs to be done in reverse order, since the index // is relative to the most significant limbs. - FASTFLOAT_CONSTEXPR14 bool nonzero(uint16_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 bool nonzero(limb_t index) const noexcept { while (index < len()) { if (rindex(index) != 0) { return true; @@ -256,16 +254,15 @@ scalar_mul(limb x, limb y, limb &carry) noexcept { // add scalar value to bigint starting from offset. // used in grade school multiplication -template +template inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, - uint32_t start) noexcept { - uint8_t index = (uint8_t)start; + limb_t start) noexcept { limb carry = y; bool overflow; - while (carry != 0 && index < vec.len()) { - vec[index] = scalar_add(vec[index], carry, overflow); + while (carry != 0 && start < vec.len()) { + vec[start] = scalar_add(vec[start], carry, overflow); carry = limb(overflow); - ++index; + ++start; } if (carry != 0) { FASTFLOAT_TRY(vec.try_push(carry)); @@ -274,18 +271,18 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, } // add scalar value to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool small_add(stackvec &vec, limb y) noexcept { return small_add_from(vec, y, 0); } // multiply bigint by scalar value. -template +template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (uint8_t index = 0; index != vec.len(); ++index) { + for (limb_t index = 0; index != vec.len(); ++index) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -296,17 +293,17 @@ inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, // add bigint to bigint starting from index. // used in grade school multiplication -template +template FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, - uint8_t start) noexcept { + limb_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. if (x.len() < start || y.len() > x.len() - start) { - FASTFLOAT_TRY(x.try_resize(uint8_t(y.len() + start), 0)); + FASTFLOAT_TRY(x.try_resize(limb_t(y.len() + start), 0)); } bool carry = false; - for (uint8_t index = 0; index < y.len(); ++index) { + for (limb_t index = 0; index < y.len(); ++index) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -321,20 +318,20 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, // handle overflow if (carry) { - FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start)); + FASTFLOAT_TRY(small_add_from(x, 1, limb_t(y.len() + start))); } return true; } // add bigint to bigint. -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y) noexcept { return large_add_from(x, y, 0); } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { limb_span xs = limb_span(x.data, x.len()); stackvec z(xs); @@ -343,7 +340,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { if (y.len() != 0) { limb y0 = y[0]; FASTFLOAT_TRY(small_mul(x, y0)); - for (uint8_t index = 1; index != y.len(); ++index) { + for (limb_t index = 1; index != y.len(); ++index) { limb yi = y[index]; stackvec zi; if (yi != 0) { @@ -362,7 +359,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { } // grade-school multiplication algorithm -template +template FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { if (y.len() == 1) { FASTFLOAT_TRY(small_mul(x, y[0])); @@ -491,7 +488,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (uint8_t index = vec.len(); index > 0; --index) { + for (limb_t index = vec.len(); index != 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -506,7 +503,7 @@ struct bigint : pow5_tables<> { // shift left each limb n bits, carrying over to the new limb // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(uint16_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_bits(bigint_bits_t n) noexcept { // Internally, for each item, we shift left by n, and add the previous // right shifted limb-bits. // For example, we transform (for u8) shifted left 2, to: @@ -515,10 +512,10 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - uint16_t const shl = n; - uint16_t const shr = limb_bits - shl; + bigint_bits_t const shl = n; + bigint_bits_t const shr = limb_bits - shl; limb prev = 0; - for (uint8_t index = 0; index != vec.len(); ++index) { + for (limb_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; @@ -532,30 +529,32 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(int16_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_limbs(bigint_bits_t n) noexcept { FASTFLOAT_DEBUG_ASSERT(n != 0); if (n + vec.len() > vec.capacity()) { + // we can't shift more than the capacity of the vector. return false; - } else if (!vec.is_empty()) { - // move limbs - limb *dst = vec.data + n; - limb const *src = vec.data; - std::copy_backward(src, src + vec.len(), dst + vec.len()); - // fill in empty limbs - limb *first = vec.data; - limb *last = first + n; - ::std::fill(first, last, 0); - vec.set_len(uint8_t(n + vec.len())); - return true; - } else { + } + if (vec.is_empty()) { + // nothing to do return true; } + // move limbs + limb *dst = vec.data + n; + limb const *src = vec.data; + std::copy_backward(src, src + vec.len(), dst + vec.len()); + // fill in empty limbs + limb *first = vec.data; + limb *last = first + n; + ::std::fill(first, last, 0); + vec.set_len(limb_t(n + vec.len())); + return true; } // move the limbs left by `n` bits. - FASTFLOAT_CONSTEXPR20 bool shl(uint16_t n) noexcept { - uint16_t const rem = n % limb_bits; - uint16_t const div = n / limb_bits; + FASTFLOAT_CONSTEXPR20 bool shl(bigint_bits_t n) noexcept { + bigint_bits_t const rem = n % limb_bits; + bigint_bits_t const div = n / limb_bits; if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -566,23 +565,23 @@ struct bigint : pow5_tables<> { } // get the number of leading zeros in the bigint. - FASTFLOAT_CONSTEXPR20 uint8_t ctlz() const noexcept { + FASTFLOAT_CONSTEXPR20 limb_t ctlz() const noexcept { if (vec.is_empty()) { + // empty vector, no bits, no zeros. return 0; - } else { + } #ifdef FASTFLOAT_64BIT_LIMB - return leading_zeroes(vec.rindex(0)); + return leading_zeroes(vec.rindex(0)); #else - // no use defining a specialized leading_zeroes for a 32-bit type. - uint64_t r0 = vec.rindex(0); - return leading_zeroes(r0 << 32); + // no use defining a specialized leading_zeroes for a 32-bit type. + uint64_t r0 = vec.rindex(0); + return leading_zeroes(r0 << 32); #endif - } } // get the number of bits in the bigint. - FASTFLOAT_CONSTEXPR20 uint16_t bit_length() const noexcept { - uint8_t lz = ctlz(); + FASTFLOAT_CONSTEXPR20 bigint_bits_t bit_length() const noexcept { + limb_t lz = ctlz(); return limb_bits * vec.len() - lz; } @@ -591,22 +590,22 @@ struct bigint : pow5_tables<> { FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } // multiply as if by 2 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow2(int16_t exp) noexcept { return shl(exp); } + FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t exp) noexcept { return shl(exp); } // multiply as if by 5 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow5(int16_t exp) noexcept { + FASTFLOAT_CONSTEXPR20 bool pow5(am_pow_t exp) noexcept { // multiply by a power of 5 - uint8_t const large_length = sizeof(large_power_of_5) / sizeof(limb); + limb_t const large_length = sizeof(large_power_of_5) / sizeof(limb); limb_span const large = limb_span(large_power_of_5, large_length); while (exp >= large_step) { FASTFLOAT_TRY(large_mul(vec, large)); exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - uint8_t const small_step = 27; + limb_t const small_step = 27; limb const max_native = 7450580596923828125UL; #else - uint8_t const small_step = 13; + limb_t const small_step = 13; limb const max_native = 1220703125U; #endif while (exp >= small_step) { @@ -625,7 +624,7 @@ struct bigint : pow5_tables<> { } // multiply as if by 10 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow10(int16_t exp) noexcept { + FASTFLOAT_CONSTEXPR20 bool pow10(am_pow_t exp) noexcept { FASTFLOAT_TRY(pow5(exp)); return pow2(exp); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index a334e18d..6a794fee 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -76,7 +76,7 @@ compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { adjusted_mantissa answer; answer.mantissa = w << hilz; int32_t bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); - answer.power2 = int16_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + + answer.power2 = am_pow_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + invalid_am_bias); return answer; } @@ -143,9 +143,9 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa = product.high >> shift; - answer.power2 = int16_t(detail::power(int32_t(q)) + upperbit - lz - + answer.power2 = am_pow_t(detail::power(int32_t(q)) + upperbit - lz - binary::minimum_exponent()); - if (answer.power2 <= 0) { // we have a subnormal? + if (answer.power2 <= 0) { // we have a subnormal or very small value. // Here have that answer.power2 <= 0 so -answer.power2 >= 0 if (-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you @@ -155,6 +155,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // result should be zero return answer; } + // We have a subnormal number. We need to shift the mantissa to the right // next line is safe because -answer.power2 + 1 < 64 answer.mantissa >>= -answer.power2 + 1; // Thankfully, we can't have both "round-to-even" and subnormals because diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index d772ca13..73c2d42c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -41,8 +41,8 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t scientific_exponent(parsed_number_string_t const &num) noexcept { - uint64_t mantissa = num.mantissa; - int16_t exponent = num.exponent; + am_mant_t mantissa = num.mantissa; + am_pow_t exponent = num.exponent; while (mantissa >= 10000) { mantissa /= 10000; exponent += 4; @@ -68,11 +68,15 @@ to_extended(T const &value) noexcept { constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); adjusted_mantissa am; - int16_t bias = binary_format::mantissa_explicit_bits() - + am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); equiv_uint bits; #if FASTFLOAT_HAS_BIT_CAST - bits = std::bit_cast(value); + bits = +#if FASTFLOAT_HAS_BIT_CAST == 1 + std:: +#endif + bit_cast(value); #else ::memcpy(&bits, &value, sizeof(T)); #endif @@ -82,7 +86,7 @@ to_extended(T const &value) noexcept { am.mantissa = bits & mantissa_mask; } else { // normal - am.power2 = int16_t((bits & exponent_mask) >> + am.power2 = am_pow_t((bits & exponent_mask) >> binary_format::mantissa_explicit_bits()); am.power2 -= bias; am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; @@ -108,14 +112,14 @@ to_extended_halfway(T const &value) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, callback cb) noexcept { - int16_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; + am_pow_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; if (-am.power2 >= mantissa_shift) { // have a denormal float - int16_t shift = -am.power2 + 1; + am_pow_t shift = -am.power2 + 1; cb(am, std::min(shift, 64)); // check for round-up: if rounding-nearest carried us to the hidden bit. am.power2 = (am.mantissa < - (uint64_t(1) << binary_format::mantissa_explicit_bits())) + (am_mant_t(1) << binary_format::mantissa_explicit_bits())) ? 0 : 1; return; @@ -126,13 +130,13 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, // check for carry if (am.mantissa >= - (uint64_t(2) << binary_format::mantissa_explicit_bits())) { - am.mantissa = (uint64_t(1) << binary_format::mantissa_explicit_bits()); + (am_mant_t(2) << binary_format::mantissa_explicit_bits())) { + am.mantissa = (am_mant_t(1) << binary_format::mantissa_explicit_bits()); ++am.power2; } // check for infinite: we could have carried to an infinite power - am.mantissa &= ~(uint64_t(1) << binary_format::mantissa_explicit_bits()); + am.mantissa &= ~(am_mant_t(1) << binary_format::mantissa_explicit_bits()); if (am.power2 >= binary_format::infinite_power()) { am.power2 = binary_format::infinite_power(); am.mantissa = 0; @@ -141,11 +145,11 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_nearest_tie_even(adjusted_mantissa &am, int16_t shift, +round_nearest_tie_even(adjusted_mantissa &am, am_pow_t shift, callback cb) noexcept { - uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1; - uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1); - uint64_t truncated_bits = am.mantissa & mask; + am_mant_t const mask = (shift == 64) ? UINT64_MAX : (am_mant_t(1) << shift) - 1; + am_mant_t const halfway = (shift == 0) ? 0 : am_mant_t(1) << (shift - 1); + am_mant_t truncated_bits = am.mantissa & mask; bool is_above = truncated_bits > halfway; bool is_halfway = truncated_bits == halfway; @@ -158,11 +162,11 @@ round_nearest_tie_even(adjusted_mantissa &am, int16_t shift, am.power2 += shift; bool is_odd = (am.mantissa & 1) == 1; - am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above)); + am.mantissa += am_mant_t(cb(is_odd, is_halfway, is_above)); } fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -round_down(adjusted_mantissa &am, int16_t shift) noexcept { +round_down(adjusted_mantissa &am, am_pow_t shift) noexcept { if (shift == 64) { am.mantissa = 0; } else { @@ -223,8 +227,8 @@ is_truncated(span s) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, - uint16_t &count) noexcept { +parse_eight_digits(UC const *&p, limb &value, am_digits &counter, + am_digits &count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; counter += 8; @@ -233,8 +237,8 @@ parse_eight_digits(UC const *&p, limb &value, uint16_t &counter, template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void -parse_one_digit(UC const *&p, limb &value, uint16_t &counter, - uint16_t &count) noexcept { +parse_one_digit(UC const *&p, limb &value, am_digits &counter, + am_digits &count) noexcept { value = value * 10 + limb(*p - UC('0')); ++p; ++counter; @@ -248,7 +252,7 @@ add_native(bigint &big, limb power, limb value) noexcept { } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void -round_up_bigint(bigint &big, uint16_t &count) noexcept { +round_up_bigint(bigint &big, am_digits &count) noexcept { // need to round-up the digits, but need to avoid rounding // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); @@ -257,19 +261,19 @@ round_up_bigint(bigint &big, uint16_t &count) noexcept { // parse the significant digits into a big integer template -inline FASTFLOAT_CONSTEXPR20 uint16_t +inline FASTFLOAT_CONSTEXPR20 am_digits parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - uint16_t const max_digits = binary_format::max_digits(); - uint16_t counter = 0; - uint16_t digits = 0; + am_digits const max_digits = binary_format::max_digits(); + am_digits counter = 0; + am_digits digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - uint16_t const step = 19; + am_digits const step = 19; #else - uint16_t const step = 9; + am_digits const step = 9; #endif // process all integer digits. @@ -343,15 +347,15 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( - bigint &bigmant, adjusted_mantissa am, int16_t const exponent) noexcept { + bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(exponent)); bool truncated; am.mantissa = bigmant.hi64(truncated); - int16_t bias = binary_format::mantissa_explicit_bits() - + am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); am.power2 = bigmant.bit_length() - 64 + bias; - round(am, [truncated](adjusted_mantissa &a, int16_t shift) { + round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { @@ -370,9 +374,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( // are of the same magnitude. template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, adjusted_mantissa am, int16_t const exponent) noexcept { + bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { bigint &real_digits = bigmant; - int16_t const &real_exp = exponent; + am_pow_t const &real_exp = exponent; T b; { @@ -382,7 +386,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. round(am_b, - [](adjusted_mantissa &a, int16_t shift) { round_down(a, shift); }); + [](adjusted_mantissa &a, am_pow_t shift) { round_down(a, shift); }); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, @@ -391,11 +395,11 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( } adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); - int16_t theor_exp = theor.power2; + am_pow_t theor_exp = theor.power2; // scale real digits and theor digits to be same power. - int16_t pow2_exp = theor_exp - real_exp; - uint16_t pow5_exp = -real_exp; + am_pow_t pow2_exp = theor_exp - real_exp; + am_pow_t pow5_exp = -real_exp; if (pow5_exp != 0) { FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); } @@ -407,7 +411,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // compare digits, and use it to director rounding int ord = real_digits.compare(theor_digits); - round(am, [ord](adjusted_mantissa &a, int16_t shift) { + round(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { (void)_; // not needed, since we've done our comparison @@ -445,11 +449,11 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am.power2 -= invalid_am_bias; bigint bigmant; - int16_t const sci_exp = scientific_exponent(num); + am_pow_t const sci_exp = scientific_exponent(num); - uint16_t const digits = parse_mantissa(bigmant, num); + am_digits const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - int16_t const exponent = sci_exp + 1 - digits; + am_pow_t const exponent = sci_exp + 1 - digits; if (exponent >= 0) { return positive_digit_comp(bigmant, am, exponent); } else { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 5ed55adb..b850a4fd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,6 +33,12 @@ namespace fast_float { +// The number of digits in the mantissa. +typedef uint16_t am_digits; + +// The number of bits in the limb. +typedef uint8_t limb_t; + typedef uint8_t chars_format_t; enum class chars_format : chars_format_t; @@ -280,12 +286,13 @@ struct is_supported_char_type > { }; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // Compares two ASCII strings in a case insensitive manner. template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, - size_t length) noexcept { - for (size_t i = 0; i < length; ++i) { + uint8_t const length) noexcept { + for (uint8_t i = 0; i != length; ++i) { UC const actual = actual_mixedcase[i]; if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { return false; @@ -293,6 +300,7 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, } return true; } +#endif #ifndef FLT_EVAL_METHOD #error "FLT_EVAL_METHOD should be defined, please include cfloat." @@ -301,16 +309,16 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - uint16_t length; + am_digits length; - constexpr span(T const *_ptr, uint16_t _length) noexcept + constexpr span(T const *_ptr, am_digits _length) noexcept : ptr(_ptr), length(_length) {} constexpr span() noexcept : ptr(nullptr), length(0) {} - constexpr uint16_t len() const noexcept { return length; } + constexpr am_digits len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T &operator[](uint16_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T &operator[](am_digits index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -327,7 +335,7 @@ struct value128 { }; /* Helper C++14 constexpr generic implementation of leading_zeroes */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint8_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) noexcept { if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; @@ -352,11 +360,11 @@ leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) noexcept { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - (uint8_t)last_bit; + return 63 - (limb_t)last_bit; } /* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint8_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); @@ -369,12 +377,12 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return (uint8_t)(63 - leading_zero); + return (limb_t)(63 - leading_zero); #else - return (uint8_t)leading_zeroes_generic(input_num); + return (limb_t)leading_zeroes_generic(input_num); #endif #else - return (uint8_t)__builtin_clzll(input_num); + return (limb_t)__builtin_clzll(input_num); #endif } @@ -436,9 +444,21 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { return answer; } +// Value of the mantissa. +typedef uint64_t am_mant_t; +// Size of bits in the mantissa. +typedef uint8_t am_bits_t; + +// Power bias is signed for handling a denormal float +// or an invalid mantissa. +typedef int16_t am_pow_t; + +// Bias so we can get the real exponent with an invalid adjusted_mantissa. +constexpr static am_pow_t invalid_am_bias = -0x8000; + struct adjusted_mantissa { - uint64_t mantissa; - int16_t power2; // a negative value indicates an invalid result + am_mant_t mantissa; + am_pow_t power2; adjusted_mantissa() noexcept = default; constexpr bool operator==(adjusted_mantissa const &o) const noexcept { @@ -450,35 +470,30 @@ struct adjusted_mantissa { } }; -// Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static int32_t invalid_am_bias = -0x8000; - // used for binary_format_lookup_tables::max_mantissa -constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; +constexpr am_mant_t constant_55555 = 5 * 5 * 5 * 5 * 5; template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - // TODO add type for bit shift operations and use it. - // TODO add type for exponent operations and use it. - - static constexpr uint8_t mantissa_explicit_bits(); - static constexpr int16_t minimum_exponent(); - static constexpr int16_t infinite_power(); - static constexpr uint8_t sign_index(); - static constexpr int8_t + + static constexpr am_bits_t mantissa_explicit_bits(); + static constexpr am_pow_t minimum_exponent(); + static constexpr am_pow_t infinite_power(); + static constexpr am_bits_t sign_index(); + static constexpr am_pow_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int8_t max_exponent_fast_path(); - static constexpr int16_t max_exponent_round_to_even(); - static constexpr int16_t min_exponent_round_to_even(); + static constexpr am_pow_t max_exponent_fast_path(); + static constexpr am_pow_t max_exponent_round_to_even(); + static constexpr am_pow_t min_exponent_round_to_even(); static constexpr equiv_uint max_mantissa_fast_path(int64_t power); static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr int16_t largest_power_of_ten(); - static constexpr int16_t smallest_power_of_ten(); + static constexpr am_pow_t largest_power_of_ten(); + static constexpr am_pow_t smallest_power_of_ten(); static constexpr T exact_power_of_ten(int64_t power); - static constexpr uint16_t max_digits(); + static constexpr am_digits max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); static constexpr equiv_uint hidden_bit_mask(); @@ -568,7 +583,7 @@ constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; #endif template <> -inline constexpr int8_t binary_format::min_exponent_fast_path() { +inline constexpr am_pow_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -577,7 +592,7 @@ inline constexpr int8_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr int8_t binary_format::min_exponent_fast_path() { +inline constexpr am_pow_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -586,81 +601,76 @@ inline constexpr int8_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr uint8_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr uint8_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 23; } template <> -inline constexpr int16_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr int16_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr int16_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr int16_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -17; } -template <> inline constexpr int16_t binary_format::minimum_exponent() { +template <> inline constexpr am_pow_t binary_format::minimum_exponent() { return -1023; } -template <> inline constexpr int16_t binary_format::minimum_exponent() { +template <> inline constexpr am_pow_t binary_format::minimum_exponent() { return -127; } -template <> inline constexpr int16_t binary_format::infinite_power() { +template <> inline constexpr am_pow_t binary_format::infinite_power() { return 0x7FF; } -template <> inline constexpr int16_t binary_format::infinite_power() { +template <> inline constexpr am_pow_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -template <> inline constexpr uint8_t binary_format::sign_index() { +template <> inline constexpr am_bits_t binary_format::sign_index() { return 63; } -template <> inline constexpr uint8_t binary_format::sign_index() { +template <> inline constexpr am_bits_t binary_format::sign_index() { return 31; } #endif template <> -inline constexpr int8_t binary_format::max_exponent_fast_path() { +inline constexpr am_pow_t binary_format::max_exponent_fast_path() { return 22; } template <> -inline constexpr int8_t binary_format::max_exponent_fast_path() { +inline constexpr am_pow_t binary_format::max_exponent_fast_path() { return 10; } -template <> -inline constexpr uint64_t binary_format::max_mantissa_fast_path() { - return uint64_t(2) << mantissa_explicit_bits(); -} - -template <> -inline constexpr uint32_t binary_format::max_mantissa_fast_path() { - return uint32_t(2) << mantissa_explicit_bits(); +template +inline constexpr binary_format::equiv_uint binary_format::max_mantissa_fast_path() { + return binary_format::equiv_uint(2) << mantissa_explicit_bits(); } // credit: Jakub Jelínek @@ -728,12 +738,6 @@ binary_format::mantissa_explicit_bits() { return 10; } -template <> -inline constexpr int8_t -binary_format::max_mantissa_fast_path() { - return uint16_t(2) << mantissa_explicit_bits(); -} - template <> inline constexpr uint64_t binary_format::max_mantissa_fast_path(int64_t power) { @@ -763,37 +767,37 @@ binary_format::min_exponent_round_to_even() { } template <> -inline constexpr int16_t binary_format::minimum_exponent() { +inline constexpr am_exp_t binary_format::minimum_exponent() { return -15; } template <> -inline constexpr int16_t binary_format::infinite_power() { +inline constexpr am_exp_t binary_format::infinite_power() { return 0x1F; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN template <> -inline constexpr uint8_t binary_format::sign_index() { +inline constexpr am_bits_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr int16_t binary_format::largest_power_of_ten() { +inline constexpr am_exp_t binary_format::largest_power_of_ten() { return 4; } template <> -inline constexpr int16_t +inline constexpr am_exp_t binary_format::smallest_power_of_ten() { return -27; } template <> -inline constexpr uint8_t binary_format::max_digits() { +inline constexpr am_digits binary_format::max_digits() { return 22; } #endif // __STDCPP_FLOAT16_T__ @@ -860,13 +864,6 @@ binary_format::mantissa_explicit_bits() { return 7; } -template <> -inline constexpr binary_format::equiv_uint -binary_format::max_mantissa_fast_path() { - return binary_format::equiv_uint(2) - << mantissa_explicit_bits(); -} - template <> inline constexpr uint64_t binary_format::max_mantissa_fast_path(int64_t power) { @@ -884,24 +881,24 @@ binary_format::min_exponent_fast_path() { } template <> -inline constexpr int16_t +inline constexpr am_exp_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr int16_t +inline constexpr am_exp_t binary_format::min_exponent_round_to_even() { return -24; } template <> -inline constexpr int16_t binary_format::minimum_exponent() { +inline constexpr am_exp_t binary_format::minimum_exponent() { return -127; } template <> -inline constexpr int16_t binary_format::infinite_power() { +inline constexpr am_exp_t binary_format::infinite_power() { return 0xFF; } @@ -915,13 +912,13 @@ inline constexpr uint8_t binary_format::sign_index() { #endif template <> -inline constexpr int16_t +inline constexpr am_exp_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int16_t +inline constexpr am_exp_t binary_format::smallest_power_of_ten() { return -60; } @@ -972,30 +969,30 @@ inline constexpr float binary_format::exact_power_of_ten(int64_t power) { } template <> -inline constexpr int16_t binary_format::largest_power_of_ten() { +inline constexpr am_pow_t binary_format::largest_power_of_ten() { return 308; } template <> -inline constexpr int16_t binary_format::largest_power_of_ten() { +inline constexpr am_pow_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr int16_t binary_format::smallest_power_of_ten() { +inline constexpr am_pow_t binary_format::smallest_power_of_ten() { return -342; } template <> -inline constexpr int16_t binary_format::smallest_power_of_ten() { +inline constexpr am_pow_t binary_format::smallest_power_of_ten() { return -64; } -template <> inline constexpr uint16_t binary_format::max_digits() { +template <> inline constexpr am_digits binary_format::max_digits() { return 769; } -template <> inline constexpr uint16_t binary_format::max_digits() { +template <> inline constexpr am_digits binary_format::max_digits() { return 114; } From 0a18d6b329a7dd80914c2f789a6c5f4a2d4f9f7e Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 12 Apr 2025 17:17:04 +0300 Subject: [PATCH 085/252] # format. --- include/fast_float/ascii_number.h | 13 +++++++------ include/fast_float/decimal_to_binary.h | 4 ++-- include/fast_float/digit_comparison.h | 20 +++++++++++--------- include/fast_float/float_common.h | 19 +++++++++++-------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a2c84dd3..dab21f2e 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -334,8 +334,7 @@ parse_number_string(UC const *p, UC const *pend, // multiplication answer.mantissa = 10 * answer.mantissa + - UC(*p - - UC('0')); // might overflow, we will handle the overflow later + UC(*p - UC('0')); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; @@ -371,7 +370,8 @@ parse_number_string(UC const *p, UC const *pend, ++p; } answer.exponent = static_cast(before - p); - answer.fraction = span(before, static_cast(p - before)); + answer.fraction = + span(before, static_cast(p - before)); digit_count -= answer.exponent; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { @@ -390,9 +390,10 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part - if ((p != pend) && (chars_format_t(options.format & chars_format::scientific) && - (UC('e') == *p) || - (UC('E') == *p)) + if ((p != pend) && + (chars_format_t(options.format & chars_format::scientific) && + (UC('e') == *p) || + (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN || (chars_format_t(options.format & detail::basic_fortran_fmt) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 6a794fee..e0db653d 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -77,7 +77,7 @@ compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { answer.mantissa = w << hilz; int32_t bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); answer.power2 = am_pow_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + - invalid_am_bias); + invalid_am_bias); return answer; } @@ -144,7 +144,7 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa = product.high >> shift; answer.power2 = am_pow_t(detail::power(int32_t(q)) + upperbit - lz - - binary::minimum_exponent()); + binary::minimum_exponent()); if (answer.power2 <= 0) { // we have a subnormal or very small value. // Here have that answer.power2 <= 0 so -answer.power2 >= 0 if (-answer.power2 + 1 >= diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 73c2d42c..ba3a5bc0 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -69,14 +69,14 @@ to_extended(T const &value) noexcept { adjusted_mantissa am; am_pow_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); + binary_format::minimum_exponent(); equiv_uint bits; #if FASTFLOAT_HAS_BIT_CAST - bits = + bits = #if FASTFLOAT_HAS_BIT_CAST == 1 - std:: + std:: #endif - bit_cast(value); + bit_cast(value); #else ::memcpy(&bits, &value, sizeof(T)); #endif @@ -87,7 +87,7 @@ to_extended(T const &value) noexcept { } else { // normal am.power2 = am_pow_t((bits & exponent_mask) >> - binary_format::mantissa_explicit_bits()); + binary_format::mantissa_explicit_bits()); am.power2 -= bias; am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; } @@ -147,7 +147,8 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round_nearest_tie_even(adjusted_mantissa &am, am_pow_t shift, callback cb) noexcept { - am_mant_t const mask = (shift == 64) ? UINT64_MAX : (am_mant_t(1) << shift) - 1; + am_mant_t const mask = + (shift == 64) ? UINT64_MAX : (am_mant_t(1) << shift) - 1; am_mant_t const halfway = (shift == 0) ? 0 : am_mant_t(1) << (shift - 1); am_mant_t truncated_bits = am.mantissa & mask; bool is_above = truncated_bits > halfway; @@ -352,7 +353,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( bool truncated; am.mantissa = bigmant.hi64(truncated); am_pow_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); + binary_format::minimum_exponent(); am.power2 = bigmant.bit_length() - 64 + bias; round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { @@ -385,8 +386,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( adjusted_mantissa am_b = am; // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. - round(am_b, - [](adjusted_mantissa &a, am_pow_t shift) { round_down(a, shift); }); + round(am_b, [](adjusted_mantissa &a, am_pow_t shift) { + round_down(a, shift); + }); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index b850a4fd..e4521297 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -408,9 +408,8 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // slow emulation routine for 32-bit #if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, - uint64_t cd, - uint64_t *hi) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +_umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ @@ -449,7 +448,7 @@ typedef uint64_t am_mant_t; // Size of bits in the mantissa. typedef uint8_t am_bits_t; -// Power bias is signed for handling a denormal float +// Power bias is signed for handling a denormal float // or an invalid mantissa. typedef int16_t am_pow_t; @@ -630,7 +629,8 @@ inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -17; } -template <> inline constexpr am_pow_t binary_format::minimum_exponent() { +template <> +inline constexpr am_pow_t binary_format::minimum_exponent() { return -1023; } @@ -669,7 +669,8 @@ inline constexpr am_pow_t binary_format::max_exponent_fast_path() { } template -inline constexpr binary_format::equiv_uint binary_format::max_mantissa_fast_path() { +inline constexpr binary_format::equiv_uint +binary_format::max_mantissa_fast_path() { return binary_format::equiv_uint(2) << mantissa_explicit_bits(); } @@ -786,7 +787,8 @@ inline constexpr am_bits_t binary_format::sign_index() { #endif template <> -inline constexpr am_exp_t binary_format::largest_power_of_ten() { +inline constexpr am_exp_t +binary_format::largest_power_of_ten() { return 4; } @@ -1197,7 +1199,8 @@ fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) noexcept { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t max_digits_u64(uint8_t base) noexcept { +fastfloat_really_inline constexpr uint8_t +max_digits_u64(uint8_t base) noexcept { return int_luts<>::maxdigits_u64[base - 2]; } From 17ffdffdd9856faccbb0c2d64c8d97759fe9cf72 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 12 Apr 2025 19:16:25 +0300 Subject: [PATCH 086/252] * additional types cleanup for speedup and reduce cache pressure. --- include/fast_float/decimal_to_binary.h | 12 ++++++------ include/fast_float/float_common.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index e0db653d..847654d2 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); @@ -171,7 +171,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // subnormal, but we can only know this after rounding. // So we only declare a subnormal if we are smaller than the threshold. answer.power2 = - (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) + (answer.mantissa < (am_mant_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1; return answer; @@ -189,18 +189,18 @@ compute_float(int64_t q, uint64_t w) noexcept { // ... we dropped out only zeroes. But if this happened, then we can go // back!!! if ((answer.mantissa << shift) == product.high) { - answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up + answer.mantissa &= ~am_mant_t(1); // flip it so that we do not round up } } answer.mantissa += (answer.mantissa & 1); // round up answer.mantissa >>= 1; - if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { - answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); + if (answer.mantissa >= (am_mant_t(2) << binary::mantissa_explicit_bits())) { + answer.mantissa = (am_mant_t(1) << binary::mantissa_explicit_bits()); ++answer.power2; // undo previous addition } - answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); + answer.mantissa &= ~(am_mant_t(1) << binary::mantissa_explicit_bits()); if (answer.power2 >= binary::infinite_power()) { // infinity answer.power2 = binary::infinite_power(); answer.mantissa = 0; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index e4521297..90eecc20 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1058,7 +1058,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN template struct space_lut { - static constexpr bool value[] = { + static constexpr uint8_t value[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1074,7 +1074,7 @@ template struct space_lut { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr bool space_lut::value[]; +template constexpr uint8_t space_lut::value[]; #endif From c99930b2a057438ea41e93e3118c335237e32665 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 30 Apr 2025 00:56:02 +0300 Subject: [PATCH 087/252] added additional macro FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED for performance improve. --- include/fast_float/parse_number.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 1b964648..3d4e3d85 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -75,6 +75,7 @@ from_chars_result_t } #endif +#ifndef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED /** * Returns true if the floating-pointing rounding mode is to 'nearest'. * It is the default on most system. This function is meant to be inexpensive. @@ -139,6 +140,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { #pragma GCC diagnostic pop #endif } +#endif } // namespace detail @@ -226,7 +228,9 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { // We could check it first (before the previous branch), but // there might be performance advantages at having the check // be last. +#ifndef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { +#endif // We have that fegetround() == FE_TONEAREST. // Next is Clinger's fast path. if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { @@ -243,6 +247,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { #endif return answer; } +#ifndef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED } else { // We do not have that fegetround() == FE_TONEAREST. // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's @@ -271,6 +276,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { return answer; } } +#endif } adjusted_mantissa am = compute_float>(pns.exponent, pns.mantissa); From 7bd3c54864206c0265548dfd44524803ad0572d7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 30 Apr 2025 01:09:29 +0300 Subject: [PATCH 088/252] benchmarks are updated. --- benchmarks/benchmark.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 0dd85e06..3dd0a39d 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,5 +1,6 @@ // #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +// #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS From 4e230e8d24fe1bde1fb99feeb4f6e5562a0e45b7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 30 Apr 2025 01:09:29 +0300 Subject: [PATCH 089/252] benchmarks are updated. --- benchmarks/benchmark.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 0dd85e06..0a740427 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,5 +1,6 @@ -// #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS @@ -226,6 +227,10 @@ int main(int argc, char **argv) { std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled" << std::endl; #endif +#ifdef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED + std::cout << "# FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED is enabled" + << std::endl; +#endif #ifdef USING_COUNTERS if (collector.has_events()) { std::cout << "# Using hardware counters" << std::endl; From 58cb366e7e2643edc427b7cb898df3d5d7ce4d09 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 18:21:35 +0300 Subject: [PATCH 090/252] Finally: after type refactoring is done give compiler opportunity to select best type for performance. --- include/fast_float/float_common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 90eecc20..d2a99c06 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -34,12 +34,12 @@ namespace fast_float { // The number of digits in the mantissa. -typedef uint16_t am_digits; +typedef uint_fast16_t am_digits; // The number of bits in the limb. -typedef uint8_t limb_t; +typedef uint_fast8_t limb_t; -typedef uint8_t chars_format_t; +typedef uint_fast8_t chars_format_t; enum class chars_format : chars_format_t; From 87214919417535ed8582bea8d9020cdefadecf0e Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 18:21:35 +0300 Subject: [PATCH 091/252] Finally: after type refactoring is done give compiler opportunity to select best type for performance. --- include/fast_float/bigint.h | 4 ++-- include/fast_float/digit_comparison.h | 4 ++-- include/fast_float/float_common.h | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 489ad116..f37e2a9f 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -32,7 +32,7 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -typedef uint16_t bigint_bits_t; +typedef uint_fast16_t bigint_bits_t; constexpr bigint_bits_t bigint_bits = 4000; constexpr limb_t bigint_limbs = bigint_bits / limb_bits; @@ -41,7 +41,7 @@ constexpr limb_t bigint_limbs = bigint_bits / limb_bits; template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint8_t length{0}; + uint_fast8_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index ba3a5bc0..f3f5e0ce 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -39,7 +39,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, // 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. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int16_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int_fast16_t scientific_exponent(parsed_number_string_t const &num) noexcept { am_mant_t mantissa = num.mantissa; am_pow_t exponent = num.exponent; @@ -116,7 +116,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, if (-am.power2 >= mantissa_shift) { // have a denormal float am_pow_t shift = -am.power2 + 1; - cb(am, std::min(shift, 64)); + cb(am, std::min(shift, 64)); // check for round-up: if rounding-nearest carried us to the hidden bit. am.power2 = (am.mantissa < (am_mant_t(1) << binary_format::mantissa_explicit_bits())) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 90eecc20..a1c2ffff 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -34,12 +34,12 @@ namespace fast_float { // The number of digits in the mantissa. -typedef uint16_t am_digits; +typedef uint_fast16_t am_digits; // The number of bits in the limb. -typedef uint8_t limb_t; +typedef uint_fast8_t limb_t; -typedef uint8_t chars_format_t; +typedef uint_fast8_t chars_format_t; enum class chars_format : chars_format_t; @@ -444,13 +444,13 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { } // Value of the mantissa. -typedef uint64_t am_mant_t; +typedef uint_fast64_t am_mant_t; // Size of bits in the mantissa. -typedef uint8_t am_bits_t; +typedef uint_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int16_t am_pow_t; +typedef int_fast16_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From 103f22056b0a9fc93bbc8a85ae787fcdb6bb95fa Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 19:07:55 +0300 Subject: [PATCH 092/252] Final functions call optimization. --- include/fast_float/ascii_number.h | 12 ++++++------ include/fast_float/decimal_to_binary.h | 2 +- include/fast_float/digit_comparison.h | 2 +- include/fast_float/fast_float.h | 2 +- include/fast_float/float_common.h | 16 ++++++++-------- include/fast_float/parse_number.h | 12 ++++++------ 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index dab21f2e..fc5b4aaa 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -50,8 +50,8 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t read8_to_u64(UC const *chars) { if (cpp20_and_in_constexpr() || !std::is_same::value) { uint64_t val = 0; - for (uint8_t i = 0; i != 8; ++i) { - val |= uint64_t(uint8_t(*chars)) << (i * 8); + for (uint_fast8_t i = 0; i != 8; ++i) { + val |= uint64_t(uint_fast8_t(*chars)) << (i * 8); ++chars; } return val; @@ -293,7 +293,7 @@ report_parse_error(UC const *p, parse_error error) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. @@ -507,7 +507,7 @@ parse_number_string(UC const *p, UC const *pend, template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_int_string(UC const *p, UC const *pend, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { from_chars_result_t answer; @@ -549,7 +549,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { - uint8_t const digit = ch_to_digit(*p); + uint_fast8_t const digit = ch_to_digit(*p); if (digit >= options.base) { break; } @@ -574,7 +574,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, answer.ptr = p; // check u64 overflow - uint8_t const max_digits = max_digits_u64(options.base); + uint_fast8_t const max_digits = max_digits_u64(options.base); if (digit_count > max_digits) { answer.ec = std::errc::result_out_of_range; return answer; diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 847654d2..d84e7167 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index f3f5e0ce..9d922014 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -116,7 +116,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, if (-am.power2 >= mantissa_shift) { // have a denormal float am_pow_t shift = -am.power2 + 1; - cb(am, std::min(shift, 64)); + cb(am, std::min(shift, 64)); // check for round-up: if rounding-nearest carried us to the hidden bit. am.power2 = (am.mantissa < (am_mant_t(1) << binary_format::mantissa_explicit_bits())) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 4c05c2dc..4ca1a0ae 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -43,7 +43,7 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept; + parse_options_t const &options) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index a1c2ffff..91b2205e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -89,7 +89,7 @@ template struct parse_options_t { /** The character used as decimal point */ UC const decimal_point; /** The base used for integers */ - uint8_t const base; /* only allowed from 2 to 36 */ + uint_fast8_t const base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; @@ -460,11 +460,11 @@ struct adjusted_mantissa { am_pow_t power2; adjusted_mantissa() noexcept = default; - 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; } - 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; } }; @@ -1039,7 +1039,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool const negative, #endif - adjusted_mantissa const &am, T &value) noexcept { + adjusted_mantissa const am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) @@ -1195,18 +1195,18 @@ template constexpr uint64_t int_luts::min_safe_u64[]; #endif template -fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) noexcept { +fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { return int_luts<>::chdigit[static_cast(c)]; } -fastfloat_really_inline constexpr uint8_t -max_digits_u64(uint8_t base) noexcept { +fastfloat_really_inline constexpr uint_fast8_t +max_digits_u64(uint_fast8_t base) noexcept { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint8_t base) noexcept { +fastfloat_really_inline constexpr uint64_t min_safe_u64(uint_fast8_t base) noexcept { return int_luts<>::min_safe_u64[base - 2]; } diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 3d4e3d85..6e56b95d 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -148,7 +148,7 @@ template struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { return from_chars_advanced(first, last, value, options); } }; @@ -307,7 +307,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -371,7 +371,7 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); @@ -407,7 +407,7 @@ template <> struct from_chars_advanced_caller<1> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { return from_chars_float_advanced(first, last, value, options); } }; @@ -416,7 +416,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { return from_chars_int_advanced(first, last, value, options); } }; @@ -424,7 +424,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const options) noexcept { + parse_options_t const &options) noexcept { return from_chars_advanced_caller< size_t(is_supported_float_type::value) + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, From 5356317356f5ef0db3e1311ce51220af838b60ab Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 19:44:30 +0300 Subject: [PATCH 093/252] Fix compilation for older standards --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 91b2205e..e3203513 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -669,7 +669,7 @@ inline constexpr am_pow_t binary_format::max_exponent_fast_path() { } template -inline constexpr binary_format::equiv_uint +inline constexpr typename binary_format::equiv_uint binary_format::max_mantissa_fast_path() { return binary_format::equiv_uint(2) << mantissa_explicit_bits(); } From 0ba4e20bc489fb59d11b31e2a89a0d711a3550c0 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 19:49:53 +0300 Subject: [PATCH 094/252] lint --- include/fast_float/float_common.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index e3203513..048aed5c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1206,7 +1206,8 @@ max_digits_u64(uint_fast8_t base) noexcept { // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t min_safe_u64(uint_fast8_t base) noexcept { +fastfloat_really_inline constexpr uint64_t +min_safe_u64(uint_fast8_t base) noexcept { return int_luts<>::min_safe_u64[base - 2]; } From 1febc3a070d77ce3eecd38c2d42e80506037596a Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 20:19:46 +0300 Subject: [PATCH 095/252] Fix compilation for older standards --- benchmarks/benchmark.cpp | 3 ++- include/fast_float/float_common.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index eaa7d6ca..048df8ff 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -216,7 +216,8 @@ void fileload(std::string filename) { line.erase(0, 1); } #endif - volume += lines.emplace_back(line).size(); + lines.emplace_back(line); + volume += line.size(); } std::cout << "# read " << lines.size() << " lines " << std::endl; process(lines, volume); diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 048aed5c..bd952ee9 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -577,7 +577,7 @@ template constexpr float binary_format_lookup_tables::powers_of_ten[]; template -constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; +constexpr uint32_t binary_format_lookup_tables::max_mantissa[]; #endif From a8c5bd9a3885f26b4b713453c1020c49e379989e Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 5 May 2025 20:24:16 +0300 Subject: [PATCH 096/252] warning fix. --- include/fast_float/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index f37e2a9f..cb41d91b 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -298,7 +298,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, limb_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. - if (x.len() < start || y.len() > x.len() - start) { + if (x.len() < start || y.len() > limb_t(x.len() - start)) { FASTFLOAT_TRY(x.try_resize(limb_t(y.len() + start), 0)); } From 9049a1a51109132786d6b3a3d10d63e5025de34b Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 14:26:20 +0300 Subject: [PATCH 097/252] clang-format. --- benchmarks/apple_arm_events.h | 3 +-- format.cmd | 7 +++++++ tests/random_string.cpp | 2 +- tests/short_random_string.cpp | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 format.cmd diff --git a/benchmarks/apple_arm_events.h b/benchmarks/apple_arm_events.h index f127d14d..74d233c5 100644 --- a/benchmarks/apple_arm_events.h +++ b/benchmarks/apple_arm_events.h @@ -618,8 +618,7 @@ typedef struct { } lib_symbol; #define lib_nelems(x) (sizeof(x) / sizeof((x)[0])) -#define lib_symbol_def(name) \ - { #name, (void **)&name } +#define lib_symbol_def(name) {#name, (void **)&name} static const lib_symbol lib_symbols_kperf[] = { lib_symbol_def(kpc_pmu_version), diff --git a/format.cmd b/format.cmd new file mode 100644 index 00000000..9b9af7f4 --- /dev/null +++ b/format.cmd @@ -0,0 +1,7 @@ +@echo off +echo Formatting with config... +for /R ".\" %%f in (*.cpp, *.h, *.c, *.hpp) do ( + echo Formatting "%%f" + clang-format -i -style=file "%%f" +) +echo Done! \ No newline at end of file diff --git a/tests/random_string.cpp b/tests/random_string.cpp index 940cd7a9..cb5b071f 100644 --- a/tests/random_string.cpp +++ b/tests/random_string.cpp @@ -54,7 +54,7 @@ float cygwin_strtof_l(char const *start, char **end) { class RandomEngine { public: RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; + RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) {}; uint64_t next() { // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h diff --git a/tests/short_random_string.cpp b/tests/short_random_string.cpp index 9008bf3a..f47509d2 100644 --- a/tests/short_random_string.cpp +++ b/tests/short_random_string.cpp @@ -54,7 +54,7 @@ float cygwin_strtof_l(char const *start, char **end) { class RandomEngine { public: RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; + RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) {}; uint64_t next() { // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h From c94d3a048c2911c42ead222a9f9990d4c4305cb6 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 14:32:53 +0300 Subject: [PATCH 098/252] clang-format --- format.cmd | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/format.cmd b/format.cmd index 9b9af7f4..34d891c2 100644 --- a/format.cmd +++ b/format.cmd @@ -1,7 +1,25 @@ @echo off -echo Formatting with config... +setlocal enabledelayedexpansion + +echo Searching for clang-format... +where clang-format >nul 2>&1 +if %errorlevel% neq 0 ( + echo Error: clang-format not found in PATH. Install LLVM or add it to PATH. + exit /b 1 +) + +echo Checking for .clang-format... +if not exist ".clang-format" ( + echo Error: .clang-format config file not found in the current directory. + exit /b 1 +) + +echo Formatting files with .clang-format... +set count=0 for /R ".\" %%f in (*.cpp, *.h, *.c, *.hpp) do ( - echo Formatting "%%f" - clang-format -i -style=file "%%f" + echo Formatting "%%f" + clang-format -i -style=file "%%f" + set /a count+=1 ) -echo Done! \ No newline at end of file + +echo Done. Proccesed !count! files. \ No newline at end of file From b2ea7bcaab624988f8f7854de19a8801848579e1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 14:42:16 +0300 Subject: [PATCH 099/252] clang-format --- format.cmd | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/format.cmd b/format.cmd index 34d891c2..cc0d283f 100644 --- a/format.cmd +++ b/format.cmd @@ -17,9 +17,12 @@ if not exist ".clang-format" ( echo Formatting files with .clang-format... set count=0 for /R ".\" %%f in (*.cpp, *.h, *.c, *.hpp) do ( - echo Formatting "%%f" - clang-format -i -style=file "%%f" - set /a count+=1 + echo "%%f" | findstr /i "\\build\\ \\.vs\\ \\.git\\ \\.github\\" >nul + if !errorlevel! equ 1 ( + echo Formatting "%%f" + clang-format -i -style=file "%%f" + set /a count+=1 + ) ) -echo Done. Proccesed !count! files. \ No newline at end of file +echo Done. Processed !count! files. \ No newline at end of file From afbb803aa4cc51d5e801973d296237b14cf4b4fe Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 16:53:30 +0300 Subject: [PATCH 100/252] compilation fixes for std::bfloat16_t and std::float16_t. Sorry for this, my compilers don't supports it. additional type usage fixes and constexpr. --- include/fast_float/decimal_to_binary.h | 21 ++--- include/fast_float/digit_comparison.h | 11 +-- include/fast_float/float_common.h | 101 +++++++++++++------------ 3 files changed, 68 insertions(+), 65 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index d84e7167..8897420c 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { int const index = 2 * int(q - powers::smallest_power_of_five); @@ -62,7 +62,7 @@ namespace detail { * where * p = log(5**-q)/log(2) = -q * log(5)/log(2) */ -constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { +constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { return (((152170 + 65536) * q) >> 16) + 63; } } // namespace detail @@ -72,11 +72,12 @@ constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { - int32_t hilz = int32_t(w >> 63) ^ 1; + am_pow_t hilz = uint64_t(w >> 63) ^ 1; adjusted_mantissa answer; answer.mantissa = w << hilz; - int32_t bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); - answer.power2 = am_pow_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + + constexpr am_pow_t bias = + binary::mantissa_explicit_bits() - binary::minimum_exponent(); + answer.power2 = am_pow_t(detail::power(am_pow_t(q)) + bias - hilz - lz - 62 + invalid_am_bias); return answer; } @@ -86,7 +87,7 @@ compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept { - int lz = leading_zeroes(w); + limb_t lz = leading_zeroes(w); w <<= lz; value128 product = compute_product_approximation(q, w); @@ -118,7 +119,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. - int lz = leading_zeroes(w); + limb_t lz = leading_zeroes(w); w <<= lz; // The required precision is binary::mantissa_explicit_bits() + 3 because @@ -138,12 +139,12 @@ compute_float(int64_t q, uint64_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - int upperbit = int(product.high >> 63); - int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + limb_t upperbit = limb_t(product.high >> 63); + limb_t shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; answer.mantissa = product.high >> shift; - answer.power2 = am_pow_t(detail::power(int32_t(q)) + upperbit - lz - + answer.power2 = am_pow_t(detail::power(am_pow_t(q)) + upperbit - lz - binary::minimum_exponent()); if (answer.power2 <= 0) { // we have a subnormal or very small value. // Here have that answer.power2 <= 0 so -answer.power2 >= 0 diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 9d922014..b6983d8a 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -68,8 +68,8 @@ to_extended(T const &value) noexcept { constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); adjusted_mantissa am; - am_pow_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); + constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); equiv_uint bits; #if FASTFLOAT_HAS_BIT_CAST bits = @@ -112,7 +112,8 @@ to_extended_halfway(T const &value) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, callback cb) noexcept { - am_pow_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; + constexpr am_pow_t mantissa_shift = + 64 - binary_format::mantissa_explicit_bits() - 1; if (-am.power2 >= mantissa_shift) { // have a denormal float am_pow_t shift = -am.power2 + 1; @@ -352,8 +353,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( FASTFLOAT_ASSERT(bigmant.pow10(exponent)); bool truncated; am.mantissa = bigmant.hi64(truncated); - am_pow_t bias = binary_format::mantissa_explicit_bits() - - binary_format::minimum_exponent(); + constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); am.power2 = bigmant.bit_length() - 64 + bias; round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index bd952ee9..e161b6e0 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -445,8 +445,8 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { // Value of the mantissa. typedef uint_fast64_t am_mant_t; -// Size of bits in the mantissa. -typedef uint_fast8_t am_bits_t; +// Size of bits in the mantissa and path and roundings shifts +typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. @@ -481,17 +481,17 @@ template struct binary_format : binary_format_lookup_tables { static constexpr am_pow_t minimum_exponent(); static constexpr am_pow_t infinite_power(); static constexpr am_bits_t sign_index(); - static constexpr am_pow_t + static constexpr am_bits_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static constexpr am_pow_t max_exponent_fast_path(); - static constexpr am_pow_t max_exponent_round_to_even(); - static constexpr am_pow_t min_exponent_round_to_even(); - static constexpr equiv_uint max_mantissa_fast_path(int64_t power); + static constexpr am_bits_t max_exponent_fast_path(); + static constexpr am_bits_t max_exponent_round_to_even(); + static constexpr am_bits_t min_exponent_round_to_even(); + static constexpr equiv_uint max_mantissa_fast_path(am_pow_t power); static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_pow_t largest_power_of_ten(); static constexpr am_pow_t smallest_power_of_ten(); - static constexpr T exact_power_of_ten(int64_t power); + static constexpr T exact_power_of_ten(am_pow_t power); static constexpr am_digits max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); @@ -582,7 +582,7 @@ constexpr uint32_t binary_format_lookup_tables::max_mantissa[]; #endif template <> -inline constexpr am_pow_t binary_format::min_exponent_fast_path() { +inline constexpr am_bits_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -591,7 +591,7 @@ inline constexpr am_pow_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_pow_t binary_format::min_exponent_fast_path() { +inline constexpr am_bits_t binary_format::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; #else @@ -610,22 +610,22 @@ inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { } template <> -inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { +inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { +inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { +inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { +inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { return -17; } @@ -659,12 +659,12 @@ template <> inline constexpr am_bits_t binary_format::sign_index() { #endif template <> -inline constexpr am_pow_t binary_format::max_exponent_fast_path() { +inline constexpr am_bits_t binary_format::max_exponent_fast_path() { return 22; } template <> -inline constexpr am_pow_t binary_format::max_exponent_fast_path() { +inline constexpr am_bits_t binary_format::max_exponent_fast_path() { return 10; } @@ -704,7 +704,7 @@ constexpr uint16_t template <> inline constexpr std::float16_t -binary_format::exact_power_of_ten(int64_t power) { +binary_format::exact_power_of_ten(am_pow_t power) { // Work around clang bug https://godbolt.org/z/zedh7rrhc return (void)powers_of_ten[0], powers_of_ten[power]; } @@ -728,52 +728,52 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr int8_t +inline constexpr am_bits_t binary_format::max_exponent_fast_path() { return 4; } template <> -inline constexpr uint8_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 10; } template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { +inline constexpr binary_format::equiv_uint +binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that - // power >= 0 && power <= 4 + FASTFLOAT_ASSUME(power >= 0 && power <= 4); // // Work around clang bug https://godbolt.org/z/zedh7rrhc return (void)max_mantissa[0], max_mantissa[power]; } template <> -inline constexpr int8_t +inline constexpr am_bits_t binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr int16_t +inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { return 5; } template <> -inline constexpr int16_t +inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { return -22; } template <> -inline constexpr am_exp_t binary_format::minimum_exponent() { +inline constexpr am_pow_t binary_format::minimum_exponent() { return -15; } template <> -inline constexpr am_exp_t binary_format::infinite_power() { +inline constexpr am_pow_t binary_format::infinite_power() { return 0x1F; } @@ -787,13 +787,13 @@ inline constexpr am_bits_t binary_format::sign_index() { #endif template <> -inline constexpr am_exp_t +inline constexpr am_pow_t binary_format::largest_power_of_ten() { return 4; } template <> -inline constexpr am_exp_t +inline constexpr am_pow_t binary_format::smallest_power_of_ten() { return -27; } @@ -812,7 +812,7 @@ template struct binary_format_lookup_tables { // Largest integer value v so that (5**index * v) <= 1<<8. // 0x100 == 1<<8 - static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5), + static constexpr uint16_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5), 0x100 / (5 * 5 * 5), 0x100 / (5 * 5 * 5 * 5)}; }; @@ -831,13 +831,13 @@ constexpr uint64_t template <> inline constexpr std::bfloat16_t -binary_format::exact_power_of_ten(int64_t power) { +binary_format::exact_power_of_ten(am_pow_t power) { // Work around clang bug https://godbolt.org/z/zedh7rrhc return (void)powers_of_ten[0], powers_of_ten[power]; } template <> -inline constexpr int8_t +inline constexpr am_bits_t binary_format::max_exponent_fast_path() { return 3; } @@ -861,66 +861,66 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr uint8_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 7; } template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { +inline constexpr binary_format::equiv_uint +binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that - // power >= 0 && power <= 3 + FASTFLOAT_ASSUME(power >= 0 && power <= 3); // // Work around clang bug https://godbolt.org/z/zedh7rrhc return (void)max_mantissa[0], max_mantissa[power]; } template <> -inline constexpr int8_t +inline constexpr am_bits_t binary_format::min_exponent_fast_path() { return 0; } template <> -inline constexpr am_exp_t +inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr am_exp_t +inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { return -24; } template <> -inline constexpr am_exp_t binary_format::minimum_exponent() { +inline constexpr am_pow_t binary_format::minimum_exponent() { return -127; } template <> -inline constexpr am_exp_t binary_format::infinite_power() { +inline constexpr am_pow_t binary_format::infinite_power() { return 0xFF; } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN template <> -inline constexpr uint8_t binary_format::sign_index() { +inline constexpr am_bits_t binary_format::sign_index() { return 15; } #endif template <> -inline constexpr am_exp_t +inline constexpr am_pow_t binary_format::largest_power_of_ten() { return 38; } template <> -inline constexpr am_exp_t +inline constexpr am_pow_t binary_format::smallest_power_of_ten() { return -60; } @@ -932,8 +932,8 @@ inline constexpr uint16_t binary_format::max_digits() { #endif // __STDCPP_BFLOAT16_T__ template <> -inline constexpr uint64_t -binary_format::max_mantissa_fast_path(int64_t power) { +inline constexpr binary_format::equiv_uint +binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 22); // @@ -942,8 +942,8 @@ binary_format::max_mantissa_fast_path(int64_t power) { } template <> -inline constexpr uint32_t -binary_format::max_mantissa_fast_path(int64_t power) { +inline constexpr binary_format::equiv_uint +binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 10); // @@ -953,7 +953,7 @@ binary_format::max_mantissa_fast_path(int64_t power) { template <> inline constexpr double -binary_format::exact_power_of_ten(int64_t power) { +binary_format::exact_power_of_ten(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 22); // @@ -962,7 +962,8 @@ binary_format::exact_power_of_ten(int64_t power) { } template <> -inline constexpr float binary_format::exact_power_of_ten(int64_t power) { +inline constexpr float +binary_format::exact_power_of_ten(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 10); // From d5c05e51af293ca2f16666861f5d27493f4cc1f0 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 17:44:31 +0300 Subject: [PATCH 101/252] additional type usage fixes and constexpr. --- include/fast_float/digit_comparison.h | 4 ++-- include/fast_float/float_common.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index b6983d8a..be337717 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -39,7 +39,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, // 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. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int_fast16_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_pow_t scientific_exponent(parsed_number_string_t const &num) noexcept { am_mant_t mantissa = num.mantissa; am_pow_t exponent = num.exponent; @@ -268,7 +268,7 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 // scalar value (9 or 19 digits) for each step. - am_digits const max_digits = binary_format::max_digits(); + constexpr am_digits max_digits = binary_format::max_digits(); am_digits counter = 0; am_digits digits = 0; limb value = 0; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index e161b6e0..c0bf8a1e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -336,7 +336,7 @@ struct value128 { /* Helper C++14 constexpr generic implementation of leading_zeroes */ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t -leading_zeroes_generic(uint64_t input_num, uint64_t last_bit = 0) noexcept { +leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; last_bit |= 32; From 99d769db5bbb0c5f65c0b4511f47640c8841dd55 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 18:15:43 +0300 Subject: [PATCH 102/252] clang-format --- benchmarks/apple_arm_events.h | 3 ++- include/fast_float/float_common.h | 11 ++++++----- tests/random_string.cpp | 2 +- tests/short_random_string.cpp | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/benchmarks/apple_arm_events.h b/benchmarks/apple_arm_events.h index 74d233c5..f127d14d 100644 --- a/benchmarks/apple_arm_events.h +++ b/benchmarks/apple_arm_events.h @@ -618,7 +618,8 @@ typedef struct { } lib_symbol; #define lib_nelems(x) (sizeof(x) / sizeof((x)[0])) -#define lib_symbol_def(name) {#name, (void **)&name} +#define lib_symbol_def(name) \ + { #name, (void **)&name } static const lib_symbol lib_symbols_kperf[] = { lib_symbol_def(kpc_pmu_version), diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index c0bf8a1e..9afdc80b 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -78,14 +78,15 @@ template struct parse_options_t { FASTFLOAT_CONSTEXPR20 explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), chars_format_t const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) { + : format(fmt), decimal_point(dot), + base(b){ #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - // static_assert(b >= 2 && b <= 36); + // static_assert(b >= 2 && b <= 36); #endif - } + } - /** Which number formats are accepted */ - chars_format const format; + /** Which number formats are accepted */ + chars_format const format; /** The character used as decimal point */ UC const decimal_point; /** The base used for integers */ diff --git a/tests/random_string.cpp b/tests/random_string.cpp index cb5b071f..940cd7a9 100644 --- a/tests/random_string.cpp +++ b/tests/random_string.cpp @@ -54,7 +54,7 @@ float cygwin_strtof_l(char const *start, char **end) { class RandomEngine { public: RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) {}; + RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; uint64_t next() { // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h diff --git a/tests/short_random_string.cpp b/tests/short_random_string.cpp index f47509d2..9008bf3a 100644 --- a/tests/short_random_string.cpp +++ b/tests/short_random_string.cpp @@ -54,7 +54,7 @@ float cygwin_strtof_l(char const *start, char **end) { class RandomEngine { public: RandomEngine() = delete; - RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) {}; + RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; uint64_t next() { // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h From 66363ccb37dfbe03d6f093b6a92caf86666c2f24 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 19:16:05 +0300 Subject: [PATCH 103/252] try to fix stupid shit in the tests, meh. --- .github/workflows/msys2.yml | 6 ++++++ .github/workflows/vs17-ci.yml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 86be5244..95b98bc6 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -43,3 +43,9 @@ jobs: run: cmake --build build - name: Run basic tests run: cd build && ctest --output-on-failure -R basictest + - name: Install dependencies + run: | + pacman -Syu --noconfirm + pacman -S --noconfirm base-devel cmake + - name: Verify CMake version + run: cmake --version diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 0fe0bbdd..81431ad8 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -11,7 +11,7 @@ jobs: matrix: include: - {gen: Visual Studio 17 2022, arch: Win32, cfg: Release} - #- {gen: Visual Studio 17 2022, arch: Win32, cfg: Debug} + - {gen: Visual Studio 17 2022, arch: Win32, cfg: Debug} - {gen: Visual Studio 17 2022, arch: x64, cfg: Release} - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: From ba3f7a68a33137a4c4d82d1a57aae2060bfc4939 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 19:35:59 +0300 Subject: [PATCH 104/252] . --- .github/workflows/msys2.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 95b98bc6..86be5244 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -43,9 +43,3 @@ jobs: run: cmake --build build - name: Run basic tests run: cd build && ctest --output-on-failure -R basictest - - name: Install dependencies - run: | - pacman -Syu --noconfirm - pacman -S --noconfirm base-devel cmake - - name: Verify CMake version - run: cmake --version From f2befa5876b264d55af7065a76c6956a78f71a37 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 19:43:08 +0300 Subject: [PATCH 105/252] . --- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index fca8ab7d..3f3d323d 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -28,7 +28,7 @@ jobs: with: update: true msystem: ${{ matrix.msystem }} - install: ${{ matrix.install }} + install: ${{ matrix.install }} cmake - name: Prepare build dir run: mkdir build - name: Configure diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 86be5244..dfb6764f 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -34,7 +34,7 @@ jobs: with: update: true msystem: ${{ matrix.msystem }} - install: ${{ matrix.install }} + install: ${{ matrix.install }} cmake - name: Prepare build dir run: mkdir build - name: Configure From e5f189754faa21e055e4b0a024c30dbe2579c0d6 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 21:05:05 +0300 Subject: [PATCH 106/252] compilation fixes. --- include/fast_float/float_common.h | 17 +++++++-------- tests/basictest.cpp | 27 ++++++++++++------------ tests/example_comma_test.cpp | 4 ++-- tests/fortran.cpp | 33 +++++++++++++---------------- tests/json_fmt.cpp | 35 ++++++++++++++----------------- 5 files changed, 53 insertions(+), 63 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 9afdc80b..0ccc8362 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -75,22 +75,21 @@ template struct from_chars_result_t { using from_chars_result = from_chars_result_t; template struct parse_options_t { - FASTFLOAT_CONSTEXPR20 explicit parse_options_t( + constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), chars_format_t const b = 10) noexcept - : format(fmt), decimal_point(dot), - base(b){ + : format(fmt), decimal_point(dot), base(b) { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - // static_assert(b >= 2 && b <= 36); + // static_assert(b >= 2 && b <= 36); #endif - } + } - /** Which number formats are accepted */ - chars_format const format; + /** Which number formats are accepted */ + chars_format format; /** The character used as decimal point */ - UC const decimal_point; + UC decimal_point; /** The base used for integers */ - uint_fast8_t const base; /* only allowed from 2 to 36 */ + uint_fast8_t base; /* only allowed from 2 to 36 */ FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 9b61bdf4..552d6f15 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -644,20 +644,19 @@ TEST_CASE("check_behavior") { TEST_CASE("decimal_point_parsing") { double result; + fast_float::parse_options options{}; { std::string const input = "1,25"; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options{}); + input.data(), input.data() + input.size(), result, options); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at comma"); CHECK_EQ(result, 1.0); + options.decimal_point = ','; answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options( - {fast_float::chars_format::general, ',', 10})); + input.data(), input.data() + input.size(), result, options); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -666,17 +665,15 @@ TEST_CASE("decimal_point_parsing") { { std::string const input = "1.25"; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options( - {fast_float::chars_format::general, ',', 10})); + input.data(), input.data() + input.size(), result, options); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + 1, "Parsing should have stopped at dot"); CHECK_EQ(result, 1.0); + options.decimal_point = '.'; answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options{}); + input.data(), input.data() + input.size(), result, options); CHECK_MESSAGE(answer.ec == std::errc(), "expected parse success"); CHECK_MESSAGE(answer.ptr == input.data() + input.size(), "Parsing should have stopped at end"); @@ -1325,8 +1322,9 @@ TEST_CASE("double.general") { TEST_CASE("double.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options( - {fast_float::chars_format::general, ',', 10}); + fast_float::parse_options ret{}; + ret.decimal_point = ','; + return ret; }(); // infinities @@ -1643,8 +1641,9 @@ TEST_CASE("float.general") { TEST_CASE("float.decimal_point") { constexpr auto options = [] { - return fast_float::parse_options( - {fast_float::chars_format::general, ',', 10}); + fast_float::parse_options ret{}; + ret.decimal_point = ','; + return ret; }(); // infinity diff --git a/tests/example_comma_test.cpp b/tests/example_comma_test.cpp index b77ad57e..79a8e1d0 100644 --- a/tests/example_comma_test.cpp +++ b/tests/example_comma_test.cpp @@ -7,9 +7,9 @@ int main() { std::string const input = "3,1416 xyz "; double result; + fast_float::parse_options options{fast_float::chars_format::general, ','}; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options({fast_float::chars_format::general, ','})); + input.data(), input.data() + input.size(), result, options); if ((answer.ec != std::errc()) || ((result != 3.1416))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; diff --git a/tests/fortran.cpp b/tests/fortran.cpp index ca419868..38473548 100644 --- a/tests/fortran.cpp +++ b/tests/fortran.cpp @@ -9,11 +9,11 @@ int main_readme() { std::string const input = "1d+4"; double result; + fast_float::parse_options options{ + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}; auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options( - {fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus})); + input.data(), input.data() + input.size(), result, options); if ((answer.ec != std::errc()) || ((result != 10000))) { std::cerr << "parsing failure\n" << result << "\n"; return EXIT_FAILURE; @@ -32,14 +32,15 @@ int main() { std::vector const fmt3{"+1+4", "+1+3", "+1+2", "+1+1", "+1+0", "+1-1", "+1-2", "+1-3", "+1-4"}; + fast_float::parse_options const options{ + fast_float::chars_format::fortran | + fast_float::chars_format::allow_leading_plus}; + for (auto const &f : fmt1) { auto d{std::distance(&fmt1[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced( - f.data(), f.data() + f.size(), result, - fast_float::parse_options( - {fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), + result, options)}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -49,11 +50,8 @@ int main() { for (auto const &f : fmt2) { auto d{std::distance(&fmt2[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced( - f.data(), f.data() + f.size(), result, - fast_float::parse_options( - {fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), + result, options)}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; @@ -63,11 +61,8 @@ int main() { for (auto const &f : fmt3) { auto d{std::distance(&fmt3[0], &f)}; double result; - auto answer{fast_float::from_chars_advanced( - f.data(), f.data() + f.size(), result, - fast_float::parse_options( - {fast_float::chars_format::fortran | - fast_float::chars_format::allow_leading_plus}))}; + auto answer{fast_float::from_chars_advanced(f.data(), f.data() + f.size(), + result, options)}; if (answer.ec != std::errc() || result != expected[std::size_t(d)]) { std::cerr << "parsing failure on " << f << std::endl; return EXIT_FAILURE; diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index 70fdef2c..c210a451 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -7,12 +7,11 @@ int main_readme() { std::string const input = "+.1"; // not valid double result; + fast_float::parse_options options{ + fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus}; // should be ignored auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options options( - {fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}) // should be ignored - ); + input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -23,12 +22,11 @@ int main_readme() { int main_readme2() { std::string const input = "inf"; // not valid in JSON double result; + fast_float::parse_options options{ + fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus}; // should be ignored auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options options( - {fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus}) // should be ignored - ); + input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; return EXIT_FAILURE; @@ -40,12 +38,11 @@ int main_readme3() { std::string const input = "inf"; // not valid in JSON but we allow it with json_or_infnan double result; + fast_float::parse_options options{ + fast_float::chars_format::json_or_infnan | + fast_float::chars_format::allow_leading_plus}; // should be ignored auto answer = fast_float::from_chars_advanced( - input.data(), input.data() + input.size(), result, - fast_float::parse_options options( - {fast_float::chars_format::json_or_infnan | - fast_float::chars_format::allow_leading_plus}); // should be ignored - ); + input.data(), input.data() + input.size(), result, options); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; return EXIT_FAILURE; @@ -137,9 +134,9 @@ int main() { auto answer = fast_float::parse_number_string( f.data(), f.data() + f.size(), fast_float::parse_options( - {fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus})); // should be - // ignored + fast_float::chars_format::json | + fast_float::chars_format::allow_leading_plus)); // should be + // ignored if (answer.valid) { std::cerr << "json parse accepted invalid json " << f << std::endl; return EXIT_FAILURE; @@ -171,4 +168,4 @@ int main() { #endif return EXIT_SUCCESS; -} \ No newline at end of file +} From 30bd959a0ff316ff867991a26e6577ffa96546e0 Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Tue, 6 May 2025 21:06:34 +0300 Subject: [PATCH 107/252] Update msys2-clang.yml --- .github/workflows/msys2-clang.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index 3f3d323d..fca8ab7d 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -28,7 +28,7 @@ jobs: with: update: true msystem: ${{ matrix.msystem }} - install: ${{ matrix.install }} cmake + install: ${{ matrix.install }} - name: Prepare build dir run: mkdir build - name: Configure From c33961825254932a4868eb7ebfe0e4af979f6991 Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Tue, 6 May 2025 21:07:02 +0300 Subject: [PATCH 108/252] Update msys2.yml --- .github/workflows/msys2.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index dfb6764f..86be5244 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -34,7 +34,7 @@ jobs: with: update: true msystem: ${{ matrix.msystem }} - install: ${{ matrix.install }} cmake + install: ${{ matrix.install }} - name: Prepare build dir run: mkdir build - name: Configure From 3f9e4889794543beaaed93d1a11a5cd37c45250e Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 21:09:33 +0300 Subject: [PATCH 109/252] format, fuck. --- include/fast_float/float_common.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 0ccc8362..7d14be7c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -78,14 +78,15 @@ template struct parse_options_t { constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), chars_format_t const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) { + : format(fmt), decimal_point(dot), + base(b){ #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - // static_assert(b >= 2 && b <= 36); + // static_assert(b >= 2 && b <= 36); #endif - } + } - /** Which number formats are accepted */ - chars_format format; + /** Which number formats are accepted */ + chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ From a4c573e8abdb41c861f63ec4ec138fef92683816 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 21:54:40 +0300 Subject: [PATCH 110/252] compilation fix --- include/fast_float/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index cb41d91b..2697e7c9 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -32,7 +32,7 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -typedef uint_fast16_t bigint_bits_t; +typedef int_fast16_t bigint_bits_t; constexpr bigint_bits_t bigint_bits = 4000; constexpr limb_t bigint_limbs = bigint_bits / limb_bits; From a3ccc1f7b175c506ab97181b7849ed8b980bd790 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 22:05:06 +0300 Subject: [PATCH 111/252] compilation fix --- include/fast_float/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 2697e7c9..cb41d91b 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -32,7 +32,7 @@ typedef span limb_span; // of bits required to store the largest bigint, which is // `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or // ~3600 bits, so we round to 4000. -typedef int_fast16_t bigint_bits_t; +typedef uint_fast16_t bigint_bits_t; constexpr bigint_bits_t bigint_bits = 4000; constexpr limb_t bigint_limbs = bigint_bits / limb_bits; From e446899538cf1e63b77a1ef1b7c0bcd5059b1757 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 22:19:50 +0300 Subject: [PATCH 112/252] compilation fix. --- include/fast_float/ascii_number.h | 10 +++++----- include/fast_float/bigint.h | 2 +- include/fast_float/decimal_to_binary.h | 2 +- include/fast_float/digit_comparison.h | 3 ++- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index fc5b4aaa..bb8511f1 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -332,9 +332,9 @@ parse_number_string(UC const *p, UC const *pend, while ((p != pend) && is_integer(*p)) { // a multiplication by 10 is cheaper than an arbitrary integer // multiplication - answer.mantissa = - 10 * answer.mantissa + - UC(*p - UC('0')); // might overflow, we will handle the overflow later + answer.mantissa = static_cast( + answer.mantissa * 10 + + UC(*p - UC('0'))); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; @@ -364,9 +364,9 @@ parse_number_string(UC const *p, UC const *pend, while ((p != pend) && is_integer(*p)) { UC const digit = UC(*p - UC('0')); - answer.mantissa = + answer.mantissa = static_cast( answer.mantissa * 10 + - digit; // in rare cases, this will overflow, but that's ok + digit); // in rare cases, this will overflow, but that's ok ++p; } answer.exponent = static_cast(before - p); diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index cb41d91b..48567e6b 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -582,7 +582,7 @@ struct bigint : pow5_tables<> { // get the number of bits in the bigint. FASTFLOAT_CONSTEXPR20 bigint_bits_t bit_length() const noexcept { limb_t lz = ctlz(); - return limb_bits * vec.len() - lz; + return static_cast(limb_bits * vec.len() - lz); } FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 8897420c..cb810f28 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -72,7 +72,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { - am_pow_t hilz = uint64_t(w >> 63) ^ 1; + am_pow_t hilz = static_cast(uint64_t(w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index be337717..7111eabf 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -355,7 +355,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( am.mantissa = bigmant.hi64(truncated); constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - am.power2 = bigmant.bit_length() - 64 + bias; + am.power2 = + static_cast(bigmant.bit_length() - 64 + bias); round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( From 6f789de5d2c11cdacd14bd623a8df8a2038e2e13 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 22:32:11 +0300 Subject: [PATCH 113/252] compilation fix. --- include/fast_float/ascii_number.h | 15 ++++++++------- include/fast_float/bigint.h | 6 ++++-- include/fast_float/digit_comparison.h | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index bb8511f1..04620201 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -334,7 +334,8 @@ parse_number_string(UC const *p, UC const *pend, // multiplication answer.mantissa = static_cast( answer.mantissa * 10 + - UC(*p - UC('0'))); // might overflow, we will handle the overflow later + static_cast( + *p - UC('0'))); // might overflow, we will handle the overflow later ++p; } UC const *const end_of_integer_part = p; @@ -391,9 +392,9 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part if ((p != pend) && - (chars_format_t(options.format & chars_format::scientific) && - (UC('e') == *p) || - (UC('E') == *p)) + ((chars_format_t(options.format & chars_format::scientific) && + (UC('e') == *p) || + (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN || (chars_format_t(options.format & detail::basic_fortran_fmt) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || @@ -421,9 +422,9 @@ parse_number_string(UC const *p, UC const *pend, } if ((p == pend) || !is_integer(*p)) { if (!chars_format_t(options.format & chars_format::fixed)) { - // The exponential part is invalid for scientific notation, so it must - // be a trailing token for fixed notation. However, fixed notation is - // disabled, so report a scientific notation error. + // The exponential part is invalid for scientific notation, so it + // must be a trailing token for fixed notation. However, fixed + // notation is disabled, so report a scientific notation error. return report_parse_error(p, parse_error::missing_exponential_part); } // Otherwise, we will be ignoring the 'e'. diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 48567e6b..3fb18467 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -67,7 +67,7 @@ template struct stackvec { // index from the end of the container FASTFLOAT_CONSTEXPR14 const limb &rindex(limb_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - limb_t rindex = length - index - 1; + limb_t rindex = static_cast(length - index - 1); return data[rindex]; } @@ -590,7 +590,9 @@ struct bigint : pow5_tables<> { FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } // multiply as if by 2 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t exp) noexcept { return shl(exp); } + FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t exp) noexcept { + return shl(static_cast(exp)); + } // multiply as if by 5 raised to a power. FASTFLOAT_CONSTEXPR20 bool pow5(am_pow_t exp) noexcept { diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 7111eabf..e6dedba8 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -457,7 +457,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am_digits const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - am_pow_t const exponent = sci_exp + 1 - digits; + am_pow_t const exponent = static_cast(sci_exp + 1 - digits); if (exponent >= 0) { return positive_digit_comp(bigmant, am, exponent); } else { From 1ec5f0880cd42f44344834a80101774c48ddf687 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 22:53:10 +0300 Subject: [PATCH 114/252] compilation fix --- include/fast_float/ascii_number.h | 24 +++++++++++++----------- include/fast_float/digit_comparison.h | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 04620201..62b6fbc9 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -367,7 +367,8 @@ parse_number_string(UC const *p, UC const *pend, UC const digit = UC(*p - UC('0')); answer.mantissa = static_cast( answer.mantissa * 10 + - digit); // in rare cases, this will overflow, but that's ok + static_cast( + digit)); // in rare cases, this will overflow, but that's ok ++p; } answer.exponent = static_cast(before - p); @@ -391,16 +392,15 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part - if ((p != pend) && - ((chars_format_t(options.format & chars_format::scientific) && - (UC('e') == *p) || - (UC('E') == *p))) + if (((p != pend) && + (((chars_format_t(options.format & chars_format::scientific) && + ((UC('e') == *p) || (UC('E') == *p)))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (chars_format_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) + || (chars_format_t(options.format & detail::basic_fortran_fmt) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) #endif - ) { + ))) { UC const *location_of_e = p; #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; @@ -483,7 +483,8 @@ parse_number_string(UC const *p, UC const *pend, am_mant_t const minimal_nineteen_digit_integer{1000000000000000000}; while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != int_end)) { - answer.mantissa = answer.mantissa * 10 + UC(*p - UC('0')); + answer.mantissa = static_cast( + answer.mantissa * 10 + static_cast(*p - UC('0'))); ++p; } if (answer.mantissa >= @@ -494,7 +495,8 @@ parse_number_string(UC const *p, UC const *pend, UC const *frac_end = p + answer.fraction.len(); while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != frac_end)) { - answer.mantissa = answer.mantissa * 10 + UC(*p - UC('0')); + answer.mantissa = static_cast( + answer.mantissa * 10 + static_cast(*p - UC('0'))); ++p; } answer.exponent = am_pow_t(answer.fraction.ptr - p) + exp_number; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index e6dedba8..cc3e0ddf 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -457,7 +457,8 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am_digits const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - am_pow_t const exponent = static_cast(sci_exp + 1 - digits); + am_pow_t const exponent = + static_cast(sci_exp + 1 - static_cast(digits)); if (exponent >= 0) { return positive_digit_comp(bigmant, am, exponent); } else { From 036ba0d15381455692fbe1ed5ed02841b242004e Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 23:03:56 +0300 Subject: [PATCH 115/252] compilation fix --- include/fast_float/ascii_number.h | 2 +- include/fast_float/decimal_to_binary.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 62b6fbc9..0b38139b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -374,7 +374,7 @@ parse_number_string(UC const *p, UC const *pend, answer.exponent = static_cast(before - p); answer.fraction = span(before, static_cast(p - before)); - digit_count -= answer.exponent; + digit_count -= static_cast(answer.exponent); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in fractional part diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index cb810f28..badf0fae 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -140,7 +140,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. limb_t upperbit = limb_t(product.high >> 63); - limb_t shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + limb_t shift = limb_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); answer.mantissa = product.high >> shift; From 568dfef204987f3a560721ee04de67f6aa616b6f Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 23:21:59 +0300 Subject: [PATCH 116/252] compilation fix --- include/fast_float/ascii_number.h | 2 +- include/fast_float/parse_number.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 0b38139b..bc449128 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -434,7 +434,7 @@ parse_number_string(UC const *p, UC const *pend, if (exp_number < 0x1000) { // check for exponent overflow if we have too many digits. UC const digit = UC(*p - UC('0')); - exp_number = 10 * exp_number + digit; + exp_number = 10 * exp_number + static_cast(digit); } ++p; } diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 6e56b95d..b7645406 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -364,7 +364,9 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - parse_options_t const options(chars_format::general, UC('.'), base); + parse_options_t const options( + static_cast(chars_format::general), UC('.'), + static_cast(base)); return from_chars_advanced(first, last, value, options); } From 2f8ff9a6ebb2df214a501b0949e93e31960c766f Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 6 May 2025 23:40:29 +0300 Subject: [PATCH 117/252] compilation fix --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7d14be7c..37e0ec82 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -76,8 +76,8 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { constexpr explicit parse_options_t( - chars_format const fmt = chars_format::general, UC const dot = UC('.'), - chars_format_t const b = 10) noexcept + chars_format_t const fmt = chars_format::general, UC const dot = UC('.'), + uint_fast8_t const b = 10) noexcept : format(fmt), decimal_point(dot), base(b){ #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 4b94a612cf8fac1360ce4e15290a3142bdbf0d0d Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 00:44:20 +0300 Subject: [PATCH 118/252] type usage fix --- include/fast_float/ascii_number.h | 24 ++++++++++++------------ include/fast_float/float_common.h | 15 +++++---------- include/fast_float/parse_number.h | 9 ++++----- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index bc449128..144ca59b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -303,8 +303,8 @@ parse_number_string(UC const *p, UC const *pend, answer.negative = (*p == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*p == UC('-')) || - (chars_format_t(options.format & chars_format::allow_leading_plus) && - !basic_json_fmt && *p == UC('+'))) { + ((chars_format_t(options.format & chars_format::allow_leading_plus)) && + (!basic_json_fmt && *p == UC('+')))) { ++p; if (p == pend) { return report_parse_error( @@ -393,14 +393,14 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part if (((p != pend) && - (((chars_format_t(options.format & chars_format::scientific) && - ((UC('e') == *p) || (UC('E') == *p)))) + (((chars_format_t(options.format & chars_format::scientific)) && + ((UC('e') == *p) || (UC('E') == *p)))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (chars_format_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) + || (((chars_format_t(options.format & detail::basic_fortran_fmt))) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) #endif - ))) { + )) { UC const *location_of_e = p; #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; @@ -421,7 +421,7 @@ parse_number_string(UC const *p, UC const *pend, } } if ((p == pend) || !is_integer(*p)) { - if (!chars_format_t(options.format & chars_format::fixed)) { + if (!(chars_format_t(options.format & chars_format::fixed))) { // The exponential part is invalid for scientific notation, so it // must be a trailing token for fixed notation. However, fixed // notation is disabled, so report a scientific notation error. @@ -445,8 +445,8 @@ parse_number_string(UC const *p, UC const *pend, } } else { // If it scientific and not fixed, we have to bail out. - if (chars_format_t(options.format & chars_format::scientific) && - !chars_format_t(options.format & chars_format::fixed)) { + if ((chars_format_t(options.format & chars_format::scientific)) && + !(chars_format_t(options.format & chars_format::fixed))) { return report_parse_error(p, parse_error::missing_exponential_part); } } @@ -531,7 +531,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, return answer; } if ((*p == UC('-')) || - (chars_format_t(options.format & chars_format::allow_leading_plus) && + ((chars_format_t(options.format & chars_format::allow_leading_plus)) && (*p == UC('+')))) { ++p; } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 37e0ec82..378ce222 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -58,7 +58,7 @@ enum class chars_format : chars_format_t { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN no_infnan = 1 << 3, // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 - json = uint64_t(detail::basic_json_fmt) | general | no_infnan, + json = chars_format_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. json_or_infnan = chars_format_t(detail::basic_json_fmt) | general, fortran = chars_format_t(detail::basic_fortran_fmt) | general, @@ -76,17 +76,12 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { constexpr explicit parse_options_t( - chars_format_t const fmt = chars_format::general, UC const dot = UC('.'), + chars_format const fmt = chars_format::general, UC const dot = UC('.'), uint_fast8_t const b = 10) noexcept - : format(fmt), decimal_point(dot), - base(b){ -#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - // static_assert(b >= 2 && b <= 36); -#endif - } + : format(fmt), decimal_point(dot), base(b) {} - /** Which number formats are accepted */ - chars_format format; + /** Which number formats are accepted */ + chars_format format; /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index b7645406..df079ba0 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -33,7 +33,7 @@ from_chars_result_t bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if ((*first == UC('-')) || - (chars_format_t(fmt & chars_format::allow_leading_plus) && + ((chars_format_t(fmt & chars_format::allow_leading_plus)) && (*first == UC('+')))) { ++first; } @@ -332,7 +332,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, #endif parsed_number_string_t const pns = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - chars_format_t(options.format & detail::basic_json_fmt) + (chars_format_t(options.format & detail::basic_json_fmt)) ? parse_number_string(first, last, options) : #endif @@ -364,9 +364,8 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - parse_options_t const options( - static_cast(chars_format::general), UC('.'), - static_cast(base)); + parse_options_t const options(chars_format::general, UC('.'), + static_cast(base)); return from_chars_advanced(first, last, value, options); } From 23a9c3f54dc44fae680af42fafbf5a4b811112ce Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 18:02:44 +0300 Subject: [PATCH 119/252] review of the parse_number_string function: now it's much faster, safer and easy to understand. --- include/fast_float/ascii_number.h | 160 +++++++++++++++++++----------- 1 file changed, 103 insertions(+), 57 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 144ca59b..540877a2 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -238,7 +238,7 @@ loop_parse_if_eight_digits(char const *&p, char const *const pend, } } -enum class parse_error { +enum class parse_error : uint_fast8_t { no_error, // A sign must be followed by an integer or dot. missing_integer_or_dot_after_sign, @@ -301,8 +301,8 @@ parse_number_string(UC const *p, UC const *pend, FASTFLOAT_ASSUME(p < pend); // so dereference without checks; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*p == UC('-')) || + if (answer.negative || + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here ((chars_format_t(options.format & chars_format::allow_leading_plus)) && (!basic_json_fmt && *p == UC('+')))) { ++p; @@ -338,10 +338,13 @@ parse_number_string(UC const *p, UC const *pend, *p - UC('0'))); // might overflow, we will handle the overflow later ++p; } + UC const *const end_of_integer_part = p; am_digits digit_count = static_cast(end_of_integer_part - start_digits); answer.integer = span(start_digits, digit_count); + // We have now parsed the integer part of the mantissa. + #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in integer part, without leading zeros @@ -355,8 +358,8 @@ parse_number_string(UC const *p, UC const *pend, } #endif - bool const has_decimal_point = (p != pend) && (*p == options.decimal_point); - if (has_decimal_point) { + // We can now parse the fraction part of the mantissa. + if ((p != pend) && (*p == options.decimal_point)) { ++p; UC const *before = p; // can occur at most twice without overflowing, but let it occur more, since @@ -378,7 +381,7 @@ parse_number_string(UC const *p, UC const *pend, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in fractional part - if (has_decimal_point && answer.exponent == 0) { + if (answer.exponent == 0) { return report_parse_error( p, parse_error::no_digits_in_fractional_part); } @@ -392,44 +395,79 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part - if (((p != pend) && - (((chars_format_t(options.format & chars_format::scientific)) && - ((UC('e') == *p) || (UC('E') == *p)))) -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (((chars_format_t(options.format & detail::basic_fortran_fmt))) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) -#endif - )) { - UC const *location_of_e = p; -#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - ++p; -#else - if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || - (UC('D') == *p)) { - ++p; + bool neg_exp = false; + if (p != pend) { + UC const *location_of_e; + if (chars_format_t(options.format & chars_format::scientific)) { + switch (*p) { + case UC('e'): + case UC('E'): + location_of_e = p; + ++p; + break; + default: + // If it scientific and not fixed, we have to bail out. + if (!chars_format_t(options.format & chars_format::fixed)) { + return report_parse_error(p, + parse_error::missing_exponential_part); + } + // In fixed notation we will be ignoring the 'e'. + location_of_e = nullptr; + } + if (location_of_e && p != pend) { + switch (*p) { + case UC('-'): + neg_exp = true; + ++p; + break; + case UC('+'): // '+' on exponent is allowed by C++17 20.19.3.(7.1) + ++p; + break; + default: + // If it scientific and not fixed, we have to bail out. + if (!chars_format_t(options.format & chars_format::fixed)) { + return report_parse_error( + p, parse_error::missing_exponential_part); + } + // In fixed notation we will be ignoring the 'e'. + location_of_e = nullptr; + } + } } -#endif - bool neg_exp = false; - if (p != pend) { - if (UC('-') == *p) { +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + else if (chars_format_t(options.format & detail::basic_fortran_fmt)) { + switch (*p) { + case UC('d'): + case UC('D'): + ++p; + break; + default: + // In Fortran the d symbol is optional. + break; + } + switch (*p) { + case UC('-'): neg_exp = true; + location_of_e = p; ++p; - } else if (UC('+') == *p) { - // '+' on exponent is allowed by C++17 20.19.3.(7.1) + break; + case UC('+'): + location_of_e = p; ++p; - } - } - if ((p == pend) || !is_integer(*p)) { - if (!(chars_format_t(options.format & chars_format::fixed))) { - // The exponential part is invalid for scientific notation, so it - // must be a trailing token for fixed notation. However, fixed - // notation is disabled, so report a scientific notation error. + break; + default: + // In Fortran the sign is mandatory. return report_parse_error(p, parse_error::missing_exponential_part); } - // Otherwise, we will be ignoring the 'e'. - p = location_of_e; - } else { + } +#endif + else { + location_of_e = nullptr; + } + + if (location_of_e) { + // We have a valid scientific notation, let's parse the explicit + // exponent. while ((p != pend) && is_integer(*p)) { if (exp_number < 0x1000) { // check for exponent overflow if we have too many digits. @@ -443,35 +481,41 @@ parse_number_string(UC const *p, UC const *pend, } answer.exponent += exp_number; } - } else { - // If it scientific and not fixed, we have to bail out. - if ((chars_format_t(options.format & chars_format::scientific)) && - !(chars_format_t(options.format & chars_format::fixed))) { +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + else if (chars_format_t(options.format & detail::basic_fortran_fmt)) { + // In Fortran the number in exponent part is mandatory. return report_parse_error(p, parse_error::missing_exponential_part); } +#endif } + + // We parsed all parts of the number, let's save progress. answer.lastmatch = p; answer.valid = true; - // If we frequently had to deal with long strings of digits, + // Now we can check for errors. + + // TODO: If we frequently had to deal with long strings of digits, // we could extend our code by using a 128-bit integer instead // of a 64-bit integer. However, this is uncommon. - // + // We can deal with up to 19 digits. - if (digit_count > 19) { // this is uncommon + if (digit_count > 19) { // It is possible that the integer had an overflow. // We have to handle the case where we have 0.0000somenumber. // We need to be mindful of the case where we only have zeroes... // E.g., 0.000000000...000. UC const *start = start_digits; - while ((start != pend) && - (*start == UC('0') || *start == options.decimal_point)) { - if (*start == UC('0')) { - --digit_count; + do { // we already have some numbers, so we can skip first check safely + if ((*start == UC('0') || *start == options.decimal_point)) { + if (*start == UC('0')) { + --digit_count; + } } - ++start; - } + } while (++start != pend); + // We have to check if we have a number with more than 19 significant + // digits. if (digit_count > 19) { answer.too_many_digits = true; // Let us start again, this time, avoiding overflows. @@ -480,19 +524,20 @@ parse_number_string(UC const *p, UC const *pend, answer.mantissa = 0; p = answer.integer.ptr; UC const *int_end = p + answer.integer.len(); - am_mant_t const minimal_nineteen_digit_integer{1000000000000000000}; + constexpr am_mant_t minimal_nineteen_digit_integer{1000000000000000000}; while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != int_end)) { answer.mantissa = static_cast( answer.mantissa * 10 + static_cast(*p - UC('0'))); ++p; } - if (answer.mantissa >= - minimal_nineteen_digit_integer) { // We have a big integers + if (answer.mantissa >= minimal_nineteen_digit_integer) { + // We have a big integers, so skip the fraction part completely. answer.exponent = am_pow_t(end_of_integer_part - p) + exp_number; - } else { // We have a value with a fractional component. + } else { + // We have a value with a significant fractional component. p = answer.fraction.ptr; - UC const *frac_end = p + answer.fraction.len(); + UC const *const frac_end = p + answer.fraction.len(); while ((answer.mantissa < minimal_nineteen_digit_integer) && (p != frac_end)) { answer.mantissa = static_cast( @@ -501,9 +546,10 @@ parse_number_string(UC const *p, UC const *pend, } answer.exponent = am_pow_t(answer.fraction.ptr - p) + exp_number; } - // We have now corrected both exponent and mantissa, to a truncated value } + // We have now corrected both exponent and mantissa, to a truncated value } + return answer; } From f7d5037a4fbc1eb6d950ff3372c1782839d3da79 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 19:31:56 +0300 Subject: [PATCH 120/252] fix for the parse_number_string small improvements for the FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN --- include/fast_float/ascii_number.h | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 540877a2..6cfa5c7f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -328,15 +328,24 @@ parse_number_string(UC const *p, UC const *pend, #endif UC const *const start_digits = p; - - while ((p != pend) && is_integer(*p)) { - // a multiplication by 10 is cheaper than an arbitrary integer - // multiplication - answer.mantissa = static_cast( - answer.mantissa * 10 + - static_cast( - *p - UC('0'))); // might overflow, we will handle the overflow later - ++p; +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + if (p != pend) +#endif + { + do { + if (is_integer(*p)) { + // a multiplication by 10 is cheaper than an arbitrary integer + // multiplication + answer.mantissa = static_cast( + answer.mantissa * 10 + + static_cast( + *p - + UC('0'))); // might overflow, we will handle the overflow later + ++p; + } else { + break; + } + } while (p != pend); } UC const *const end_of_integer_part = p; @@ -398,7 +407,8 @@ parse_number_string(UC const *p, UC const *pend, bool neg_exp = false; if (p != pend) { UC const *location_of_e; - if (chars_format_t(options.format & chars_format::scientific)) { + if (chars_format_t(options.format & chars_format::scientific) || + chars_format_t(options.format & chars_format::fixed)) { switch (*p) { case UC('e'): case UC('E'): @@ -406,8 +416,8 @@ parse_number_string(UC const *p, UC const *pend, ++p; break; default: - // If it scientific and not fixed, we have to bail out. if (!chars_format_t(options.format & chars_format::fixed)) { + // It scientific and not fixed, we have to bail out. return report_parse_error(p, parse_error::missing_exponential_part); } @@ -424,13 +434,8 @@ parse_number_string(UC const *p, UC const *pend, ++p; break; default: - // If it scientific and not fixed, we have to bail out. - if (!chars_format_t(options.format & chars_format::fixed)) { - return report_parse_error( - p, parse_error::missing_exponential_part); - } - // In fixed notation we will be ignoring the 'e'. - location_of_e = nullptr; + // In scientific and fixed notations sign is optional. + break; } } } From 6b229571887e862050b974a8866dd651b092bc81 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 20:18:57 +0300 Subject: [PATCH 121/252] fix for the parse_number_string --- include/fast_float/ascii_number.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 6cfa5c7f..cdf3e680 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -396,8 +396,8 @@ parse_number_string(UC const *p, UC const *pend, } } #endif - } 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(p, parse_error::no_digits_in_mantissa); } // We have now parsed the integer and the fraction part of the mantissa. @@ -407,8 +407,7 @@ parse_number_string(UC const *p, UC const *pend, bool neg_exp = false; if (p != pend) { UC const *location_of_e; - if (chars_format_t(options.format & chars_format::scientific) || - chars_format_t(options.format & chars_format::fixed)) { + if (chars_format_t(options.format & chars_format::scientific)) { switch (*p) { case UC('e'): case UC('E'): @@ -485,13 +484,11 @@ parse_number_string(UC const *p, UC const *pend, exp_number = -exp_number; } answer.exponent += exp_number; - } -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - else if (chars_format_t(options.format & detail::basic_fortran_fmt)) { - // In Fortran the number in exponent part is mandatory. + } else if (chars_format_t(options.format & chars_format::scientific) && + !chars_format_t(options.format & chars_format::fixed)) { + // If it scientific and not fixed, we have to bail out. return report_parse_error(p, parse_error::missing_exponential_part); } -#endif } // We parsed all parts of the number, let's save progress. From 3ee80c2da340ad10684e5aa0e2f724928773f78d Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 21:43:26 +0300 Subject: [PATCH 122/252] fix for the parse_number_string --- include/fast_float/ascii_number.h | 133 +++++++++++------------------- 1 file changed, 49 insertions(+), 84 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index cdf3e680..4692b793 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -328,24 +328,15 @@ parse_number_string(UC const *p, UC const *pend, #endif UC const *const start_digits = p; -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (p != pend) -#endif - { - do { - if (is_integer(*p)) { - // a multiplication by 10 is cheaper than an arbitrary integer - // multiplication - answer.mantissa = static_cast( - answer.mantissa * 10 + - static_cast( - *p - - UC('0'))); // might overflow, we will handle the overflow later - ++p; - } else { - break; - } - } while (p != pend); + + while ((p != pend) && is_integer(*p)) { + // a multiplication by 10 is cheaper than an arbitrary integer + // multiplication + answer.mantissa = static_cast( + answer.mantissa * 10 + + static_cast( + *p - UC('0'))); // might overflow, we will handle the overflow later + ++p; } UC const *const end_of_integer_part = p; @@ -370,7 +361,7 @@ parse_number_string(UC const *p, UC const *pend, // We can now parse the fraction part of the mantissa. if ((p != pend) && (*p == options.decimal_point)) { ++p; - UC const *before = p; + UC const *const before = p; // can occur at most twice without overflowing, but let it occur more, since // for integers with many digits, digit parsing is the primary bottleneck. loop_parse_if_eight_digits(p, pend, answer.mantissa); @@ -404,74 +395,46 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part - bool neg_exp = false; - if (p != pend) { - UC const *location_of_e; - if (chars_format_t(options.format & chars_format::scientific)) { - switch (*p) { - case UC('e'): - case UC('E'): - location_of_e = p; - ++p; - break; - default: - if (!chars_format_t(options.format & chars_format::fixed)) { - // It scientific and not fixed, we have to bail out. - return report_parse_error(p, - parse_error::missing_exponential_part); - } - // In fixed notation we will be ignoring the 'e'. - location_of_e = nullptr; - } - if (location_of_e && p != pend) { - switch (*p) { - case UC('-'): - neg_exp = true; - ++p; - break; - case UC('+'): // '+' on exponent is allowed by C++17 20.19.3.(7.1) - ++p; - break; - default: - // In scientific and fixed notations sign is optional. - break; - } - } - } + if ((p != pend) && + (chars_format_t(options.format & chars_format::scientific) && + ((UC('e') == *p) || (UC('E') == *p))) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - else if (chars_format_t(options.format & detail::basic_fortran_fmt)) { - switch (*p) { - case UC('d'): - case UC('D'): - ++p; - break; - default: - // In Fortran the d symbol is optional. - break; - } - switch (*p) { - case UC('-'): + || (chars_format_t(options.format & detail::basic_fortran_fmt) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) +#endif + ) { + UC const *location_of_e = p; +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + ++p; +#else + if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || + (UC('D') == *p)) { + ++p; + } +#endif + bool neg_exp = false; + if (p != pend) { + if (UC('-') == *p) { neg_exp = true; - location_of_e = p; ++p; - break; - case UC('+'): - location_of_e = p; + } else if (UC('+') == *p) { + // '+' on exponent is allowed by C++17 20.19.3.(7.1) ++p; - break; - default: - // In Fortran the sign is mandatory. - return report_parse_error(p, parse_error::missing_exponential_part); } } -#endif - else { - location_of_e = nullptr; - } - - if (location_of_e) { - // We have a valid scientific notation, let's parse the explicit - // exponent. + // We have now parsed the sign of the exponent. + if ((p == pend) || !is_integer(*p)) { + if (!(chars_format_t(options.format & chars_format::fixed))) { + // The exponential part is invalid for scientific notation, so it + // must be a trailing token for fixed notation. However, fixed + // notation is disabled, so report a scientific notation error. + return report_parse_error(p, parse_error::missing_exponential_part); + } + // Otherwise, we will be ignoring the 'e'. + p = location_of_e; + } else { + // Now let's parse the explicit exponent. while ((p != pend) && is_integer(*p)) { if (exp_number < 0x1000) { // check for exponent overflow if we have too many digits. @@ -484,9 +447,11 @@ parse_number_string(UC const *p, UC const *pend, exp_number = -exp_number; } answer.exponent += exp_number; - } else if (chars_format_t(options.format & chars_format::scientific) && - !chars_format_t(options.format & chars_format::fixed)) { - // If it scientific and not fixed, we have to bail out. + } + } else { + // If it scientific and not fixed, we have to bail out. + if ((chars_format_t(options.format & chars_format::scientific)) && + !(chars_format_t(options.format & chars_format::fixed))) { return report_parse_error(p, parse_error::missing_exponential_part); } } From 88fff015130f256488a4b4fd2d77b463daea6d87 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 21:51:43 +0300 Subject: [PATCH 123/252] fix for the parse_number_string --- include/fast_float/ascii_number.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 4692b793..5cbf2ca6 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -396,14 +396,14 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part if ((p != pend) && - (chars_format_t(options.format & chars_format::scientific) && - ((UC('e') == *p) || (UC('E') == *p))) + (chars_format_t(options.format & chars_format::scientific) && + ((UC('e') == *p) || (UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (chars_format_t(options.format & detail::basic_fortran_fmt) && - ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || - (UC('D') == *p))) + || (chars_format_t(options.format & detail::basic_fortran_fmt) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p))) #endif - ) { + )) { UC const *location_of_e = p; #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; From f14d48276763754d0e08e68b15d5d0bad3e708f0 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 21:59:53 +0300 Subject: [PATCH 124/252] fix for the parse_number_string --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 5cbf2ca6..58ca993b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -396,8 +396,8 @@ parse_number_string(UC const *p, UC const *pend, // Now we can parse the explicit exponential part. am_pow_t exp_number = 0; // explicit exponential part if ((p != pend) && - (chars_format_t(options.format & chars_format::scientific) && - ((UC('e') == *p) || (UC('E') == *p)) + ((chars_format_t(options.format & chars_format::scientific) && + (UC('e') == *p || UC('E') == *p)) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN || (chars_format_t(options.format & detail::basic_fortran_fmt) && ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || From 7bac32408e2564e29f81c9f8ece772248242e809 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 22:14:55 +0300 Subject: [PATCH 125/252] fix for the parse_number_string --- include/fast_float/ascii_number.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 58ca993b..5432d16e 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -473,13 +473,13 @@ parse_number_string(UC const *p, UC const *pend, // We need to be mindful of the case where we only have zeroes... // E.g., 0.000000000...000. UC const *start = start_digits; - do { // we already have some numbers, so we can skip first check safely - if ((*start == UC('0') || *start == options.decimal_point)) { - if (*start == UC('0')) { - --digit_count; - } + while ((start != pend) && + (*start == UC('0') || *start == options.decimal_point)) { + if (*start == UC('0')) { + --digit_count; } - } while (++start != pend); + ++start; + } // We have to check if we have a number with more than 19 significant // digits. From a55041531431f0063c6f778bd4d39cd8e1f8e123 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 22:55:48 +0300 Subject: [PATCH 126/252] additional fix for bfloat16_t. Sorry, I can't compile it's locally. --- include/fast_float/float_common.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 378ce222..2c5a2ca8 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -232,8 +232,7 @@ using parse_options = parse_options_t; namespace fast_float { -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -cpp20_and_in_constexpr() noexcept { +fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED return std::is_constant_evaluated(); #else @@ -922,7 +921,7 @@ binary_format::smallest_power_of_ten() { } template <> -inline constexpr uint16_t binary_format::max_digits() { +inline constexpr am_digits binary_format::max_digits() { return 98; } #endif // __STDCPP_BFLOAT16_T__ From 978441a5bbc5f6fd33bda763c7e24eb4dfc982d1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 7 May 2025 23:19:18 +0300 Subject: [PATCH 127/252] additional FASTFLOAT_HAS_BIT_CAST improve for older standards. --- include/fast_float/float_common.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2c5a2ca8..eae56f96 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1045,7 +1045,11 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); #endif #if FASTFLOAT_HAS_BIT_CAST - value = std::bit_cast(word); + value = +#if FASTFLOAT_HAS_BIT_CAST == 1 + std:: +#endif + bit_cast(word); #else ::memcpy(&value, &word, sizeof(T)); #endif From 437a80ccfdd7c54e0f5aa42ee94952bca54ff11b Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 8 May 2025 18:19:45 +0300 Subject: [PATCH 128/252] fix for type usage in parse_int_string --- include/fast_float/ascii_number.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 5432d16e..da13a242 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -20,7 +20,8 @@ namespace fast_float { -template fastfloat_really_inline constexpr bool has_simd_opt() { +template +fastfloat_really_inline constexpr bool has_simd_opt() noexcept { #ifdef FASTFLOAT_HAS_SIMD return std::is_same::value; #else @@ -36,7 +37,7 @@ fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { } #if FASTFLOAT_HAS_BYTESWAP == 0 -fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { +fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) noexcept { return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 | (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 | (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | @@ -123,7 +124,7 @@ uint64_t simd_read8_to_u64(UC const *) { // credit @aqrit fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t -parse_eight_digits_unrolled(uint64_t val) { +parse_eight_digits_unrolled(uint64_t val) noexcept { uint64_t const mask = 0x000000FF000000FF; uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) @@ -530,6 +531,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const first = p; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + // Read sign bool const negative = (*p == UC('-')); #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(push) @@ -552,6 +554,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_num = p; + // Skip leading zeros while (p != pend && *p == UC('0')) { ++p; } @@ -560,6 +563,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_digits = p; + // Parse digits uint64_t i = 0; if (options.base == 10) { loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible @@ -573,7 +577,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, p++; } - uint16_t const digit_count = static_cast(p - start_digits); + am_digits const digit_count = static_cast(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { From 5ae2fba79d8e270a25fbf972f7cbdb91041ae29d Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 10 May 2025 19:59:22 +0300 Subject: [PATCH 129/252] cleanup for parse_number_string --- include/fast_float/ascii_number.h | 16 ++++++++-------- include/fast_float/parse_number.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index da13a242..e7e9e70f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -268,7 +268,7 @@ template struct parsed_number_string_t { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif - bool valid{false}; + bool invalid{false}; bool too_many_digits{false}; // contains the range of the significant digits span integer{}; // non-nullable @@ -283,7 +283,7 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t report_parse_error(UC const *p, parse_error error) noexcept { parsed_number_string_t answer; - answer.valid = false; + answer.invalid = true; answer.lastmatch = p; answer.error = error; return answer; @@ -299,7 +299,8 @@ parse_number_string(UC const *p, UC const *pend, // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. parsed_number_string_t answer; - FASTFLOAT_ASSUME(p < pend); // so dereference without checks; + // so dereference without checks + FASTFLOAT_ASSUME(p < pend); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); if (answer.negative || @@ -312,15 +313,15 @@ parse_number_string(UC const *p, UC const *pend, p, parse_error::missing_integer_or_dot_after_sign); } FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { - if (!is_integer(*p)) { // a sign must be followed by an integer + // a sign must be followed by an integer + if (!is_integer(*p)) { return report_parse_error(p, parse_error::missing_integer_after_sign); } } else { - if (!is_integer(*p) && - (*p != options.decimal_point)) { // a sign must be followed by an - // integer or the dot + // a sign must be followed by an integer or the dot + if (!is_integer(*p) && (*p != options.decimal_point)) { return report_parse_error( p, parse_error::missing_integer_or_dot_after_sign); } @@ -459,7 +460,6 @@ parse_number_string(UC const *p, UC const *pend, // We parsed all parts of the number, let's save progress. answer.lastmatch = p; - answer.valid = true; // Now we can check for errors. diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index df079ba0..306c7357 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -337,7 +337,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, : #endif parse_number_string(first, last, options); - if (!pns.valid) { + if (pns.invalid) { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (chars_format_t(options.format & chars_format::no_infnan)) { #endif From 42131710b78c6e97637e5b82a529906b4ea632fa Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 12 May 2025 15:28:42 +0300 Subject: [PATCH 130/252] compilation fix for internal tests --- tests/json_fmt.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index c210a451..6a17dc62 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -10,7 +10,7 @@ int main_readme() { fast_float::parse_options options{ fast_float::chars_format::json | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( + auto const answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -25,7 +25,7 @@ int main_readme2() { fast_float::parse_options options{ fast_float::chars_format::json | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( + auto const answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -41,7 +41,7 @@ int main_readme3() { fast_float::parse_options options{ fast_float::chars_format::json_or_infnan | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto answer = fast_float::from_chars_advanced( + auto const answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; @@ -97,7 +97,7 @@ int main() { auto const &s = accept[i].input; auto const &expected = accept[i].expected; double result; - auto answer = + auto const answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, fast_float::chars_format::json_or_infnan); if (answer.ec != std::errc()) { @@ -120,7 +120,7 @@ int main() { for (std::size_t i = 0; i < reject.size(); ++i) { auto const &s = reject[i].input; double result; - auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, + auto const answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, fast_float::chars_format::json); if (answer.ec == std::errc()) { std::cerr << "json fmt accepted invalid json " << s << std::endl; @@ -131,13 +131,13 @@ int main() { for (std::size_t i = 0; i < reject.size(); ++i) { auto const &f = reject[i].input; auto const &expected_reason = reject[i].reason; - auto answer = fast_float::parse_number_string( + auto const answer = fast_float::parse_number_string( f.data(), f.data() + f.size(), fast_float::parse_options( fast_float::chars_format::json | fast_float::chars_format::allow_leading_plus)); // should be // ignored - if (answer.valid) { + if (!answer.invalid) { std::cerr << "json parse accepted invalid json " << f << std::endl; return EXIT_FAILURE; } From a72afb539fa77fb169c51b2d33c43f21190626a2 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 12 May 2025 16:45:40 +0300 Subject: [PATCH 131/252] unfck clang format --- tests/json_fmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index 6a17dc62..ca4b46b6 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -120,8 +120,8 @@ int main() { for (std::size_t i = 0; i < reject.size(); ++i) { auto const &s = reject[i].input; double result; - auto const answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, - fast_float::chars_format::json); + auto const answer = fast_float::from_chars( + s.data(), s.data() + s.size(), result, fast_float::chars_format::json); if (answer.ec == std::errc()) { std::cerr << "json fmt accepted invalid json " << s << std::endl; return EXIT_FAILURE; From 0cdbf36d787164d00200ad3e79714826ebcbecf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 04:14:24 +0000 Subject: [PATCH 132/252] Bump actions/checkout from 4 to 5 in the github-actions group Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 4 to 5 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu20.yml | 2 +- .github/workflows/lint_and_format_check.yml | 2 +- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu20-cxx20.yml | 2 +- .github/workflows/ubuntu20-fastmath.yml | 2 +- .github/workflows/ubuntu20.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 2 +- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index 85291dfa..9b24bdef 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu20.yml b/.github/workflows/amalgamate-ubuntu20.yml index af738691..9012e18a 100644 --- a/.github/workflows/amalgamate-ubuntu20.yml +++ b/.github/workflows/amalgamate-ubuntu20.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index b56bc066..ce6a2af5 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,7 +24,7 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 + - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 - name: Run clang-format uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0 diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index fca8ab7d..7697bb59 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 86be5244..4bd814e6 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 47024dc8..26ef5d58 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 9eaad27e..6bdc2be7 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu20-cxx20.yml b/.github/workflows/ubuntu20-cxx20.yml index ff226c7d..953eec90 100644 --- a/.github/workflows/ubuntu20-cxx20.yml +++ b/.github/workflows/ubuntu20-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu20-fastmath.yml b/.github/workflows/ubuntu20-fastmath.yml index a2d7b6db..5427f83c 100644 --- a/.github/workflows/ubuntu20-fastmath.yml +++ b/.github/workflows/ubuntu20-fastmath.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu20.yml b/.github/workflows/ubuntu20.yml index f0a8b6f3..c3627d53 100644 --- a/.github/workflows/ubuntu20.yml +++ b/.github/workflows/ubuntu20.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index ad335f1d..f8af4374 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index af7f8b90..91abf7ce 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index 18a4c266..08fe8d73 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index ccf912ec..71543954 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 3dad9dd3..511c7ce3 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index 0bdf5793..6769a2a4 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 81431ad8..9f8546b8 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index f7e6ba86..56b51611 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index b35b06a0..aecbca8f 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From e3aa99448abe7c712ec7e41917e7be01a927a389 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 16 Sep 2025 21:45:58 +0300 Subject: [PATCH 133/252] # fix for stackvec constructor. --- include/fast_float/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 3fb18467..dc4db71b 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -39,7 +39,7 @@ constexpr limb_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. template struct stackvec { - limb data[size]; + limb data[size] = {0}; // we never need more than 150 limbs uint_fast8_t length{0}; From 10970dbbaeb7d9bbb9654c8a2e94e1d67b2cecdc Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 17 Sep 2025 00:52:26 +0300 Subject: [PATCH 134/252] # cleanup --- include/fast_float/ascii_number.h | 12 ++++++------ include/fast_float/float_common.h | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 2e5a79e4..ab3908ff 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -52,7 +52,7 @@ read8_to_u64(UC const *chars) { if (cpp20_and_in_constexpr() || !std::is_same::value) { uint64_t val = 0; for (uint_fast8_t i = 0; i != 8; ++i) { - val |= uint64_t(uint_fast8_t(*chars)) << (i * 8); + val |= uint64_t(uint8_t(*chars)) << (i * 8); ++chars; } return val; @@ -72,7 +72,7 @@ read8_to_u64(UC const *chars) { #ifdef FASTFLOAT_SSE2 -fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS __m128i const packed = _mm_packus_epi16(data, data); #ifdef FASTFLOAT_64BIT @@ -95,7 +95,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { #elif defined(FASTFLOAT_NEON) -fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS uint8x8_t utf8_packed = vmovn_u16(data); return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); @@ -125,9 +125,9 @@ uint64_t simd_read8_to_u64(UC const *) { // credit @aqrit fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t parse_eight_digits_unrolled(uint64_t val) noexcept { - uint64_t const mask = 0x000000FF000000FF; - uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) - uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) + constexpr uint64_t mask = 0x000000FF000000FF; + constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + constexpr uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) val -= 0x3030303030303030; val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 66b66ace..7c9d3670 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,7 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { // Value of the mantissa. typedef uint_fast64_t am_mant_t; -// Size of bits in the mantissa and path and roundings shifts +// Size of bits in the mantissa and path and rounding shifts typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float @@ -461,11 +461,11 @@ struct adjusted_mantissa { am_pow_t power2; adjusted_mantissa() noexcept = default; - 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; } - 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; } }; @@ -1041,7 +1041,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool const negative, #endif - adjusted_mantissa const am, T &value) noexcept { + adjusted_mantissa const &am, T &value) noexcept { using equiv_uint = equiv_uint_t; equiv_uint word = equiv_uint(am.mantissa); word = equiv_uint(word | equiv_uint(am.power2) From 329282003d6251fead63e2fa0dca53f581aa8902 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 18 Sep 2025 22:18:36 +0300 Subject: [PATCH 135/252] * Readme updated. --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 17e7b121..1acc7bda 100644 --- a/README.md +++ b/README.md @@ -404,7 +404,7 @@ out of range. Overloads of `fast_float::integer_times_pow10()` are provided for signed and unsigned integer types: `int64_t`, `uint64_t`, etc. -You also can use not standard options: +## You also can use additional options, like allow_leading_plus and skip_white_space: ```C++ #include "fast_float/fast_float.h" @@ -420,10 +420,9 @@ int main() { } ``` -For special case scenarious, like mathematical or other AST like parcer that already process minus sign -and only pasre in FastFloat positive numbers in fixed, scientific or hex format and do not have inf or nan -in input you can use macros FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN that significantly reduce -the code size and improve performance: +## For mathematical or other AST like parcers that already process sign and all other symbols before any number by itself +you can use FastFloat for only parse positive numbers in fixed, scientific or hex format with macros +FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN, that significantly reduce the code size and improve performance: ```C++ #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 097800a609aa59d7495d7ff2474fb73a3b7872a1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 18 Sep 2025 22:41:24 +0300 Subject: [PATCH 136/252] # compilation fix after merge from upstream. --- include/fast_float/parse_number.h | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index af08b801..c132ff20 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -250,14 +250,14 @@ clinger_fast_path_impl(uint64_t const mantissa, int64_t const exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is_negative ? T(-0.) : #endif - T(0.); + T(0.); return true; } #endif - value = T(pns.mantissa) * - binary_format::exact_power_of_ten(pns.exponent); + value = T(mantissa) * + binary_format::exact_power_of_ten(exponent); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - if (pns.negative) { + if (is_negative) { value = -value; } #endif @@ -276,7 +276,7 @@ clinger_fast_path_impl(uint64_t const mantissa, int64_t const exponent, */ template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { +from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); static_assert(is_supported_char_type::value, @@ -287,12 +287,11 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { answer.ec = std::errc(); // be optimistic answer.ptr = pns.lastmatch; - if (!pns.too_many_digits && - clinger_fast_path_impl(pns.mantissa, pns.exponent, + if (!pns.too_many_digits && clinger_fast_path_impl(pns.mantissa, pns.exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - pns.negative, + pns.negative, #endif - value)) + value)) return answer; adjusted_mantissa am = @@ -387,7 +386,8 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcept { +integer_times_pow10(uint64_t const mantissa, + int const decimal_exponent) noexcept { double value; if (clinger_fast_path_impl(mantissa, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -400,14 +400,15 @@ integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcep compute_float>(decimal_exponent, mantissa); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - false, + false, #endif - am, value); + am, value); return value; } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept { +integer_times_pow10(int64_t const mantissa, + int const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); const uint64_t m = static_cast(mantissa); @@ -427,9 +428,9 @@ integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept compute_float>(decimal_exponent, m); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - is_negative, + is_negative, #endif - am, value); + am, value); return value; } From 384fcec12dac0e2e987d99a12d65560e8991a4fd Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 18 Sep 2025 22:57:06 +0300 Subject: [PATCH 137/252] # clang format --- include/fast_float/fast_float.h | 6 ++++-- include/fast_float/parse_number.h | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 1d13815a..08a1a441 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -59,9 +59,11 @@ from_chars_advanced(UC const *first, UC const *last, T &value, * `new` or `malloc`). */ FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcept; +integer_times_pow10(uint64_t const mantissa, + int const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept; +integer_times_pow10(int64_t const mantissa, + int const decimal_exponent) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index c132ff20..8a310ced 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -254,8 +254,7 @@ clinger_fast_path_impl(uint64_t const mantissa, int64_t const exponent, return true; } #endif - value = T(mantissa) * - binary_format::exact_power_of_ten(exponent); + value = T(mantissa) * binary_format::exact_power_of_ten(exponent); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (is_negative) { value = -value; From fe376285c7a4ecd19855379087fbdb6c08309f52 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 18 Sep 2025 23:57:54 +0300 Subject: [PATCH 138/252] # types fix after merge from upstream. --- include/fast_float/parse_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 8a310ced..f7096a66 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -197,7 +197,7 @@ from_chars(UC const *first, UC const *last, T &value, template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool -clinger_fast_path_impl(uint64_t const mantissa, int64_t const exponent, +clinger_fast_path_impl(am_mant_t const mantissa, am_pow_t const exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool const is_negative, #endif From c7e0786a8792e793a9ede101d36514d82d2242cf Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Fri, 19 Sep 2025 19:37:48 +0300 Subject: [PATCH 139/252] Update README.md --- README.md | 74 ++++++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 1acc7bda..70fa721b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ struct from_chars_result { }; ``` -It parses the character sequence `[first, last)` for a number. It parses +It parses the character sequence `[first, last]` for a number. It parses floating-point numbers expecting a locale-independent format equivalent to the C++17 from_chars function. The resulting floating-point value is the closest floating-point values (using either `float` or `double`), using the "round to @@ -48,7 +48,8 @@ parsed value. In case of error, the returned `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored. The implementation does not throw and does not allocate memory (e.g., with `new` -or `malloc`). +or `malloc`) and can be usable in the kernel, embeded and other scenarious that +relays on such behavior. It will parse infinity and nan values. @@ -288,7 +289,7 @@ int main() { } ``` -## Advanced options: using commas as decimal separator, JSON and Fortran +## Advanced options: using commas as decimal separator, parse JSON, Fortran and more The C++ standard stipulate that `from_chars` has to be locale-independent. In particular, the decimal separator has to be the period (`.`). However, some @@ -377,6 +378,32 @@ int main() { } ``` +## You also can also use some additional options (currently only configure by macroses): + +There is a really common use case in mathematical and other abstract syntax tree (AST) like parsers, +that already process sign and all other symbols before any number by itself. In this case you can +use FastFloat for only parse positive numbers in all supported formats with macros +`FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, that significantly reduce the code size and improve +performance. Additionally you can use macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you +only uneed `FE_TONEAREST` rounding mode in the parsing: this option is also improve performance a bit. + +```C++ +#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED +#include "fast_float/fast_float.h" +#include + +int main() { + std::string input = "23.14069263277926900572"; + double result; + auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); + if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) + { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } + + return EXIT_SUCCESS; +} +``` + ## Multiplication of an integer by a power of 10 An integer `W` can be multiplied by a power of ten `10^Q` and converted to `double` with correctly rounded value @@ -404,47 +431,6 @@ out of range. Overloads of `fast_float::integer_times_pow10()` are provided for signed and unsigned integer types: `int64_t`, `uint64_t`, etc. -## You also can use additional options, like allow_leading_plus and skip_white_space: - -```C++ -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = " +456"; - double result; - fast_float::parse_options options{chars_format::allow_leading_plus | chars_format::skip_white_space}; - auto answer = fast_float::from_chars_advanced(input.data(), input.data() + input.size(), result, options); - if ((answer.ec != std::errc()) || ((result != 456))) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; -} -``` - -## For mathematical or other AST like parcers that already process sign and all other symbols before any number by itself -you can use FastFloat for only parse positive numbers in fixed, scientific or hex format with macros -FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN, that significantly reduce the code size and improve performance: - -```C++ -#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -#include "fast_float/fast_float.h" -#include - -int main() { - std::string input = "23.14069263277926900572"; - double result; - auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); - if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) - { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - input = "-23.14069263277926900572"; - if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on any sign\n"; return EXIT_FAILURE; } - input = "inf"; - if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on infinity\n"; return EXIT_FAILURE; } - input = "nan"; - if (answer.ec == std::errc()) { std::cerr << "parsing failure, should failed on nan in input\n"; return EXIT_FAILURE; } - return EXIT_SUCCESS; -} -``` - ## Users and Related Work The fast_float library is part of: From 9f4be55249e358de4699543bb5f93c58d3e69c93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 02:28:13 +0000 Subject: [PATCH 140/252] Bump the github-actions group across 1 directory with 3 updates Bumps the github-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [github/codeql-action](https://github.com/github/codeql-action) and [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/checkout` from 4 to 5 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v5) Updates `github/codeql-action` from 3 to 4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v3...v4) Updates `actions/setup-node` from 4.4.0 to 5.0.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/49933ea5288caeca8642d1e84afbd3f7d6820020...a0853c24544627f65ddf259abe73b1d18a591444) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: github/codeql-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 2 +- .github/workflows/risc.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index fac5cee3..4d9f67b0 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -27,7 +27,7 @@ jobs: path: ./out/artifacts - name: Upload Sarif if: always() && steps.build.outcome == 'success' - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: # Path to SARIF file relative to the root of the repository sarif_file: cifuzz-sarif/results.sarif diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 1b00f447..c5dc90ad 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index 68e26cb4..8bc85588 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install packages run: | sudo apt-get update -q -y From 72e75ed98f133fae7aff734db2ff53606dd5ce0e Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 16:16:18 +0300 Subject: [PATCH 141/252] # compilation fix after merge. --- include/fast_float/digit_comparison.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index a0d5882c..0380df70 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -38,7 +38,6 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL, // this algorithm is not even close to optimized, but it has no practical // 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. -template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_pow_t scientific_exponent(am_mant_t mantissa, am_pow_t exponent) noexcept { while (mantissa >= 10000) { @@ -450,7 +449,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( // remove the invalid exponent bias am.power2 -= invalid_am_bias; - am_pow_t const sci_exp = scientific_exponent(num); + am_pow_t const sci_exp = scientific_exponent(num.mantissa, num.exponent); bigint bigmant; am_digits const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. From 240d393bf63bd2fdbd3d5046a49eb7b1b0f063c1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 16:25:35 +0300 Subject: [PATCH 142/252] # format --- include/fast_float/parse_number.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 814f7ec1..0d2e221d 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -387,7 +387,8 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t mantissa, int const decimal_exponent) noexcept { + integer_times_pow10(uint64_t mantissa, + int const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 3288e56b34aa7a4e731a9b574bb20611fb6c0c4a Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 18:18:20 +0300 Subject: [PATCH 143/252] # compilation fix after merge --- include/fast_float/parse_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 0d2e221d..027a7231 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -418,7 +418,7 @@ FASTFLOAT_CONSTEXPR20 const bool is_negative = mantissa < 0; const uint64_t m = static_cast(is_negative ? -mantissa : mantissa); #endif - double value; + T value; if (clinger_fast_path_impl(m, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is_negative, From 031f7febbe2b303d16d3203ae1c3504713a894e6 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 19:31:28 +0300 Subject: [PATCH 144/252] # tests are updated --- tests/basictest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 1a5537bb..33370754 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -69,7 +69,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -char const *round_name(int d) { +const std::string_view round_name(int const d) { switch (d) { case FE_UPWARD: return "FE_UPWARD"; @@ -2313,7 +2313,7 @@ TEST_CASE("integer_times_pow10") { for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) { fesetround(mode); - INFO("fesetround(): " << std::string{round_name(mode)}); + INFO("fesetround(): " << round_name(mode)); struct Guard { ~Guard() { fesetround(FE_TONEAREST); } From 1dc13a91f1177bb255a48486f63d2e41a188a9bb Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 19:56:43 +0300 Subject: [PATCH 145/252] # improve checking for integer in the FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN mode. --- include/fast_float/fast_float.h | 4 ++-- include/fast_float/parse_number.h | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index a18266fd..c1201e55 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -73,11 +73,11 @@ integer_times_pow10(int64_t const mantissa, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t mantissa, int decimal_exponent) noexcept; + integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t mantissa, int decimal_exponent) noexcept; + integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 027a7231..fed56058 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -387,7 +387,7 @@ from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t mantissa, + integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, @@ -410,7 +410,7 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t mantissa, int const decimal_exponent) noexcept { + integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); const uint64_t m = static_cast(mantissa); @@ -494,23 +494,27 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + // We are in parser code with external loop that checks bounds. + FASTFLOAT_ASSUME(first < last); + // base is already checked in the parse_options_t constructor. +#else if (chars_format_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { ++first; } } - if (first == last || options.base < 2 || options.base > 36) { +#endif + if ( +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + first == last || +#endif + options.base < 2 || options.base > 36) { from_chars_result_t answer; answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } -#else - // We are in parser code with external loop that checks bounds. - FASTFLOAT_ASSUME(first < last); - // base is already checked in the parse_options_t constructor. -#endif return parse_int_string(first, last, value, options); } From fe0bce5eb7e810a8d21182a47ef3ff7d3d5329de Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 21:08:08 +0300 Subject: [PATCH 146/252] # const and constexpr fixes # types fixes. # FASTFLOAT_ASSERT fix. --- include/fast_float/digit_comparison.h | 4 ++-- include/fast_float/fast_table.h | 10 +++++----- include/fast_float/float_common.h | 7 +++---- include/fast_float/parse_number.h | 5 +++-- tests/basictest.cpp | 27 ++++++++++++++++----------- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 0380df70..78ec5de2 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -270,9 +270,9 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { am_digits digits = 0; limb value = 0; #ifdef FASTFLOAT_64BIT_LIMB - am_digits const step = 19; + constexpr am_digits step = 19; #else - am_digits const step = 9; + constexpr am_digits step = 9; #endif // process all integer digits. diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index 69f9b2c9..536e1499 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -31,14 +31,14 @@ namespace fast_float { */ template struct powers_template { - constexpr static int smallest_power_of_five = + constexpr static am_pow_t smallest_power_of_five = binary_format::smallest_power_of_ten(); - constexpr static int largest_power_of_five = + constexpr static am_pow_t largest_power_of_five = binary_format::largest_power_of_ten(); - constexpr static int number_of_entries = + constexpr static am_digits number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1); // Powers of five from 5^-342 all the way to 5^308 rounded toward one. - constexpr static uint64_t power_of_five_128[number_of_entries] = { + constexpr static am_mant_t power_of_five_128[number_of_entries] = { 0xeef453d6923bd65a, 0x113faa2906a13b3f, 0x9558b4661b6565f8, 0x4ac7ca59a424c507, 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, @@ -696,7 +696,7 @@ template struct powers_template { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE template -constexpr uint64_t +constexpr am_mant_t powers_template::power_of_five_128[number_of_entries]; #endif diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 66a96d9d..e34c4e09 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -83,7 +83,9 @@ template struct parse_options_t { constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), uint_fast8_t const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) {} + : format(fmt), decimal_point(dot), base(b) { + FASTFLOAT_ASSUME(base >= 2 && base <= 36); + } /** Which number formats are accepted */ chars_format format; @@ -91,7 +93,6 @@ template struct parse_options_t { UC decimal_point; /** The base used for integers */ uint_fast8_t base; /* only allowed from 2 to 36 */ - FASTFLOAT_ASSUME(base >= 2 && base <= 36); }; using parse_options = parse_options_t; @@ -214,7 +215,6 @@ using parse_options = parse_options_t; #define FASTFLOAT_ASSERT(x) \ { \ ((void)(x)); \ - FASTFLOAT_ASSUME(x); \ } #endif @@ -222,7 +222,6 @@ using parse_options = parse_options_t; #define FASTFLOAT_DEBUG_ASSERT(x) \ { \ ((void)(x)); \ - FASTFLOAT_ASSUME(x); \ } #endif diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index fed56058..fd76edab 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -437,12 +437,13 @@ FASTFLOAT_CONSTEXPR20 } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t mantissa, int const decimal_exponent) noexcept { +integer_times_pow10(uint64_t const mantissa, + int const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t mantissa, int const decimal_exponent) noexcept { +integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 33370754..671ec3df 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -2126,8 +2126,9 @@ TEST_CASE("bfloat16.general") { #endif template -void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent, - T actual, U expected) { +void verify_integer_times_pow10_result(Int const mantissa, + int const decimal_exponent, + T const actual, U const expected) { static_assert(std::is_same::value, "expected and actual types must match"); @@ -2144,8 +2145,8 @@ void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent, } template -T calculate_integer_times_pow10_expected_result(Int mantissa, - int decimal_exponent) { +T calculate_integer_times_pow10_expected_result(Int const mantissa, + int const decimal_exponent) { std::string constructed_string = std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); T expected_result; @@ -2158,8 +2159,9 @@ T calculate_integer_times_pow10_expected_result(Int mantissa, } template -void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent, - double expected) { +void verify_integer_times_pow10_dflt(Int const mantissa, + int const decimal_exponent, + double const expected) { static_assert(std::is_integral::value); // the "default" overload @@ -2171,7 +2173,8 @@ void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent, } template -void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) { +void verify_integer_times_pow10_dflt(Int const mantissa, + int const decimal_exponent) { static_assert(std::is_integral::value); const auto expected_result = @@ -2182,8 +2185,8 @@ void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) { } template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent, - T expected) { +void verify_integer_times_pow10(Int const mantissa, int const decimal_exponent, + T const expected) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2196,7 +2199,8 @@ void verify_integer_times_pow10(Int mantissa, int decimal_exponent, } template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { +void verify_integer_times_pow10(Int const mantissa, + int const decimal_exponent) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2208,7 +2212,8 @@ void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { namespace all_supported_types { template -void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { +void verify_integer_times_pow10(Int const mantissa, + int const decimal_exponent) { static_assert(std::is_integral::value); // verify the "default" overload From 5a378ed87ff81e29dc5a556cedec04436c889986 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 21:14:58 +0300 Subject: [PATCH 147/252] # minimize diff in the crutch. --- include/fast_float/digit_comparison.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 78ec5de2..3041fe7a 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -378,22 +378,20 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( bigint &real_digits = bigmant; am_pow_t const &real_exp = exponent; + // get the value of `b`, rounded down, and get a bigint representation of + // b+h + adjusted_mantissa am_b = am; + // gcc7 bug: use a lambda to remove the noexcept qualifier bug with + // -Wnoexcept-type. + round(am_b, [](adjusted_mantissa &a, am_pow_t shift) { + round_down(a, shift); + }); T b; - { - // get the value of `b`, rounded down, and get a bigint representation of - // b+h - adjusted_mantissa am_b = am; - // gcc7 bug: use a lambda to remove the noexcept qualifier bug with - // -Wnoexcept-type. - round(am_b, [](adjusted_mantissa &a, am_pow_t shift) { - round_down(a, shift); - }); - to_float( + to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - false, + false, #endif - am_b, b); - } + am_b, b); adjusted_mantissa theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); am_pow_t theor_exp = theor.power2; From 0e123c5e82da793788f7353b2c5863d59e55f9f2 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 21:31:19 +0300 Subject: [PATCH 148/252] # fix for digit_comp. --- include/fast_float/digit_comparison.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 3041fe7a..ca5f1033 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -346,16 +346,17 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( - bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { + bigint &bigmant, am_pow_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(exponent)); + adjusted_mantissa answer; bool truncated; - am.mantissa = bigmant.hi64(truncated); + answer.mantissa = bigmant.hi64(truncated); constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - am.power2 = + answer.power2 = static_cast(bigmant.bit_length() - 64 + bias); - round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { + round(answer, [truncated](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { @@ -364,7 +365,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( }); }); - return am; + return answer; } // the scaling here is quite simple: we have, for the real digits `m * 10^e`, @@ -410,6 +411,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // compare digits, and use it to direct rounding int ord = real_digits.compare(theor_digits); + adjusted_mantissa answer = am; round(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { @@ -425,7 +427,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( }); }); - return am; + return answer; } // parse the significant digits as a big integer to unambiguously round @@ -454,7 +456,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am_pow_t const exponent = static_cast(sci_exp + 1 - static_cast(digits)); if (exponent >= 0) { - return positive_digit_comp(bigmant, am, exponent); + return positive_digit_comp(bigmant, exponent); } else { return negative_digit_comp(bigmant, am, exponent); } From 487799ede2bcb8d444aafc5f27bcb21469a371bb Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 21:49:21 +0300 Subject: [PATCH 149/252] # cleanup and speedup digit_comp. --- include/fast_float/digit_comparison.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index ca5f1033..2e8f2fd9 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -345,18 +345,18 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { } template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( - bigint &bigmant, am_pow_t const exponent) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +positive_digit_comp( + bigint &bigmant, adjusted_mantissa& am, am_pow_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(exponent)); - adjusted_mantissa answer; bool truncated; - answer.mantissa = bigmant.hi64(truncated); + am.mantissa = bigmant.hi64(truncated); constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - answer.power2 = + am.power2 = static_cast(bigmant.bit_length() - 64 + bias); - round(answer, [truncated](adjusted_mantissa &a, am_pow_t shift) { + round(am, [truncated](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { @@ -365,7 +365,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( }); }); - return answer; + return am; } // the scaling here is quite simple: we have, for the real digits `m * 10^e`, @@ -374,8 +374,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +negative_digit_comp( + bigint &bigmant, adjusted_mantissa& am, am_pow_t const exponent) noexcept { bigint &real_digits = bigmant; am_pow_t const &real_exp = exponent; @@ -411,7 +412,6 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // compare digits, and use it to direct rounding int ord = real_digits.compare(theor_digits); - adjusted_mantissa answer = am; round(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { @@ -427,7 +427,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( }); }); - return answer; + return am; } // parse the significant digits as a big integer to unambiguously round @@ -445,7 +445,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( // of both, and use that to direct rounding. template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( - parsed_number_string_t const &num, adjusted_mantissa am) noexcept { + parsed_number_string_t const &num, adjusted_mantissa& am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; @@ -456,7 +456,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( am_pow_t const exponent = static_cast(sci_exp + 1 - static_cast(digits)); if (exponent >= 0) { - return positive_digit_comp(bigmant, exponent); + return positive_digit_comp(bigmant, am, exponent); } else { return negative_digit_comp(bigmant, am, exponent); } From 336b97d027315e165c41ab7d81cdcd579e4506f4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 22:01:22 +0300 Subject: [PATCH 150/252] # cleanup. --- include/fast_float/digit_comparison.h | 17 +++++++---------- include/fast_float/fast_float.h | 6 ++++-- include/fast_float/float_common.h | 8 ++------ include/fast_float/parse_number.h | 6 ++++-- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 2e8f2fd9..475bf29a 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -345,9 +345,8 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { } template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -positive_digit_comp( - bigint &bigmant, adjusted_mantissa& am, am_pow_t const exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( + bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(exponent)); bool truncated; am.mantissa = bigmant.hi64(truncated); @@ -374,9 +373,8 @@ positive_digit_comp( // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -negative_digit_comp( - bigint &bigmant, adjusted_mantissa& am, am_pow_t const exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( + bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { bigint &real_digits = bigmant; am_pow_t const &real_exp = exponent; @@ -385,9 +383,8 @@ negative_digit_comp( adjusted_mantissa am_b = am; // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. - round(am_b, [](adjusted_mantissa &a, am_pow_t shift) { - round_down(a, shift); - }); + round(am_b, + [](adjusted_mantissa &a, am_pow_t shift) { round_down(a, shift); }); T b; to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -445,7 +442,7 @@ negative_digit_comp( // of both, and use that to direct rounding. template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( - parsed_number_string_t const &num, adjusted_mantissa& am) noexcept { + parsed_number_string_t const &num, adjusted_mantissa am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index c1201e55..8d1d137a 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -73,11 +73,13 @@ integer_times_pow10(int64_t const mantissa, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t const mantissa, int const decimal_exponent) noexcept; + integer_times_pow10(uint64_t const mantissa, + int const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept; + integer_times_pow10(int64_t const mantissa, + int const decimal_exponent) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index e34c4e09..078717fd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -213,16 +213,12 @@ using parse_options = parse_options_t; #ifndef FASTFLOAT_ASSERT #define FASTFLOAT_ASSERT(x) \ - { \ - ((void)(x)); \ - } + { ((void)(x)); } #endif #ifndef FASTFLOAT_DEBUG_ASSERT #define FASTFLOAT_DEBUG_ASSERT(x) \ - { \ - ((void)(x)); \ - } + { ((void)(x)); } #endif // rust style `try!()` macro, or `?` operator diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index fd76edab..e527dad6 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -410,7 +410,8 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept { + integer_times_pow10(int64_t const mantissa, + int const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); const uint64_t m = static_cast(mantissa); @@ -443,7 +444,8 @@ integer_times_pow10(uint64_t const mantissa, } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t const mantissa, int const decimal_exponent) noexcept { +integer_times_pow10(int64_t const mantissa, + int const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } From eee068d3bca57c4575c9846eb5f6a1c3ac419aa4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 22:19:04 +0300 Subject: [PATCH 151/252] # types fix. --- include/fast_float/float_common.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 078717fd..2801437e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -473,7 +473,7 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - static constexpr am_bits_t mantissa_explicit_bits(); + static constexpr limb_t mantissa_explicit_bits(); static constexpr am_pow_t minimum_exponent(); static constexpr am_pow_t infinite_power(); static constexpr am_bits_t sign_index(); @@ -596,12 +596,12 @@ inline constexpr am_bits_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { +inline constexpr limb_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { +inline constexpr limb_t binary_format::mantissa_explicit_bits() { return 23; } @@ -730,7 +730,7 @@ binary_format::max_exponent_fast_path() { } template <> -inline constexpr am_bits_t +inline constexpr limb_t binary_format::mantissa_explicit_bits() { return 10; } @@ -857,7 +857,7 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr am_bits_t +inline constexpr limb_t binary_format::mantissa_explicit_bits() { return 7; } From 1f0e2819e0deb5c14ac718a26117afacbc6808fe Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 21 Oct 2025 22:40:41 +0300 Subject: [PATCH 152/252] # type usage fix. --- include/fast_float/parse_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index e527dad6..c8e465e8 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -414,10 +414,10 @@ FASTFLOAT_CONSTEXPR20 int const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); - const uint64_t m = static_cast(mantissa); + const am_mant_t m = static_cast(mantissa); #else const bool is_negative = mantissa < 0; - const uint64_t m = static_cast(is_negative ? -mantissa : mantissa); + const am_mant_t m = static_cast(is_negative ? -mantissa : mantissa); #endif T value; if (clinger_fast_path_impl(m, decimal_exponent, From 58b5dc04c3a69f90337a42a92dc57ea2f52f002c Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 00:27:36 +0300 Subject: [PATCH 153/252] * Upgrade manually vectorized code to SSE4.2 for FASTFLOAT_64BIT because it's already used SSE4.1 instructions. --- include/fast_float/ascii_number.h | 33 +++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index ab3908ff..a3ebc89c 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -74,9 +74,10 @@ read8_to_u64(UC const *chars) { fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS + // _mm_packus_epi16 is SSE4.1+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); #ifdef FASTFLOAT_64BIT - return uint64_t(_mm_cvtsi128_si64(packed)); + return static_cast(_mm_cvtsi128_si64(packed)); #else uint64_t value; // Visual Studio + older versions of GCC don't support _mm_storeu_si64 @@ -109,7 +110,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { FASTFLOAT_SIMD_RESTORE_WARNINGS } -#endif // FASTFLOAT_SSE2 +#endif // MSVC SFINAE is broken pre-VS2017 #if defined(_MSC_VER) && _MSC_VER <= 1900 @@ -164,20 +165,40 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, } #ifdef FASTFLOAT_SSE2 FASTFLOAT_SIMD_DISABLE_WARNINGS + // Load 8 UTF-16 characters (16 bytes) __m128i const data = _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); - // (x - '0') <= 9 +#ifdef FASTFLOAT_64BIT + // --- Digit range check using SSE4.2 comparisons --- + // Validate: '0' (0x30) ≤ x ≤ '9' (0x39) + const __m128i ascii0 = _mm_set1_epi16(u'0'); + const __m128i ascii9 = _mm_set1_epi16(u'9'); + + __m128i below0 = _mm_cmplt_epi16(data, ascii0); // x < '0' + __m128i above9 = _mm_cmpgt_epi16(data, ascii9); // x > '9' + __m128i invalid = _mm_or_si128(below0, above9); + + // Check if any invalid byte exists + if (_mm_testz_si128(invalid, invalid)) { // SSE4.1/4.2: zero flag test +#else + // Branchless "are all digits?" trick from Lemire: + // (x - '0') <= 9 <=> (x + 32720) <= 32729 + // encoded as signed comparison: (x + 32720) > -32759 ? not digit : digit // http://0x80.pl/articles/simd-parsing-int-sequences.html - __m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720)); - __m128i const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759)); + __m128i const adjust = _mm_set1_epi16(32720); + __m128i const cutoff = _mm_set1_epi16(-32759); + __m128i const t0 = _mm_add_epi16(data, adjust); + __m128i const mask = _mm_cmpgt_epi16(t0, cutoff); - if (_mm_movemask_epi8(t1) == 0) { + // If mask == 0 → all digits valid. + if (_mm_movemask_epi8(mask) == 0) { i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; } else return false; FASTFLOAT_SIMD_RESTORE_WARNINGS +#endif #elif defined(FASTFLOAT_NEON) FASTFLOAT_SIMD_DISABLE_WARNINGS uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); From f757eb45a228749607a11c5f43d4ebe01a07b09b Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 00:44:29 +0300 Subject: [PATCH 154/252] * Upgrade manually vectorized code to support SSE4.2. --- include/fast_float/ascii_number.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a3ebc89c..c281be4c 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -10,11 +10,11 @@ #include "float_common.h" -#ifdef FASTFLOAT_SSE2 +#if defined(FASTFLOAT_SSE42) +#include // SSE4.2 intrinsics +#elif defined(FASTFLOAT_SSE2) #include -#endif - -#ifdef FASTFLOAT_NEON +#elif defined(FASTFLOAT_NEON) #include #endif @@ -76,7 +76,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS // _mm_packus_epi16 is SSE4.1+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); -#ifdef FASTFLOAT_64BIT +#ifdef FASTFLOAT_SSE42 return static_cast(_mm_cvtsi128_si64(packed)); #else uint64_t value; @@ -169,7 +169,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, __m128i const data = _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); -#ifdef FASTFLOAT_64BIT +#ifdef FASTFLOAT_SSE42 // --- Digit range check using SSE4.2 comparisons --- // Validate: '0' (0x30) ≤ x ≤ '9' (0x39) const __m128i ascii0 = _mm_set1_epi16(u'0'); @@ -197,8 +197,8 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, return true; } else return false; - FASTFLOAT_SIMD_RESTORE_WARNINGS #endif + FASTFLOAT_SIMD_RESTORE_WARNINGS #elif defined(FASTFLOAT_NEON) FASTFLOAT_SIMD_DISABLE_WARNINGS uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); From f396c23809d20c7f7530ffdcb2dcdc01104ec5a4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 01:13:25 +0300 Subject: [PATCH 155/252] * Upgrade manually vectorized code to support SSE4.2, final cleanup and documentation for SSE2 code. --- include/fast_float/ascii_number.h | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index c281be4c..22c67200 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -74,7 +74,7 @@ read8_to_u64(UC const *chars) { fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS - // _mm_packus_epi16 is SSE4.1+, converts 8×u16 → 8×u8 + // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); #ifdef FASTFLOAT_SSE42 return static_cast(_mm_cvtsi128_si64(packed)); @@ -171,13 +171,10 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, #ifdef FASTFLOAT_SSE42 // --- Digit range check using SSE4.2 comparisons --- - // Validate: '0' (0x30) ≤ x ≤ '9' (0x39) - const __m128i ascii0 = _mm_set1_epi16(u'0'); - const __m128i ascii9 = _mm_set1_epi16(u'9'); - - __m128i below0 = _mm_cmplt_epi16(data, ascii0); // x < '0' - __m128i above9 = _mm_cmpgt_epi16(data, ascii9); // x > '9' - __m128i invalid = _mm_or_si128(below0, above9); + // Validate: '0' (0x0030) ≤ x ≤ '9' (0x0039) + __m128i const below0 = _mm_cmplt_epi16(data, _mm_set1_epi16(u'0')); // x < '0' + __m128i const above9 = _mm_cmpgt_epi16(data, _mm_set1_epi16(u'9')); // x > '9' + __m128i const invalid = _mm_or_si128(below0, above9); // Check if any invalid byte exists if (_mm_testz_si128(invalid, invalid)) { // SSE4.1/4.2: zero flag test @@ -186,18 +183,16 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, // (x - '0') <= 9 <=> (x + 32720) <= 32729 // encoded as signed comparison: (x + 32720) > -32759 ? not digit : digit // http://0x80.pl/articles/simd-parsing-int-sequences.html - __m128i const adjust = _mm_set1_epi16(32720); - __m128i const cutoff = _mm_set1_epi16(-32759); - __m128i const t0 = _mm_add_epi16(data, adjust); - __m128i const mask = _mm_cmpgt_epi16(t0, cutoff); + __m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720)); + __m128i const mask = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759)); // If mask == 0 → all digits valid. if (_mm_movemask_epi8(mask) == 0) { +#endif i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; } else return false; -#endif FASTFLOAT_SIMD_RESTORE_WARNINGS #elif defined(FASTFLOAT_NEON) FASTFLOAT_SIMD_DISABLE_WARNINGS @@ -218,10 +213,10 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, (void)chars; (void)i; return false; -#endif // FASTFLOAT_SSE2 +#endif } -#endif // FASTFLOAT_HAS_SIMD +#endif // MSVC SFINAE is broken pre-VS2017 #if defined(_MSC_VER) && _MSC_VER <= 1900 From 397c0b8d260566dc0f0c3c8ab3dcc114f36af65f Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 01:31:06 +0300 Subject: [PATCH 156/252] # fix for FASTFLOAT_64BIT --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 22c67200..5bbb9c3d 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -76,7 +76,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); -#ifdef FASTFLOAT_SSE42 +#ifdef FASTFLOAT_64BIT return static_cast(_mm_cvtsi128_si64(packed)); #else uint64_t value; From 1dfd486df418e9c688337a500337561db61ca5f5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 01:51:13 +0300 Subject: [PATCH 157/252] # cleanup --- include/fast_float/ascii_number.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 5bbb9c3d..24eba9ad 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -191,8 +191,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, #endif i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; - } else - return false; + } FASTFLOAT_SIMD_RESTORE_WARNINGS #elif defined(FASTFLOAT_NEON) FASTFLOAT_SIMD_DISABLE_WARNINGS @@ -206,14 +205,13 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, if (vminvq_u16(mask) == 0xFFFF) { i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; - } else - return false; + } FASTFLOAT_SIMD_RESTORE_WARNINGS #else (void)chars; (void)i; - return false; #endif + return false; } #endif From 57f63fc327d65584a3069ca9e03997b1a31076a8 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 02:28:31 +0300 Subject: [PATCH 158/252] * fix for parse_eight_digits_unrolled --- include/fast_float/ascii_number.h | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 24eba9ad..b92e8536 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -10,9 +10,7 @@ #include "float_common.h" -#if defined(FASTFLOAT_SSE42) -#include // SSE4.2 intrinsics -#elif defined(FASTFLOAT_SSE2) +#if defined(FASTFLOAT_SSE2) #include #elif defined(FASTFLOAT_NEON) #include @@ -124,7 +122,7 @@ uint64_t simd_read8_to_u64(UC const *) { } // credit @aqrit -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t parse_eight_digits_unrolled(uint64_t val) noexcept { constexpr uint64_t mask = 0x000000FF000000FF; constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) @@ -132,12 +130,12 @@ parse_eight_digits_unrolled(uint64_t val) noexcept { val -= 0x3030303030303030; val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; - return uint32_t(val); + return val; } // Call this if chars are definitely 8 digits. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t parse_eight_digits_unrolled(UC const *chars) noexcept { if (cpp20_and_in_constexpr() || !has_simd_opt()) { return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay @@ -169,16 +167,6 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, __m128i const data = _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); -#ifdef FASTFLOAT_SSE42 - // --- Digit range check using SSE4.2 comparisons --- - // Validate: '0' (0x0030) ≤ x ≤ '9' (0x0039) - __m128i const below0 = _mm_cmplt_epi16(data, _mm_set1_epi16(u'0')); // x < '0' - __m128i const above9 = _mm_cmpgt_epi16(data, _mm_set1_epi16(u'9')); // x > '9' - __m128i const invalid = _mm_or_si128(below0, above9); - - // Check if any invalid byte exists - if (_mm_testz_si128(invalid, invalid)) { // SSE4.1/4.2: zero flag test -#else // Branchless "are all digits?" trick from Lemire: // (x - '0') <= 9 <=> (x + 32720) <= 32729 // encoded as signed comparison: (x + 32720) > -32759 ? not digit : digit @@ -188,7 +176,6 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, // If mask == 0 → all digits valid. if (_mm_movemask_epi8(mask) == 0) { -#endif i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; } From 6c175c5a14bea9508265af2b66a18888f90412f5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 02:31:52 +0300 Subject: [PATCH 159/252] # format --- include/fast_float/parse_number.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index c8e465e8..e69f7ba7 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -417,7 +417,8 @@ FASTFLOAT_CONSTEXPR20 const am_mant_t m = static_cast(mantissa); #else const bool is_negative = mantissa < 0; - const am_mant_t m = static_cast(is_negative ? -mantissa : mantissa); + const am_mant_t m = + static_cast(is_negative ? -mantissa : mantissa); #endif T value; if (clinger_fast_path_impl(m, decimal_exponent, From 0c4171eb26b4e5cb931dddb3d0525ef1afe50a92 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 22 Oct 2025 02:56:40 +0300 Subject: [PATCH 160/252] # small cleanup --- include/fast_float/digit_comparison.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 475bf29a..f7b8878b 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -177,9 +177,9 @@ round_down(adjusted_mantissa &am, am_pow_t shift) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void skip_zeros(UC const *&first, UC const *last) noexcept { - uint64_t val; while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len()) { + uint64_t val; ::memcpy(&val, first, sizeof(uint64_t)); if (val != int_cmp_zeros()) { break; @@ -190,7 +190,7 @@ skip_zeros(UC const *&first, UC const *last) noexcept { if (*first != UC('0')) { break; } - first++; + ++first; } } @@ -200,9 +200,9 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool is_truncated(UC const *first, UC const *last) noexcept { // do 8-bit optimizations, can just compare to 8 literal 0s. - uint64_t val; while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len()) { + uint64_t val; ::memcpy(&val, first, sizeof(uint64_t)); if (val != int_cmp_zeros()) { return true; From 5dc09e79a999d64630e7f52b42987c8bec82c9c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 02:27:02 +0000 Subject: [PATCH 161/252] Bump the github-actions group across 1 directory with 3 updates Bumps the github-actions group with 3 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/setup-node](https://github.com/actions/setup-node) and [jidicula/clang-format-action](https://github.com/jidicula/clang-format-action). Updates `actions/upload-artifact` from 4 to 5 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) Updates `actions/setup-node` from 5.0.0 to 6.0.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/a0853c24544627f65ddf259abe73b1d18a591444...2028fbc5c25fe9cf00d9f06a71cc4710d4507903) Updates `jidicula/clang-format-action` from 4.15.0 to 4.16.0 - [Release notes](https://github.com/jidicula/clang-format-action/releases) - [Commits](https://github.com/jidicula/clang-format-action/compare/4726374d1aa3c6aecf132e5197e498979588ebc8...6cd220de46c89139a0365edae93eee8eb30ca8fe) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: jidicula/clang-format-action dependency-version: 4.16.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 2 +- .github/workflows/lint_and_format_check.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 4d9f67b0..bd9e1e6c 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -20,7 +20,7 @@ jobs: fuzz-seconds: 300 output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index c5dc90ad..399f0c9e 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 - - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index ce6a2af5..be16fa18 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 - name: Run clang-format - uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0 + uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 with: clang-format-version: '17' From 56d423399d66aedbdee0971946fdc6fb48bc3dbb Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 18:14:39 +0300 Subject: [PATCH 162/252] * Improving in code generation -> speedup. * fix warning in 32 bit build. --- include/fast_float/ascii_number.h | 6 +++--- include/fast_float/bigint.h | 8 ++++---- include/fast_float/digit_comparison.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index b92e8536..f3190ea0 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -122,7 +122,7 @@ uint64_t simd_read8_to_u64(UC const *) { } // credit @aqrit -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t parse_eight_digits_unrolled(uint64_t val) noexcept { constexpr uint64_t mask = 0x000000FF000000FF; constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) @@ -130,12 +130,12 @@ parse_eight_digits_unrolled(uint64_t val) noexcept { val -= 0x3030303030303030; val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; - return val; + return uint32_t(val); } // Call this if chars are definitely 8 digits. template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t parse_eight_digits_unrolled(UC const *chars) noexcept { if (cpp20_and_in_constexpr() || !has_simd_opt()) { return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index dc4db71b..09d52b35 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -604,11 +604,11 @@ struct bigint : pow5_tables<> { exp -= large_step; } #ifdef FASTFLOAT_64BIT_LIMB - limb_t const small_step = 27; - limb const max_native = 7450580596923828125UL; + limb_t constexpr small_step = 27; + limb constexpr max_native = 7450580596923828125UL; #else - limb_t const small_step = 13; - limb const max_native = 1220703125U; + limb_t constexpr small_step = 13; + limb constexpr max_native = 1220703125U; #endif while (exp >= small_step) { FASTFLOAT_TRY(small_mul(vec, max_native)); diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index f7b8878b..2ccda2a0 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -260,7 +260,7 @@ round_up_bigint(bigint &big, am_digits &count) noexcept { // parse the significant digits into a big integer template -inline FASTFLOAT_CONSTEXPR20 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 From 62b60e0040c25d4055ac3502d8fcba094dfc5e71 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 18:29:14 +0300 Subject: [PATCH 163/252] # Disable FASTFLOAT_HAS_BYTESWAP: step to try to fix precision error on x86 platform --- include/fast_float/constexpr_feature_detect.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 8d409dfc..69995387 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -29,11 +29,12 @@ #define FASTFLOAT_CONSTEVAL FASTFLOAT_CONSTEXPR14 #endif -#if defined(__cpp_lib_byteswap) -#define FASTFLOAT_HAS_BYTESWAP 1 -#else +// Try to fix precision error in x86 platform +//#if defined(__cpp_lib_byteswap) +//#define FASTFLOAT_HAS_BYTESWAP 1 +//#else #define FASTFLOAT_HAS_BYTESWAP 0 -#endif +//#endif #if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L #define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) From e6f2bf13b46eca3307ba311aeff501c5027ab756 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 19:09:45 +0300 Subject: [PATCH 164/252] # test failed. --- include/fast_float/constexpr_feature_detect.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 69995387..8d409dfc 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -29,12 +29,11 @@ #define FASTFLOAT_CONSTEVAL FASTFLOAT_CONSTEXPR14 #endif -// Try to fix precision error in x86 platform -//#if defined(__cpp_lib_byteswap) -//#define FASTFLOAT_HAS_BYTESWAP 1 -//#else +#if defined(__cpp_lib_byteswap) +#define FASTFLOAT_HAS_BYTESWAP 1 +#else #define FASTFLOAT_HAS_BYTESWAP 0 -//#endif +#endif #if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L #define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) From e96afe608ef2a47dde685852afc8f7017b8640b1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 19:25:53 +0300 Subject: [PATCH 165/252] * try to fix precision error on x86 platform step2. --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2801437e..1a952c5d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int_fast16_t am_pow_t; +typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias hacks. Needs rewriting this. // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From 77ef46838cfa926d99e929a0beef09fd88daeb98 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 19:40:24 +0300 Subject: [PATCH 166/252] * try to fix precision error on x86 platform step3. --- include/fast_float/fast_float.h | 8 ++++---- include/fast_float/float_common.h | 3 ++- include/fast_float/parse_number.h | 16 ++++++++-------- tests/basictest.cpp | 17 +++++++++-------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 8d1d137a..7e72120b 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -60,10 +60,10 @@ from_chars_advanced(UC const *first, UC const *last, T &value, */ FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - int const decimal_exponent) noexcept; + int16_t const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - int const decimal_exponent) noexcept; + int16_t const decimal_exponent) noexcept; /** * This function is a template overload of `integer_times_pow10()` @@ -74,12 +74,12 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - int const decimal_exponent) noexcept; + int16_t const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - int const decimal_exponent) noexcept; + int16_t const decimal_exponent) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 1a952c5d..8ff706fd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,8 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias hacks. Needs rewriting this. +typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias + // hacks. Needs rewriting this. // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index e69f7ba7..d7ec565b 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -388,7 +388,7 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - int const decimal_exponent) noexcept { + int16_t const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -411,7 +411,7 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - int const decimal_exponent) noexcept { + int16_t const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); const am_mant_t m = static_cast(mantissa); @@ -440,13 +440,13 @@ FASTFLOAT_CONSTEXPR20 FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - int const decimal_exponent) noexcept { + int16_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - int const decimal_exponent) noexcept { + int16_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } @@ -458,7 +458,7 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && !std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -469,7 +469,7 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { + integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -477,14 +477,14 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { +integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int decimal_exponent) noexcept { +integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 671ec3df..f0431d27 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -2127,7 +2127,7 @@ TEST_CASE("bfloat16.general") { template void verify_integer_times_pow10_result(Int const mantissa, - int const decimal_exponent, + int16_t const decimal_exponent, T const actual, U const expected) { static_assert(std::is_same::value, "expected and actual types must match"); @@ -2145,8 +2145,8 @@ void verify_integer_times_pow10_result(Int const mantissa, } template -T calculate_integer_times_pow10_expected_result(Int const mantissa, - int const decimal_exponent) { +T calculate_integer_times_pow10_expected_result( + Int const mantissa, int16_t const decimal_exponent) { std::string constructed_string = std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); T expected_result; @@ -2160,7 +2160,7 @@ T calculate_integer_times_pow10_expected_result(Int const mantissa, template void verify_integer_times_pow10_dflt(Int const mantissa, - int const decimal_exponent, + int16_t const decimal_exponent, double const expected) { static_assert(std::is_integral::value); @@ -2174,7 +2174,7 @@ void verify_integer_times_pow10_dflt(Int const mantissa, template void verify_integer_times_pow10_dflt(Int const mantissa, - int const decimal_exponent) { + int16_t const decimal_exponent) { static_assert(std::is_integral::value); const auto expected_result = @@ -2185,7 +2185,8 @@ void verify_integer_times_pow10_dflt(Int const mantissa, } template -void verify_integer_times_pow10(Int const mantissa, int const decimal_exponent, +void verify_integer_times_pow10(Int const mantissa, + int16_t const decimal_exponent, T const expected) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2200,7 +2201,7 @@ void verify_integer_times_pow10(Int const mantissa, int const decimal_exponent, template void verify_integer_times_pow10(Int const mantissa, - int const decimal_exponent) { + int16_t const decimal_exponent) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2213,7 +2214,7 @@ void verify_integer_times_pow10(Int const mantissa, namespace all_supported_types { template void verify_integer_times_pow10(Int const mantissa, - int const decimal_exponent) { + int16_t const decimal_exponent) { static_assert(std::is_integral::value); // verify the "default" overload From 578b1e989805e2cc27ca788dedcaf8fd0d757931 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 21:19:23 +0300 Subject: [PATCH 167/252] * try to fix precision error on x86 platform step4. --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 8ff706fd..2b322d3a 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias +typedef int64_t am_pow_t; // can't be int_fast16_t because invalid_am_bias // hacks. Needs rewriting this. // Bias so we can get the real exponent with an invalid adjusted_mantissa. From cd62aadb1be77fb7a4721166b66cf0691c5a4f5e Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 21:26:31 +0300 Subject: [PATCH 168/252] * try to fix precision error on x86 platform step5. --- include/fast_float/float_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2b322d3a..f15860b2 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -450,7 +450,7 @@ typedef int64_t am_pow_t; // can't be int_fast16_t because invalid_am_bias // hacks. Needs rewriting this. // Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static am_pow_t invalid_am_bias = -0x8000; +constexpr static am_pow_t invalid_am_bias = -0x800000000000000; struct adjusted_mantissa { am_mant_t mantissa; From df6b574e40848de8e8befc91b4e64b59e59fe642 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 21:38:15 +0300 Subject: [PATCH 169/252] * try to fix precision error on x86 platform step6. --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index f15860b2..8ff706fd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,11 +446,11 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int64_t am_pow_t; // can't be int_fast16_t because invalid_am_bias +typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias // hacks. Needs rewriting this. // Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static am_pow_t invalid_am_bias = -0x800000000000000; +constexpr static am_pow_t invalid_am_bias = -0x8000; struct adjusted_mantissa { am_mant_t mantissa; From 1ba0d482c171f457e84c6c5e5cb7d9087ac0cde5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 22:01:14 +0300 Subject: [PATCH 170/252] * try to fix precision error on x86 platform step7. --- include/fast_float/decimal_to_binary.h | 5 +++-- include/fast_float/float_common.h | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index badf0fae..97a8d443 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -139,8 +139,9 @@ compute_float(int64_t q, uint64_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - limb_t upperbit = limb_t(product.high >> 63); - limb_t shift = limb_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); + am_pow_t const upperbit = am_pow_t(product.high >> 63); + am_pow_t const shift = + am_pow_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); answer.mantissa = product.high >> shift; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 8ff706fd..b3aa60a6 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,8 +446,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int16_t am_pow_t; // can't be int_fast16_t because invalid_am_bias - // hacks. Needs rewriting this. +typedef int32_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From 97aa629922976de343c06dec04d7872067e936f0 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 22:15:17 +0300 Subject: [PATCH 171/252] * try to fix precision error on x86 platform step8. --- include/fast_float/ascii_number.h | 2 +- include/fast_float/bigint.h | 2 +- include/fast_float/float_common.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index f3190ea0..730496a3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -439,7 +439,7 @@ parse_number_string(UC const *p, UC const *pend, } else { // Now let's parse the explicit exponent. while ((p != pend) && is_integer(*p)) { - if (exp_number < 0x1000) { + if (exp_number < 0x10000000) { // check for exponent overflow if we have too many digits. UC const digit = UC(*p - UC('0')); exp_number = 10 * exp_number + static_cast(digit); diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 09d52b35..45e7299d 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -39,7 +39,7 @@ constexpr limb_t bigint_limbs = bigint_bits / limb_bits; // vector-like type that is allocated on the stack. the entire // buffer is pre-allocated, and only the length changes. template struct stackvec { - limb data[size] = {0}; + limb data[size]; // we never need more than 150 limbs uint_fast8_t length{0}; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index b3aa60a6..a0bfbcf3 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int32_t am_pow_t; +typedef int_fast32_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From 3e498bb3b1aa3f4854f1f45d50515837da89c139 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 22:28:40 +0300 Subject: [PATCH 172/252] * try to fix precision error on x86 platform step9. --- include/fast_float/ascii_number.h | 2 +- include/fast_float/decimal_to_binary.h | 6 +++--- include/fast_float/float_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 730496a3..05149bbb 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -439,7 +439,7 @@ parse_number_string(UC const *p, UC const *pend, } else { // Now let's parse the explicit exponent. while ((p != pend) && is_integer(*p)) { - if (exp_number < 0x10000000) { + if (exp_number < 0x10000) { // check for exponent overflow if we have too many digits. UC const digit = UC(*p - UC('0')); exp_number = 10 * exp_number + static_cast(digit); diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 97a8d443..57e80f71 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -139,9 +139,9 @@ compute_float(int64_t q, uint64_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - am_pow_t const upperbit = am_pow_t(product.high >> 63); - am_pow_t const shift = - am_pow_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); + limb_t const upperbit = limb_t(product.high >> 63); + limb_t const shift = + limb_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); answer.mantissa = product.high >> shift; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index a0bfbcf3..2801437e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -446,7 +446,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int_fast32_t am_pow_t; +typedef int_fast16_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From a92f025df70aeadeb0de10d1f6416c9cbe2cea65 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 8 Nov 2025 23:59:52 +0300 Subject: [PATCH 173/252] * type usage fix --- include/fast_float/decimal_to_binary.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 57e80f71..5732f0d2 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -20,14 +20,14 @@ namespace fast_float { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) noexcept { - int const index = 2 * int(q - powers::smallest_power_of_five); + am_pow_t const index = 2 * am_pow_t(q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact // because The line value128 firstproduct = full_multiplication(w, // power_of_five_128[index]); gives the exact answer. value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]); static_assert((bit_precision >= 0) && (bit_precision <= 64), - " precision should be in (0,64]"); + " precision should be in [0,64]"); constexpr uint64_t precision_mask = (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) : uint64_t(0xFFFFFFFFFFFFFFFF); @@ -40,7 +40,7 @@ compute_product_approximation(int64_t q, uint64_t w) noexcept { full_multiplication(w, powers::power_of_five_128[index + 1]); firstproduct.low += secondproduct.high; if (secondproduct.high > firstproduct.low) { - firstproduct.high++; + ++firstproduct.high; } } return firstproduct; @@ -71,8 +71,8 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { - am_pow_t hilz = static_cast(uint64_t(w >> 63) ^ 1); +compute_error_scaled(int64_t q, uint64_t w, limb_t lz) noexcept { + limb_t const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = @@ -87,7 +87,7 @@ compute_error_scaled(int64_t q, uint64_t w, int32_t lz) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept { - limb_t lz = leading_zeroes(w); + limb_t const lz = leading_zeroes(w); w <<= lz; value128 product = compute_product_approximation(q, w); @@ -119,7 +119,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. - limb_t lz = leading_zeroes(w); + limb_t const lz = leading_zeroes(w); w <<= lz; // The required precision is binary::mantissa_explicit_bits() + 3 because From 9e1d063628e6db7d4495859f74db75f6573c6892 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 00:12:43 +0300 Subject: [PATCH 174/252] # tests --- tests/basictest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index f0431d27..93a7a28c 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -69,7 +69,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -const std::string_view round_name(int const d) { +const std::string round_name(int const d) { switch (d) { case FE_UPWARD: return "FE_UPWARD"; From 80902aa90cd8fef52ec3cff6edd27d081f25f0fb Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 16:34:07 +0300 Subject: [PATCH 175/252] * try to fix error on x86 platform step1. --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 05149bbb..94abf966 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -70,7 +70,7 @@ read8_to_u64(UC const *chars) { #ifdef FASTFLOAT_SSE2 -fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { FASTFLOAT_SIMD_DISABLE_WARNINGS // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); @@ -94,7 +94,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { #elif defined(FASTFLOAT_NEON) -fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { FASTFLOAT_SIMD_DISABLE_WARNINGS uint8x8_t utf8_packed = vmovn_u16(data); return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); From 50fa3ad99e1bb13e01368d8f181c3bff4569534a Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 16:34:42 +0300 Subject: [PATCH 176/252] * code cleanup. --- benchmarks/event_counter.h | 2 +- tests/basictest.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index ee37f08a..509488b6 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -130,7 +130,7 @@ struct event_collector { LinuxEvents linux_events; event_collector() - : linux_events(std::array{ + : linux_events(std::array{ PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_MISSES}) {} diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 93a7a28c..95592e18 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -69,7 +69,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -const std::string round_name(int const d) { +const std::string_view round_name(int const d) { switch (d) { case FE_UPWARD: return "FE_UPWARD"; @@ -107,9 +107,9 @@ TEST_CASE("system_info") { #endif #ifdef FASTFLOAT_IS_BIG_ENDIAN #if FASTFLOAT_IS_BIG_ENDIAN - printf("big endian\n"); + std::cout << "big endian" << std::endl; #else - printf("little endian\n"); + std::cout << "little endian" << std::endl; #endif #endif #ifdef FASTFLOAT_32BIT From d0c7def24d81a0cad2f5e3b473050a19c6c686c1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 16:38:57 +0300 Subject: [PATCH 177/252] * try to fix error on x86 platform step2. --- include/fast_float/float_common.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2801437e..ce68bd48 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -179,7 +179,8 @@ using parse_options = parse_options_t; #if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ (defined(_M_AMD64) || defined(_M_X64) || \ (defined(_M_IX86_FP) && _M_IX86_FP == 2))) -#define FASTFLOAT_SSE2 1 +// try to fix error on x86 platform: disable SSE2 code +//#define FASTFLOAT_SSE2 1 #endif #if defined(__aarch64__) || defined(_M_ARM64) From 3ae6d3c2b3e93ec48af7f4ce7d540518efc3b323 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 16:40:44 +0300 Subject: [PATCH 178/252] # unfck lint --- benchmarks/event_counter.h | 3 ++- include/fast_float/float_common.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/benchmarks/event_counter.h b/benchmarks/event_counter.h index 509488b6..6b8f4e1d 100644 --- a/benchmarks/event_counter.h +++ b/benchmarks/event_counter.h @@ -130,7 +130,8 @@ struct event_collector { LinuxEvents linux_events; event_collector() - : linux_events(std::array{ + : linux_events(std::array{ PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_MISSES}) {} diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index ce68bd48..9a56cf35 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -180,7 +180,7 @@ using parse_options = parse_options_t; (defined(_M_AMD64) || defined(_M_X64) || \ (defined(_M_IX86_FP) && _M_IX86_FP == 2))) // try to fix error on x86 platform: disable SSE2 code -//#define FASTFLOAT_SSE2 1 +// #define FASTFLOAT_SSE2 1 #endif #if defined(__aarch64__) || defined(_M_ARM64) From e109eedd35af8709c248334b66558d6f16529410 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 17:21:52 +0300 Subject: [PATCH 179/252] * try to fix error on x86 platform step3. --- include/fast_float/ascii_number.h | 4 ++-- include/fast_float/float_common.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 94abf966..05149bbb 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -70,7 +70,7 @@ read8_to_u64(UC const *chars) { #ifdef FASTFLOAT_SSE2 -fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); @@ -94,7 +94,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { #elif defined(FASTFLOAT_NEON) -fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { +fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) { FASTFLOAT_SIMD_DISABLE_WARNINGS uint8x8_t utf8_packed = vmovn_u16(data); return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 9a56cf35..2801437e 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -179,8 +179,7 @@ using parse_options = parse_options_t; #if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ (defined(_M_AMD64) || defined(_M_X64) || \ (defined(_M_IX86_FP) && _M_IX86_FP == 2))) -// try to fix error on x86 platform: disable SSE2 code -// #define FASTFLOAT_SSE2 1 +#define FASTFLOAT_SSE2 1 #endif #if defined(__aarch64__) || defined(_M_ARM64) From b9d91e7f34b4cf00981379be093a6800105cd6c6 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 17:22:13 +0300 Subject: [PATCH 180/252] * code cleanup. --- include/fast_float/bigint.h | 27 ++++++++++++++------------- include/fast_float/digit_comparison.h | 16 +++++++--------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 45e7299d..3040c503 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -535,19 +535,17 @@ struct bigint : pow5_tables<> { // we can't shift more than the capacity of the vector. return false; } - if (vec.is_empty()) { - // nothing to do - return true; + if (!vec.is_empty()) { + // move limbs + limb *dst = vec.data + n; + limb const *src = vec.data; + std::copy_backward(src, src + vec.len(), dst + vec.len()); + // fill in empty limbs + limb *first = vec.data; + limb *last = first + n; + ::std::fill(first, last, 0); + vec.set_len(limb_t(n + vec.len())); } - // move limbs - limb *dst = vec.data + n; - limb const *src = vec.data; - std::copy_backward(src, src + vec.len(), dst + vec.len()); - // fill in empty limbs - limb *first = vec.data; - limb *last = first + n; - ::std::fill(first, last, 0); - vec.set_len(limb_t(n + vec.len())); return true; } @@ -590,12 +588,14 @@ struct bigint : pow5_tables<> { FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } // multiply as if by 2 raised to a power. - FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t exp) noexcept { + FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t const exp) noexcept { + FASTFLOAT_ASSERT(exp >= 0); return shl(static_cast(exp)); } // multiply as if by 5 raised to a power. FASTFLOAT_CONSTEXPR20 bool pow5(am_pow_t exp) noexcept { + FASTFLOAT_ASSERT(exp >= 0); // multiply by a power of 5 limb_t const large_length = sizeof(large_power_of_5) / sizeof(limb); limb_span const large = limb_span(large_power_of_5, large_length); @@ -627,6 +627,7 @@ struct bigint : pow5_tables<> { // multiply as if by 10 raised to a power. FASTFLOAT_CONSTEXPR20 bool pow10(am_pow_t exp) noexcept { + FASTFLOAT_ASSERT(exp >= 0); FASTFLOAT_TRY(pow5(exp)); return pow2(exp); } diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 2ccda2a0..fa39efd0 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -373,11 +373,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp( // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( - bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { - bigint &real_digits = bigmant; - am_pow_t const &real_exp = exponent; - +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +negative_digit_comp(bigint &real_digits, adjusted_mantissa am, + am_pow_t const real_exp) noexcept { // get the value of `b`, rounded down, and get a bigint representation of // b+h adjusted_mantissa am_b = am; @@ -391,12 +389,12 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( false, #endif am_b, b); - adjusted_mantissa theor = to_extended_halfway(b); + adjusted_mantissa const theor = to_extended_halfway(b); bigint theor_digits(theor.mantissa); - am_pow_t theor_exp = theor.power2; + am_pow_t const theor_exp = theor.power2; // scale real digits and theor digits to be same power. - am_pow_t pow2_exp = theor_exp - real_exp; + am_pow_t const pow2_exp = theor_exp - real_exp; am_pow_t pow5_exp = -real_exp; if (pow5_exp != 0) { FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); @@ -408,7 +406,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( } // compare digits, and use it to direct rounding - int ord = real_digits.compare(theor_digits); + int const ord = real_digits.compare(theor_digits); round(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { From 959c9531ea1f2ca89063030f1d80cbd40b7822ae Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 18:13:17 +0300 Subject: [PATCH 181/252] # cycles (for and while) cleanup in low level for the best compiler optimization and the best runtime. --- include/fast_float/ascii_number.h | 2 +- include/fast_float/bigint.h | 11 +++++------ include/fast_float/float_common.h | 2 +- tests/basictest.cpp | 12 ++++++------ 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 05149bbb..e8bdcd8a 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -49,7 +49,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t read8_to_u64(UC const *chars) { if (cpp20_and_in_constexpr() || !std::is_same::value) { uint64_t val = 0; - for (uint_fast8_t i = 0; i != 8; ++i) { + for (uint_fast8_t i = 0; i++ != 8;) { val |= uint64_t(uint8_t(*chars)) << (i * 8); ++chars; } diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 3040c503..5b210156 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -259,10 +259,9 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, limb_t start) noexcept { limb carry = y; bool overflow; - while (carry != 0 && start < vec.len()) { + while (carry != 0 && start++ != vec.len()) { vec[start] = scalar_add(vec[start], carry, overflow); carry = limb(overflow); - ++start; } if (carry != 0) { FASTFLOAT_TRY(vec.try_push(carry)); @@ -282,7 +281,7 @@ template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (limb_t index = 0; index != vec.len(); ++index) { + for (limb_t index = 0; index++ != vec.len();) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -303,7 +302,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } bool carry = false; - for (limb_t index = 0; index < y.len(); ++index) { + for (limb_t index = 0; index++ != y.len();) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -488,7 +487,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (limb_t index = vec.len(); index != 0; --index) { + for (limb_t index = vec.len(); index-- != 0;) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -515,7 +514,7 @@ struct bigint : pow5_tables<> { bigint_bits_t const shl = n; bigint_bits_t const shr = limb_bits - shl; limb prev = 0; - for (limb_t index = 0; index != vec.len(); ++index) { + for (limb_t index = 0; index++ != vec.len();) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2801437e..d80bb2ab 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -288,7 +288,7 @@ template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, uint8_t const length) noexcept { - for (uint8_t i = 0; i != length; ++i) { + for (uint8_t i = 0; i++ != length;) { UC const actual = actual_mixedcase[i]; if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { return false; diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 95592e18..f0899efc 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -618,7 +618,7 @@ TEST_CASE("issue8") { "752384674818467669405132000568127145263560827785771342757789609173637178" "721468440901224953430146549585371050792279689258923542019956112129021960" "864034418159813629774771309960518707211349999998372978"; - for (int i = 0; i < 16; i++) { + for (int i = 0; i != 16; ++i) { // Parse all but the last i chars. We should still get 3.141ish. double d = 0.0; auto answer = fast_float::from_chars(s, s + strlen(s) - i, d); @@ -919,9 +919,9 @@ uint16_t get_mantissa(std::bfloat16_t f) { } #endif -std::string append_zeros(std::string str, size_t number_of_zeros) { +std::string append_zeros(std::string_view str, size_t const number_of_zeros) { std::string answer(str); - for (size_t i = 0; i < number_of_zeros; i++) { + for (size_t i = 0; i++ != number_of_zeros;) { answer += "0"; } return answer; @@ -947,7 +947,7 @@ constexpr void check_basic_test_result(stringtype str, result_type result, #define FASTFLOAT_CHECK_EQ(...) \ if constexpr (diag == Diag::runtime) { \ char narrow[global_string_capacity]{}; \ - for (size_t i = 0; i < str.size(); i++) { \ + for (size_t i = 0; i++ != str.size();) { \ narrow[i] = char(str[i]); \ } \ INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \ @@ -1006,7 +1006,7 @@ constexpr void basic_test(std::string_view str, T expected, // We give plenty of memory: 2048 characters. char16_t u16[global_string_capacity]{}; - for (size_t i = 0; i < str.size(); i++) { + for (size_t i = 0; i++ != str.size();) { u16[i] = char16_t(str[i]); } @@ -1015,7 +1015,7 @@ constexpr void basic_test(std::string_view str, T expected, actual, expected, expected_ec); char32_t u32[global_string_capacity]{}; - for (size_t i = 0; i < str.size(); i++) { + for (size_t i = 0; i++ != str.size();) { u32[i] = char32_t(str[i]); } From c8e4d89fefff180d569943d56193c6eda76b333c Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 18:15:53 +0300 Subject: [PATCH 182/252] # unfck lint --- tests/basictest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index f0899efc..92908b1d 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -947,7 +947,7 @@ constexpr void check_basic_test_result(stringtype str, result_type result, #define FASTFLOAT_CHECK_EQ(...) \ if constexpr (diag == Diag::runtime) { \ char narrow[global_string_capacity]{}; \ - for (size_t i = 0; i++ != str.size();) { \ + for (size_t i = 0; i++ != str.size();) { \ narrow[i] = char(str[i]); \ } \ INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \ From 497e65b03f439a967d0f3e6afd180f3546ae6a04 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 9 Nov 2025 19:08:11 +0300 Subject: [PATCH 183/252] * Added separate config macros FASTFLOAT_ISNOT_CHECKED_BOUNDS. --- README.md | 14 ++++++++------ include/fast_float/parse_number.h | 20 +++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 17ddc85d..938ba9b0 100644 --- a/README.md +++ b/README.md @@ -380,15 +380,17 @@ int main() { ## You also can also use some additional options (currently only configure by macroses): -There is a really common use case in mathematical and other abstract syntax tree (AST) like parsers, -that already process sign and all other symbols before any number by itself. In this case you can -use FastFloat for only parse positive numbers in all supported formats with macros -`FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, that significantly reduce the code size and improve -performance. Additionally you can use macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you -only uneed `FE_TONEAREST` rounding mode in the parsing: this option is also improve performance a bit. +There is a really common use case in mathematical and other abstract syntax tree (AST)-like parsers that already processes +the sign and all other symbols before any number by itself. In this case you can use FastFloat to only parse positive numbers +in all supported formats with macros `FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, which significantly reduce the code size +and improve performance. You also can use macros `FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds; +it's very likely because all parsers need to check the first character by itself before parsing. Additionally, you can use +macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need `FE_TONEAREST` rounding mode in the parsing; +this option also improves performance a bit and reduces code size. ```C++ #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#define FASTFLOAT_ISNOT_CHECKED_BOUNDS #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #include "fast_float/fast_float.h" #include diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index d7ec565b..f3d5e3a9 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -336,14 +336,16 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, ++first; } } +#endif +#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS + // We are in parser code with external loop that checks bounds. + FASTFLOAT_ASSUME(first < last); +#else if (first == last) { answer.ec = std::errc::invalid_argument; answer.ptr = first; return answer; } -#else - // We are in parser code with external loop that checks bounds. - FASTFLOAT_ASSUME(first < last); #endif parsed_number_string_t const pns = #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -498,19 +500,19 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); -#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - // We are in parser code with external loop that checks bounds. - FASTFLOAT_ASSUME(first < last); - // base is already checked in the parse_options_t constructor. -#else +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN if (chars_format_t(options.format & chars_format::skip_white_space)) { while ((first != last) && fast_float::is_space(*first)) { ++first; } } +#endif +#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS + // We are in parser code with external loop that checks bounds. + FASTFLOAT_ASSUME(first < last); #endif if ( -#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#ifndef FASTFLOAT_ISNOT_CHECKED_BOUNDS first == last || #endif options.base < 2 || options.base > 36) { From b8163709f51df3b3bdbeff796ff7b6c7e3030551 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Nov 2025 02:41:26 +0300 Subject: [PATCH 184/252] * type usage fix for better performance in any hardware. --- include/fast_float/bigint.h | 4 ++-- include/fast_float/fast_float.h | 10 +++++----- include/fast_float/float_common.h | 16 ++++++++-------- include/fast_float/parse_number.h | 22 +++++++++++----------- tests/basictest.cpp | 14 +++++++------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 5b210156..f3f61ecd 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -369,7 +369,7 @@ FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { } template struct pow5_tables { - static constexpr uint8_t large_step = 135; + static constexpr uint_fast8_t large_step = 135; static constexpr uint64_t small_power_of_5[] = { 1UL, 5UL, @@ -413,7 +413,7 @@ template struct pow5_tables { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint8_t pow5_tables::large_step; +template constexpr uint_fast8_t pow5_tables::large_step; template constexpr uint64_t pow5_tables::small_power_of_5[]; diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 7e72120b..0d70a8dc 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -60,10 +60,10 @@ from_chars_advanced(UC const *first, UC const *last, T &value, */ FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - int16_t const decimal_exponent) noexcept; + int_fast16_t const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - int16_t const decimal_exponent) noexcept; + int_fast16_t const decimal_exponent) noexcept; /** * This function is a template overload of `integer_times_pow10()` @@ -74,12 +74,12 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - int16_t const decimal_exponent) noexcept; + int_fast16_t const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - int16_t const decimal_exponent) noexcept; + int_fast16_t const decimal_exponent) noexcept; /** * from_chars for integer types. @@ -88,7 +88,7 @@ template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - int const base = 10) noexcept; + uint_fast8_t const base = 10) noexcept; } // namespace fast_float diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index d80bb2ab..733d7e9c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -287,8 +287,8 @@ struct is_supported_char_type template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, - uint8_t const length) noexcept { - for (uint8_t i = 0; i++ != length;) { + uint_fast8_t const length) noexcept { + for (uint_fast8_t i = 0; i++ != length;) { UC const actual = actual_mixedcase[i]; if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { return false; @@ -1059,7 +1059,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN template struct space_lut { - static constexpr uint8_t value[] = { + static constexpr uint_fast8_t value[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1075,12 +1075,12 @@ template struct space_lut { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint8_t space_lut::value[]; +template constexpr uint_fast8_t space_lut::value[]; #endif template constexpr bool is_space(UC c) { - return c < 256 && space_lut<>::value[uint8_t(c)]; + return c < 256 && space_lut<>::value[uint_fast8_t(c)]; } #endif @@ -1166,7 +1166,7 @@ template struct int_luts { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - static constexpr uint8_t maxdigits_u64[] = { + static constexpr uint_fast8_t maxdigits_u64[] = { 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; @@ -1187,9 +1187,9 @@ template struct int_luts { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint8_t int_luts::chdigit[]; +template constexpr uint_fast8_t int_luts::chdigit[]; -template constexpr uint8_t int_luts::maxdigits_u64[]; +template constexpr uint_fast8_t int_luts::maxdigits_u64[]; template constexpr uint64_t int_luts::min_safe_u64[]; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index f3d5e3a9..0a324f62 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -374,15 +374,15 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { +from_chars(UC const *first, UC const *last, T &value, + uint_fast8_t const base) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - parse_options_t const options(chars_format::general, UC('.'), - static_cast(base)); + parse_options_t const options(chars_format::general, UC('.'), base); return from_chars_advanced(first, last, value, options); } @@ -390,7 +390,7 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - int16_t const decimal_exponent) noexcept { + int_fast16_t const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -413,7 +413,7 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - int16_t const decimal_exponent) noexcept { + int_fast16_t const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa > 0); const am_mant_t m = static_cast(mantissa); @@ -442,13 +442,13 @@ FASTFLOAT_CONSTEXPR20 FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - int16_t const decimal_exponent) noexcept { + int_fast16_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - int16_t const decimal_exponent) noexcept { + int_fast16_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } @@ -460,7 +460,7 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && !std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { + integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -471,7 +471,7 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { + integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -479,14 +479,14 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { +integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int16_t decimal_exponent) noexcept { +integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 92908b1d..514f5269 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -2127,7 +2127,7 @@ TEST_CASE("bfloat16.general") { template void verify_integer_times_pow10_result(Int const mantissa, - int16_t const decimal_exponent, + int_fast16_t const decimal_exponent, T const actual, U const expected) { static_assert(std::is_same::value, "expected and actual types must match"); @@ -2146,7 +2146,7 @@ void verify_integer_times_pow10_result(Int const mantissa, template T calculate_integer_times_pow10_expected_result( - Int const mantissa, int16_t const decimal_exponent) { + Int const mantissa, int_fast16_t const decimal_exponent) { std::string constructed_string = std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); T expected_result; @@ -2160,7 +2160,7 @@ T calculate_integer_times_pow10_expected_result( template void verify_integer_times_pow10_dflt(Int const mantissa, - int16_t const decimal_exponent, + int_fast16_t const decimal_exponent, double const expected) { static_assert(std::is_integral::value); @@ -2174,7 +2174,7 @@ void verify_integer_times_pow10_dflt(Int const mantissa, template void verify_integer_times_pow10_dflt(Int const mantissa, - int16_t const decimal_exponent) { + int_fast16_t const decimal_exponent) { static_assert(std::is_integral::value); const auto expected_result = @@ -2186,7 +2186,7 @@ void verify_integer_times_pow10_dflt(Int const mantissa, template void verify_integer_times_pow10(Int const mantissa, - int16_t const decimal_exponent, + int_fast16_t const decimal_exponent, T const expected) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2201,7 +2201,7 @@ void verify_integer_times_pow10(Int const mantissa, template void verify_integer_times_pow10(Int const mantissa, - int16_t const decimal_exponent) { + int_fast16_t const decimal_exponent) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2214,7 +2214,7 @@ void verify_integer_times_pow10(Int const mantissa, namespace all_supported_types { template void verify_integer_times_pow10(Int const mantissa, - int16_t const decimal_exponent) { + int_fast16_t const decimal_exponent) { static_assert(std::is_integral::value); // verify the "default" overload From 597c239218b01fc2167df5142b8f4e412df073d9 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Nov 2025 03:13:05 +0300 Subject: [PATCH 185/252] # test fixed. --- tests/fast_int.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/fast_int.cpp b/tests/fast_int.cpp index 49044d36..45bebeba 100644 --- a/tests/fast_int.cpp +++ b/tests/fast_int.cpp @@ -466,7 +466,7 @@ int main() { auto const &f = invalid_base_test_1[i]; int result; auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, -1); + fast_float::from_chars(f.data(), f.data() + f.size(), result, 1); if (answer.ec != std::errc::invalid_argument) { std::cerr << "expected error should be 'invalid_argument' for: \"" << f << "\"" << std::endl; @@ -567,7 +567,7 @@ int main() { auto const &f = int_out_of_range_base_test[i]; int64_t result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(2 + (i / 2))); + uint_fast8_t(2 + (i / 2))); if (answer.ec != std::errc::result_out_of_range) { std::cerr << "expected error for should be 'result_out_of_range': \"" << f << "\"" << std::endl; @@ -612,7 +612,7 @@ int main() { "7ORP63SH4DPHI", "5G24A25TWKWFG", "3W5E11264SGSG"}; - int base_unsigned = 2; + uint_fast8_t base_unsigned = 2; for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i) { auto const &f = unsigned_out_of_range_base_test[i]; uint64_t result; @@ -703,7 +703,7 @@ int main() { auto const &f = int_within_range_base_test[i]; int64_t result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(2 + (i / 2))); + uint_fast8_t(2 + (i / 2))); if (answer.ec != std::errc()) { std::cerr << "converting " << f << " to int failed (most likely out of range)" << std::endl; @@ -748,7 +748,7 @@ int main() { "7ORP63SH4DPHH", "5G24A25TWKWFF", "3W5E11264SGSF"}; - int base_unsigned2 = 2; + uint_fast8_t base_unsigned2 = 2; for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i) { auto const &f = unsigned_within_range_base_test[i]; uint64_t result; @@ -806,7 +806,7 @@ int main() { auto const &f = int_leading_zeros_test[i]; int result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - int(i + 2)); + uint_fast8_t(i + 2)); if (answer.ec != std::errc()) { std::cerr << "could not convert to int for input: \"" << f << "\"" << std::endl; From c9d0ac0084ca7cf203c0eae815acf47d4ff911ba Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 10 Nov 2025 03:49:27 +0300 Subject: [PATCH 186/252] # cleanup. --- include/fast_float/float_common.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 733d7e9c..0474ba3a 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -45,8 +45,8 @@ enum class chars_format : chars_format_t; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN namespace detail { -constexpr chars_format basic_json_fmt = chars_format(1 << 4); -constexpr chars_format basic_fortran_fmt = chars_format(1 << 5); +constexpr chars_format basic_json_fmt = chars_format(1 << 6); +constexpr chars_format basic_fortran_fmt = chars_format(1 << 7); } // namespace detail #endif @@ -57,13 +57,13 @@ enum class chars_format : chars_format_t { hex = 1 << 2, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN no_infnan = 1 << 3, + allow_leading_plus = 1 << 4, + skip_white_space = 1 << 5, // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 json = chars_format_t(detail::basic_json_fmt) | general | no_infnan, // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. json_or_infnan = chars_format_t(detail::basic_json_fmt) | general, fortran = chars_format_t(detail::basic_fortran_fmt) | general, - allow_leading_plus = 1 << 6, - skip_white_space = 1 << 7, #endif }; @@ -83,9 +83,7 @@ template struct parse_options_t { constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), uint_fast8_t const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) { - FASTFLOAT_ASSUME(base >= 2 && base <= 36); - } + : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ chars_format format; From 843aa3f703ebfea3aa191ec9525ea12ab14fe1e5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 12 Nov 2025 14:58:15 +0300 Subject: [PATCH 187/252] * improvements in compiler function detection. --- include/fast_float/constexpr_feature_detect.h | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 8d409dfc..bbe8dcc0 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -7,14 +7,32 @@ #endif #endif -// Testing for https://wg21.link/N3652, adopted in C++14 -#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 +// C++14 constexpr +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304L +#define FASTFLOAT_CONSTEXPR14 constexpr +#elif __cplusplus >= 201402L +#define FASTFLOAT_CONSTEXPR14 constexpr +#elif defined(_MSC_VER) && _MSC_VER >= 1910 && _MSVC_LANG >= 201402L #define FASTFLOAT_CONSTEXPR14 constexpr #else #define FASTFLOAT_CONSTEXPR14 #endif +// C++14 variable templates +#if defined(__cpp_variable_templates) && __cpp_variable_templates >= 201304L +#define FASTFLOAT_HAS_VARIABLE_TEMPLATES 1 +#elif __cplusplus >= 201402L +#define FASTFLOAT_HAS_VARIABLE_TEMPLATES 1 +#elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918L && \ + _MSVC_LANG >= 201402L +#define FASTFLOAT_HAS_VARIABLE_TEMPLATES 1 +#else +#define FASTFLOAT_HAS_VARIABLE_TEMPLATES 0 +#endif + +// C++20 std::bit_cast #if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L +#include #define FASTFLOAT_HAS_BIT_CAST 1 #else #define FASTFLOAT_HAS_BIT_CAST 0 @@ -35,12 +53,39 @@ #define FASTFLOAT_HAS_BYTESWAP 0 #endif +// C++17 if constexpr #if defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L #define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) +#elif defined(__cpp_constexpr) && __cpp_constexpr >= 201603L +#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) +#elif __cplusplus >= 201703L +#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) +#elif defined(_MSC_VER) && _MSC_VER >= 1911 && _MSVC_LANG >= 201703L +#define FASTFLOAT_IF_CONSTEXPR17(x) if constexpr (x) #else #define FASTFLOAT_IF_CONSTEXPR17(x) if (x) #endif +// C++17 inline variables +#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L +#define FASTFLOAT_INLINE_VARIABLE inline constexpr +#elif __cplusplus >= 201703L +#define FASTFLOAT_INLINE_VARIABLE inline constexpr +#elif defined(_MSC_VER) && _MSC_VER >= 1912 && _MSVC_LANG >= 201703L +#define FASTFLOAT_INLINE_VARIABLE inline constexpr +#else +#define FASTFLOAT_INLINE_VARIABLE static constexpr +#endif + +#if defined(__cpp_lib_is_constant_evaluated) && \ + __cpp_lib_is_constant_evaluated >= 201811L +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 +#define FASTFLOAT_CONSTEVAL consteval +#else +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 +#define FASTFLOAT_CONSTEVAL FASTFLOAT_CONSTEXPR14 +#endif + // Testing for relevant C++20 constexpr library features #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ defined(__cpp_lib_constexpr_algorithms) && \ @@ -58,6 +103,12 @@ #define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 #endif +#if defined(__has_builtin) +#define FASTFLOAT_HAS_BUILTIN(x) __has_builtin(x) +#else +#define FASTFLOAT_HAS_BUILTIN(x) false +#endif + // For support attribute [[assume]] is declared in P1774 #if defined(__cpp_attrubute_assume) #define FASTFLOAT_ASSUME(expr) [[assume(expr)]] From 3685667dd2e7033e977af0ea5ca011e990248f44 Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 19 Nov 2025 22:13:24 +0300 Subject: [PATCH 188/252] * FASTFLOAT_HAS_BIT_CAST cleanup. --- include/fast_float/constexpr_feature_detect.h | 1 - include/fast_float/digit_comparison.h | 15 +++------- include/fast_float/float_common.h | 28 +++++++++++++------ 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index bbe8dcc0..6c97f14f 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -32,7 +32,6 @@ // C++20 std::bit_cast #if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L -#include #define FASTFLOAT_HAS_BIT_CAST 1 #else #define FASTFLOAT_HAS_BIT_CAST 0 diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index fa39efd0..43934da5 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -64,19 +64,12 @@ to_extended(T const &value) noexcept { constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); - adjusted_mantissa am; constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - equiv_uint bits; -#if FASTFLOAT_HAS_BIT_CAST - bits = -#if FASTFLOAT_HAS_BIT_CAST == 1 - std:: -#endif - bit_cast(value); -#else - ::memcpy(&bits, &value, sizeof(T)); -#endif + + equiv_uint const bits = bit_cast(value); + + adjusted_mantissa am; if ((bits & exponent_mask) == 0) { // denormal am.power2 = 1 - bias; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 0474ba3a..507da399 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -101,6 +101,23 @@ using parse_options = parse_options_t; #include #endif +namespace fast_float { +template +FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { +#if FASTFLOAT_HAS_BIT_CAST + return std::bit_cast(from); +#else + // Implementation of std::bit_cast for pre-C++20. + static_assert(sizeof(To) == sizeof(From), + "bit_cast requires source and destination to be the same size"); + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; +#endif +} +} // namespace fast_float + #if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ defined(__MINGW64__) || defined(__s390x__) || \ @@ -1029,6 +1046,7 @@ binary_format::hidden_bit_mask() { return 0x0010000000000000; } +// Fix for C2672: Ensure bit_cast is called with explicit template arguments template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -1043,15 +1061,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( word = equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); #endif -#if FASTFLOAT_HAS_BIT_CAST - value = -#if FASTFLOAT_HAS_BIT_CAST == 1 - std:: -#endif - bit_cast(word); -#else - ::memcpy(&value, &word, sizeof(T)); -#endif + value = bit_cast(word); } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 3d46d99cdff4b9c84e1d02f9e0bc0ec701921744 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 21 Nov 2025 18:19:06 +0300 Subject: [PATCH 189/252] # warning fix. --- include/fast_float/digit_comparison.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 43934da5..084b36d7 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -67,7 +67,7 @@ to_extended(T const &value) noexcept { constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - equiv_uint const bits = bit_cast(value); + equiv_uint const bits = bit_cast(value); adjusted_mantissa am; if ((bits & exponent_mask) == 0) { From 077c6d0736a7b59ada61aa60214a2251277d4147 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:24:38 +0000 Subject: [PATCH 190/252] Bump the github-actions group across 1 directory with 2 updates Bumps the github-actions group with 2 updates in the / directory: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/checkout` from 5 to 6 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v5...v6) Updates `actions/setup-node` from 6.0.0 to 6.1.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/2028fbc5c25fe9cf00d9f06a71cc4710d4507903...395ad3262231945c25e8478fd5baf05154b1d79f) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu24.yml | 2 +- .github/workflows/emscripten.yml | 6 +++--- .github/workflows/lint_and_format_check.yml | 2 +- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/risc.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24-cxx20.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 2 +- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 19 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index 9b24bdef..b77fd44f 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml index ca57ff65..db822cb8 100644 --- a/.github/workflows/amalgamate-ubuntu24.yml +++ b/.github/workflows/amalgamate-ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 399f0c9e..e5ddb06e 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -4,13 +4,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.2.2 + - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v3.6.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v3.6.0 - name: Configure run: emcmake cmake -B build - name: Build # We build but do not test diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index be16fa18..164cd225 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,7 +24,7 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.1.7 - name: Run clang-format uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index 7697bb59..d263b6d4 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 4bd814e6..4848f2e0 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 26ef5d58..371cba0a 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index 8bc85588..a8f4d399 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: | sudo apt-get update -q -y diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 6bdc2be7..1c703c5c 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index f8af4374..3e6df05e 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index 91abf7ce..b7bba1e0 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index 08fe8d73..c51524e1 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index 71543954..c8fb3c11 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24-cxx20.yml b/.github/workflows/ubuntu24-cxx20.yml index 85167601..c705631f 100644 --- a/.github/workflows/ubuntu24-cxx20.yml +++ b/.github/workflows/ubuntu24-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 511c7ce3..1b998099 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index 6769a2a4..f4fa84e4 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 9f8546b8..98ed5ce7 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index 56b51611..31b3a4b6 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index aecbca8f..93b7a896 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From 588623e076a6e42847cd95b8745ed65e2080a4f4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 8 Dec 2025 23:59:29 +0300 Subject: [PATCH 191/252] * type usage fix for better performance in any hardware. --- benchmarks/benchmark.cpp | 2 +- include/fast_float/ascii_number.h | 52 +++++++++++++++---------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 048df8ff..de6137e4 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -216,8 +216,8 @@ void fileload(std::string filename) { line.erase(0, 1); } #endif - lines.emplace_back(line); volume += line.size(); + lines.emplace_back(line); } std::cout << "# read " << lines.size() << " lines " << std::endl; process(lines, volume); diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index e8bdcd8a..559f17f4 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -330,21 +330,20 @@ parse_number_string(UC const *p, UC const *pend, } #endif - UC const *const start_digits = p; + auto const *const start_digits = p; while ((p != pend) && is_integer(*p)) { // a multiplication by 10 is cheaper than an arbitrary integer // multiplication answer.mantissa = static_cast( answer.mantissa * 10 + - static_cast( + static_cast( *p - UC('0'))); // might overflow, we will handle the overflow later ++p; } - UC const *const end_of_integer_part = p; - am_digits digit_count = - static_cast(end_of_integer_part - start_digits); + auto const *const end_of_integer_part = p; + auto digit_count = static_cast(end_of_integer_part - start_digits); answer.integer = span(start_digits, digit_count); // We have now parsed the integer part of the mantissa. @@ -364,17 +363,16 @@ parse_number_string(UC const *p, UC const *pend, // We can now parse the fraction part of the mantissa. if ((p != pend) && (*p == options.decimal_point)) { ++p; - UC const *const before = p; + auto const *const before = p; // can occur at most twice without overflowing, but let it occur more, since // for integers with many digits, digit parsing is the primary bottleneck. loop_parse_if_eight_digits(p, pend, answer.mantissa); while ((p != pend) && is_integer(*p)) { - UC const digit = UC(*p - UC('0')); + auto const digit = uint8_t(*p - UC('0')); answer.mantissa = static_cast( answer.mantissa * 10 + - static_cast( - digit)); // in rare cases, this will overflow, but that's ok + digit); // in rare cases, this will overflow, but that's ok ++p; } answer.exponent = static_cast(before - p); @@ -407,7 +405,7 @@ parse_number_string(UC const *p, UC const *pend, (UC('D') == *p))) #endif )) { - UC const *location_of_e = p; + auto const *location_of_e = p; #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; #else @@ -439,10 +437,10 @@ parse_number_string(UC const *p, UC const *pend, } else { // Now let's parse the explicit exponent. while ((p != pend) && is_integer(*p)) { - if (exp_number < 0x10000) { + if (exp_number < std::numeric_limits::max()) { // check for exponent overflow if we have too many digits. - UC const digit = UC(*p - UC('0')); - exp_number = 10 * exp_number + static_cast(digit); + auto const digit = uint8_t(*p - UC('0')); + exp_number = 10 * exp_number + digit; } ++p; } @@ -474,7 +472,7 @@ parse_number_string(UC const *p, UC const *pend, // We have to handle the case where we have 0.0000somenumber. // We need to be mindful of the case where we only have zeroes... // E.g., 0.000000000...000. - UC const *start = start_digits; + auto const *start = start_digits; while ((start != pend) && (*start == UC('0') || *start == options.decimal_point)) { if (*start == UC('0')) { @@ -529,7 +527,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, from_chars_result_t answer; - UC const *const first = p; + auto const *const first = p; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // Read sign @@ -553,7 +551,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } #endif - UC const *const start_num = p; + auto const *const start_num = p; // Skip leading zeros while (p != pend && *p == UC('0')) { @@ -562,23 +560,23 @@ parse_int_string(UC const *p, UC const *pend, T &value, bool const has_leading_zeros = p > start_num; - UC const *const start_digits = p; + auto const *const start_digits = p; // Parse digits - uint64_t i = 0; + am_mant_t i = 0; if (options.base == 10) { loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { - uint_fast8_t const digit = ch_to_digit(*p); + auto const digit = ch_to_digit(*p); if (digit >= options.base) { break; } - i = uint64_t(options.base) * i + digit; // might overflow, check this later - p++; + i = am_mant_t(options.base) * i + digit; // might overflow, check this later + ++p; } - am_digits const digit_count = static_cast(p - start_digits); + auto const digit_count = static_cast(p - start_digits); if (digit_count == 0) { if (has_leading_zeros) { @@ -595,7 +593,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, answer.ptr = p; // check u64 overflow - uint_fast8_t const max_digits = max_digits_u64(options.base); + auto const max_digits = max_digits_u64(options.base); if (digit_count > max_digits) { answer.ec = std::errc::result_out_of_range; return answer; @@ -608,10 +606,10 @@ parse_int_string(UC const *p, UC const *pend, T &value, } // check other types overflow - if (!std::is_same::value) { - if (i > uint64_t(std::numeric_limits::max()) + if (!std::is_same::value) { + if (i > am_mant_t(std::numeric_limits::max()) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - + uint64_t(negative) + + uint8_t(negative) #endif ) { answer.ec = std::errc::result_out_of_range; @@ -634,7 +632,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, // this is always optimized into a neg instruction (note: T is an integer // type) value = T(-std::numeric_limits::max() - - T(i - uint64_t(std::numeric_limits::max()))); + T(i - am_mant_t(std::numeric_limits::max()))); #ifdef FASTFLOAT_VISUAL_STUDIO #pragma warning(pop) #endif From b79c3e5c0ade4b80011bc75e4fffebfe90d05c13 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 9 Dec 2025 22:40:28 +0300 Subject: [PATCH 192/252] Benchmark are updated. --- benchmarks/benchmark.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index de6137e4..45d3d589 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,6 +1,7 @@ // #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN // #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED +// #define FASTFLOAT_ISNOT_CHECKED_BOUNDS #if defined(__linux__) || (__APPLE__ && __aarch64__) #define USING_COUNTERS @@ -50,14 +51,16 @@ time_it_ns(std::vector> &lines, T const &function, size_t repeat) { std::vector aggregate; bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { + for (size_t i = 0; i != repeat; ++i) { + collector.start(); auto const ts = function(lines); + aggregate.push_back(collector.end()); + if (ts == 0 && !printed_bug) { printf("bug\n"); printed_bug = true; } - aggregate.push_back(collector.end()); } return aggregate; } @@ -130,18 +133,21 @@ time_it_ns(std::vector> &lines, T const &function, double average = 0; double min_value = DBL_MAX; bool printed_bug = false; - for (size_t i = 0; i < repeat; i++) { + for (size_t i = 0; i != repeat; ++i) { + t1 = std::chrono::high_resolution_clock::now(); auto const ts = function(lines); - if (ts == 0 && !printed_bug) { - printf("bug\n"); - printed_bug = true; - } t2 = std::chrono::high_resolution_clock::now(); + double const dif = static_cast( std::chrono::duration_cast(t2 - t1).count()); average += dif; min_value = min_value < dif ? min_value : dif; + + if (ts == 0 && !printed_bug) { + printf("bug\n"); + printed_bug = true; + } } average /= repeat; return std::make_pair(min_value, average); @@ -162,7 +168,7 @@ void pretty_print(size_t volume, size_t number_of_floats, inline std::u16string widen(std::string const &line) { std::u16string u16line; u16line.resize(line.size()); - for (size_t i = 0; i < line.size(); ++i) { + for (size_t i = 0; i != line.size(); ++i) { u16line[i] = char16_t(line[i]); } return u16line; @@ -178,7 +184,7 @@ std::vector widen(const std::vector &lines) { } void process(std::vector &lines, size_t volume) { - size_t const repeat = 1000; + size_t constexpr repeat = 1000; double volumeMB = volume / (1024. * 1024.); std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl; pretty_print(volume, lines.size(), "fastfloat (64)", @@ -232,6 +238,9 @@ int main(int argc, char **argv) { std::cout << "# FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED is enabled" << std::endl; #endif +#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS + std::cout << "# FASTFLOAT_ISNOT_CHECKED_BOUNDS is enabled" << std::endl; +#endif #ifdef USING_COUNTERS if (collector.has_events()) { std::cout << "# Using hardware counters" << std::endl; From 47e181dabffc4b0df06a4ae9904b58100ff3f57b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 02:20:49 +0000 Subject: [PATCH 193/252] Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/upload-artifact](https://github.com/actions/upload-artifact). Updates `actions/checkout` from 5.0.1 to 6.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v5.0.1...v6.0.1) Updates `actions/upload-artifact` from 5 to 6 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu24.yml | 2 +- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 4 ++-- .github/workflows/lint_and_format_check.yml | 2 +- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/risc.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24-cxx20.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 2 +- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index b77fd44f..6fdc85c9 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml index db822cb8..0353dc6f 100644 --- a/.github/workflows/amalgamate-ubuntu24.yml +++ b/.github/workflows/amalgamate-ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index bd9e1e6c..2d0bdaa5 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -20,7 +20,7 @@ jobs: fuzz-seconds: 300 output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index e5ddb06e..9f8f07b4 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -4,13 +4,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.2.2 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4.2.2 - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v3.6.0 + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v3.6.0 - name: Configure run: emcmake cmake -B build - name: Build # We build but do not test diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index 164cd225..72f8fa5a 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,7 +24,7 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.1.7 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4.1.7 - name: Run clang-format uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index d263b6d4..59baaf1f 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 4848f2e0..416ef810 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 371cba0a..5b78e24b 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index a8f4d399..70e0c198 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Install packages run: | sudo apt-get update -q -y diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 1c703c5c..21403a44 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index 3e6df05e..359aef43 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index b7bba1e0..9ea6c993 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index c51524e1..c31a9fa4 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index c8fb3c11..de4cb7d2 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24-cxx20.yml b/.github/workflows/ubuntu24-cxx20.yml index c705631f..b5e8d205 100644 --- a/.github/workflows/ubuntu24-cxx20.yml +++ b/.github/workflows/ubuntu24-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 1b998099..3b002f87 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.1 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index f4fa84e4..bf15121b 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 98ed5ce7..10a4c0ac 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index 31b3a4b6..ac9de08f 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index 93b7a896..85544c3c 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.1 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From 65810ebfd3a13435329648effb1e48800a2a2a95 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 00:21:42 +0300 Subject: [PATCH 194/252] * enable warning in GCC because PVS-Studio are also detect this. This is an error! --- include/fast_float/float_common.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 51ceb9d9..d64859ae 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -205,20 +205,20 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { #define FASTFLOAT_HAS_SIMD 1 #endif -#if defined(__GNUC__) +//#if defined(__GNUC__) // disable -Wcast-align=strict (GCC only) -#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wcast-align\"") -#else +//#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ +// _Pragma("GCC diagnostic push") \ +// _Pragma("GCC diagnostic ignored \"-Wcast-align\"") +//#else #define FASTFLOAT_SIMD_DISABLE_WARNINGS -#endif +//#endif -#if defined(__GNUC__) -#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") -#else +//#if defined(__GNUC__) +//#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +//#else #define FASTFLOAT_SIMD_RESTORE_WARNINGS -#endif +//#endif #ifdef FASTFLOAT_VISUAL_STUDIO #define fastfloat_really_inline __forceinline From f42c8802afd56ac9a698ea2fe180a768f720a288 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 01:12:02 +0300 Subject: [PATCH 195/252] * enable warning in GCC because PVS-Studio are also detect this. This is an error! --- include/fast_float/ascii_number.h | 16 ++-------------- include/fast_float/float_common.h | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 559f17f4..7d962884 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -71,7 +71,6 @@ read8_to_u64(UC const *chars) { #ifdef FASTFLOAT_SSE2 fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { - FASTFLOAT_SIMD_DISABLE_WARNINGS // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 __m128i const packed = _mm_packus_epi16(data, data); #ifdef FASTFLOAT_64BIT @@ -82,30 +81,23 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { _mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed); return value; #endif - FASTFLOAT_SIMD_RESTORE_WARNINGS } fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - FASTFLOAT_SIMD_DISABLE_WARNINGS return simd_read8_to_u64( - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); - FASTFLOAT_SIMD_RESTORE_WARNINGS + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); //TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The pointer 'chars' is cast to a more strictly aligned pointer type. } #elif defined(FASTFLOAT_NEON) fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) { - FASTFLOAT_SIMD_DISABLE_WARNINGS uint8x8_t utf8_packed = vmovn_u16(data); return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); - FASTFLOAT_SIMD_RESTORE_WARNINGS } fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - FASTFLOAT_SIMD_DISABLE_WARNINGS return simd_read8_to_u64( vld1q_u16(reinterpret_cast(chars))); - FASTFLOAT_SIMD_RESTORE_WARNINGS } #endif @@ -162,10 +154,9 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, return false; } #ifdef FASTFLOAT_SSE2 - FASTFLOAT_SIMD_DISABLE_WARNINGS // Load 8 UTF-16 characters (16 bytes) __m128i const data = - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); //TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The pointer 'chars' is cast to a more strictly aligned pointer type. // Branchless "are all digits?" trick from Lemire: // (x - '0') <= 9 <=> (x + 32720) <= 32729 @@ -179,9 +170,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; } - FASTFLOAT_SIMD_RESTORE_WARNINGS #elif defined(FASTFLOAT_NEON) - FASTFLOAT_SIMD_DISABLE_WARNINGS uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); // (x - '0') <= 9 @@ -193,7 +182,6 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); return true; } - FASTFLOAT_SIMD_RESTORE_WARNINGS #else (void)chars; (void)i; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index d64859ae..4f48d8ad 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -205,19 +205,20 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { #define FASTFLOAT_HAS_SIMD 1 #endif +// Don't silent this. This is an important warning! //#if defined(__GNUC__) // disable -Wcast-align=strict (GCC only) //#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ // _Pragma("GCC diagnostic push") \ // _Pragma("GCC diagnostic ignored \"-Wcast-align\"") //#else -#define FASTFLOAT_SIMD_DISABLE_WARNINGS +//#define FASTFLOAT_SIMD_DISABLE_WARNINGS //#endif //#if defined(__GNUC__) //#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") //#else -#define FASTFLOAT_SIMD_RESTORE_WARNINGS +//#define FASTFLOAT_SIMD_RESTORE_WARNINGS //#endif #ifdef FASTFLOAT_VISUAL_STUDIO @@ -336,8 +337,18 @@ template struct span { }; struct value128 { - uint64_t low; - uint64_t high; + union { + struct { + uint64_t low; + uint64_t high; + }; +#ifdef FASTFLOAT_SSE2 + __m128i full; // trick for test only +#endif +#ifdef FASTFLOAT_NEON + uint16x8_t full; // trick for test only +#endif + }; constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} From 600f236fd8f1ee0032577840d915e1159d87eee3 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 11:16:13 +0300 Subject: [PATCH 196/252] * Small optimization in code generation for auto vectorization. --- include/fast_float/float_common.h | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 4f48d8ad..2716401c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -336,19 +336,9 @@ template struct span { } }; -struct value128 { - union { - struct { - uint64_t low; - uint64_t high; - }; -#ifdef FASTFLOAT_SSE2 - __m128i full; // trick for test only -#endif -#ifdef FASTFLOAT_NEON - uint16x8_t full; // trick for test only -#endif - }; +struct alignas(16) value128 { + uint64_t low; + uint64_t high; constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} From b7fb05b843683fc6f2d5840aac8c48805852531e Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 14:04:04 +0300 Subject: [PATCH 197/252] * Added additional compile option FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED for improve cache usage in high load. * Small optimization in code generation for auto vectorization. --- README.md | 12 +++++++----- benchmarks/benchmark.cpp | 5 +++++ include/fast_float/ascii_number.h | 7 +++++++ include/fast_float/float_common.h | 6 +++++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6af9cf70..3746a6ab 100644 --- a/README.md +++ b/README.md @@ -383,13 +383,15 @@ int main() { There is a really common use case in mathematical and other abstract syntax tree (AST)-like parsers that already processes the sign and all other symbols before any number by itself. In this case you can use FastFloat to only parse positive numbers in all supported formats with macros `FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, which significantly reduce the code size -and improve performance. You also can use macros `FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds; -it's very likely because all parsers need to check the first character by itself before parsing. Additionally, you can use -macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need `FE_TONEAREST` rounding mode in the parsing; -this option also improves performance a bit and reduces code size. - +and improve performance. An additional option for high performance and very fast processing is +`FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED`; it reduces data size and speeds up parsing because a data cache is used for your +real data, not for a 256-byte table that flushes out at least 3 cache lines on x86. You also can use macros +`FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds; it's very likely because all parsers need to check the first +character by itself before parsing. Additionally, you can use macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need +`FE_TONEAREST` rounding mode in the parsing; this option also improves performance a bit and reduces code size. ```C++ #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +#define FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED #define FASTFLOAT_ISNOT_CHECKED_BOUNDS #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #include "fast_float/fast_float.h" diff --git a/benchmarks/benchmark.cpp b/benchmarks/benchmark.cpp index 66a2fd8b..030ebcce 100644 --- a/benchmarks/benchmark.cpp +++ b/benchmarks/benchmark.cpp @@ -1,5 +1,6 @@ // #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +// #define FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED // #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED // #define FASTFLOAT_ISNOT_CHECKED_BOUNDS @@ -234,6 +235,10 @@ int main(int argc, char **argv) { std::cout << "# FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is enabled" << std::endl; #endif +#ifdef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED + std::cout << "# FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED is enabled" + << std::endl; +#endif #ifdef FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED std::cout << "# FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED is enabled" << std::endl; diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index f77c516a..7ff36ec0 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -642,7 +642,14 @@ parse_int_string(UC const *p, UC const *pend, T &value, loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { +#ifdef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED + const auto digit = *p; + if (!is_integer(digit)) { + break; + } +#else auto const digit = ch_to_digit(*p); +#endif if (digit >= options.base) { break; } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 3d7f46af..b3393e00 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -513,7 +513,7 @@ typedef int_fast16_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; -struct adjusted_mantissa { +struct alignas(16) adjusted_mantissa { am_mant_t mantissa; am_pow_t power2; adjusted_mantissa() noexcept = default; @@ -1201,6 +1201,7 @@ template <> constexpr char8_t const *str_const_inf() { #endif template struct int_luts { +#ifndef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED static constexpr uint8_t chdigit[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -1220,6 +1221,7 @@ template struct int_luts { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; +#endif static constexpr uint_fast8_t maxdigits_u64[] = { 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, @@ -1250,6 +1252,7 @@ template constexpr uint64_t int_luts::min_safe_u64[]; #endif +#ifndef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED template fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { // wchar_t and char can be signed, so we need to be careful. @@ -1259,6 +1262,7 @@ fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { static_cast( -((static_cast(c) & ~0xFFull) == 0)))]; } +#endif fastfloat_really_inline constexpr uint_fast8_t max_digits_u64(uint_fast8_t base) noexcept { From 2aba1685b03e9d79ffbad45cdc84f066408cfe36 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 14:36:51 +0300 Subject: [PATCH 198/252] * optimize layout of the parsed_number_string_t. --- include/fast_float/ascii_number.h | 13 ++++++------- include/fast_float/float_common.h | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 7ff36ec0..9100000e 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -250,19 +250,18 @@ enum class parse_error : uint_fast8_t { }; template struct parsed_number_string_t { - // an unsigned int avoids signed overflows (which are bad) am_mant_t mantissa{0}; am_pow_t exponent{0}; + // contains the range of the significant digits + span integer{}; // non-nullable + span fraction{}; // nullable UC const *lastmatch{nullptr}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif - bool invalid{false}; - bool too_many_digits{false}; - // contains the range of the significant digits - span integer{}; // non-nullable - span fraction{}; // nullable - parse_error error{parse_error::no_error}; + bool invalid{false}; // be optimistic + bool too_many_digits{false}; // be optimistic + parse_error error{parse_error::no_error}; // be optimistic }; using byte_span = span; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index b3393e00..8d64a1e0 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -502,7 +502,7 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { } // Value of the mantissa. -typedef uint_fast64_t am_mant_t; +typedef uint_fast64_t am_mant_t; // an unsigned int avoids signed overflows (which are bad) // Size of bits in the mantissa and path and rounding shifts typedef int_fast8_t am_bits_t; From a8c78f440335c755f2ea75e58b418e8676edf70d Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 15:15:25 +0300 Subject: [PATCH 199/252] unfck lint. --- include/fast_float/ascii_number.h | 16 ++++++++++------ include/fast_float/float_common.h | 21 +++------------------ 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9100000e..7b3aff8f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -84,8 +84,10 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { } fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - return simd_read8_to_u64( - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); //TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The pointer 'chars' is cast to a more strictly aligned pointer type. + return simd_read8_to_u64(_mm_loadu_si128(reinterpret_cast<__m128i const *>( + chars))); // TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ + // The pointer 'chars' is cast to a more strictly aligned + // pointer type. } #elif defined(FASTFLOAT_NEON) @@ -155,8 +157,10 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, } #ifdef FASTFLOAT_SSE2 // Load 8 UTF-16 characters (16 bytes) - __m128i const data = - _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); //TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The pointer 'chars' is cast to a more strictly aligned pointer type. + __m128i const data = _mm_loadu_si128(reinterpret_cast<__m128i const *>( + chars)); // TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The + // pointer 'chars' is cast to a more strictly aligned pointer + // type. // Branchless "are all digits?" trick from Lemire: // (x - '0') <= 9 <=> (x + 32720) <= 32729 @@ -259,8 +263,8 @@ template struct parsed_number_string_t { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif - bool invalid{false}; // be optimistic - bool too_many_digits{false}; // be optimistic + bool invalid{false}; // be optimistic + bool too_many_digits{false}; // be optimistic parse_error error{parse_error::no_error}; // be optimistic }; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 8d64a1e0..4b596528 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -205,22 +205,6 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { #define FASTFLOAT_HAS_SIMD 1 #endif -// Don't silent this. This is an important warning! -//#if defined(__GNUC__) -// disable -Wcast-align=strict (GCC only) -//#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ -// _Pragma("GCC diagnostic push") \ -// _Pragma("GCC diagnostic ignored \"-Wcast-align\"") -//#else -//#define FASTFLOAT_SIMD_DISABLE_WARNINGS -//#endif - -//#if defined(__GNUC__) -//#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") -//#else -//#define FASTFLOAT_SIMD_RESTORE_WARNINGS -//#endif - #ifdef FASTFLOAT_VISUAL_STUDIO #define fastfloat_really_inline __forceinline #else @@ -501,8 +485,9 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { return answer; } -// Value of the mantissa. -typedef uint_fast64_t am_mant_t; // an unsigned int avoids signed overflows (which are bad) +// Value of the mantissa. An unsigned int avoids signed overflows (which are +// bad) +typedef uint_fast64_t am_mant_t; // Size of bits in the mantissa and path and rounding shifts typedef int_fast8_t am_bits_t; From e88d9ae42781e492cd455dde445bc0c6bfa5127e Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 16:47:56 +0300 Subject: [PATCH 200/252] FASTFLOAT_HAS_BYTESWAP cleanup. --- include/fast_float/ascii_number.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 7b3aff8f..cf9cd76b 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -41,6 +41,10 @@ fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) noexcept { (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; } +#elif FASTFLOAT_HAS_BYTESWAP == 1 +fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) noexcept { + return std::byteswap(val); +} #endif // Read 8 UC into a u64. Truncates UC if not char. @@ -59,11 +63,7 @@ read8_to_u64(UC const *chars) { ::memcpy(&val, chars, sizeof(uint64_t)); #if FASTFLOAT_IS_BIG_ENDIAN == 1 // Need to read as-if the number was in little-endian order. - val = -#if FASTFLOAT_HAS_BYTESWAP == 1 - std:: -#endif - byteswap(val); + val = byteswap(val); #endif return val; } From 325c7236e75d9d07e8cc88278b9930b22cf5107f Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 19:16:26 +0300 Subject: [PATCH 201/252] MSVC compilation fix. --- tests/basictest.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 514f5269..2175746d 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -21,6 +21,16 @@ #endif // #ifndef FASTFLOAT_CONSTEXPR_TESTS #endif // FASTFLOAT_IS_CONSTEXPR +// MSVC's constexpr evaluation and some constexpr-friendly std library pieces +// (like i/o and certain std::numeric_limits members) aren't suitable for the +// compile-time tests in this file on MSVC; disable the constexpr tests when +// compiling with MSVC (but allow them for clang/clang-cl). +#if defined(_MSC_VER) && !defined(__clang__) +# ifdef FASTFLOAT_CONSTEXPR_TESTS +# undef FASTFLOAT_CONSTEXPR_TESTS +# endif +#endif + #if FASTFLOAT_HAS_BIT_CAST #include #endif From 9ff1624d920b51b5f2f0cb8b900980a649290bb1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 19:17:12 +0300 Subject: [PATCH 202/252] small fix. --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index cf9cd76b..e95a6768 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -53,7 +53,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t read8_to_u64(UC const *chars) { if (cpp20_and_in_constexpr() || !std::is_same::value) { uint64_t val = 0; - for (uint_fast8_t i = 0; i++ != 8;) { + for (uint_fast8_t i = 0; i != 8; ++i) { val |= uint64_t(uint8_t(*chars)) << (i * 8); ++chars; } @@ -259,7 +259,7 @@ template struct parsed_number_string_t { // contains the range of the significant digits span integer{}; // non-nullable span fraction{}; // nullable - UC const *lastmatch{nullptr}; + UC const *lastmatch; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif From 074fdeac74239949ffaf0e32da3d1f73fb35d574 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 19:21:17 +0300 Subject: [PATCH 203/252] small fix --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index e95a6768..a2a42123 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -259,7 +259,7 @@ template struct parsed_number_string_t { // contains the range of the significant digits span integer{}; // non-nullable span fraction{}; // nullable - UC const *lastmatch; + UC const *lastmatch{nullptr}; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif From be4683501ee4e575724736fea90c0f52ec67fe8d Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 19:37:41 +0300 Subject: [PATCH 204/252] fix for biodegradable code in doctest. --- tests/basictest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 2175746d..760aa7dc 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1,4 +1,4 @@ -#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS +// DOCTEST_CONFIG_SUPER_FAST_ASSERTS // don't enable this biodegradable code! #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include "doctest/doctest.h" From cdabfe49af4dae7e65b70a212068e52d11fe9cb9 Mon Sep 17 00:00:00 2001 From: IRainman Date: Thu, 25 Dec 2025 23:00:52 +0300 Subject: [PATCH 205/252] # constexpr noexcept --- tests/basictest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 760aa7dc..92cb6516 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -79,7 +79,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -const std::string_view round_name(int const d) { +constexpr std::string_view round_name(int const d) noexcept { switch (d) { case FE_UPWARD: return "FE_UPWARD"; From d07362c459512cda1e53c82f6b1553d98ec692c7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 00:13:41 +0300 Subject: [PATCH 206/252] Final review for a more simple merge. Feature FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED is removed because hex and bin parsing isn't working properly. Properly use FASTFLOAT_SIMD_DISABLE_WARNINGS and FASTFLOAT_SIMD_RESTORE_WARNINGS only for instructions that allow unaligned loads. --- include/fast_float/ascii_number.h | 54 +++++++++++++------------- include/fast_float/bigint.h | 8 ++-- include/fast_float/decimal_to_binary.h | 4 +- include/fast_float/digit_comparison.h | 11 +++--- include/fast_float/fast_float.h | 2 +- include/fast_float/fast_table.h | 2 - include/fast_float/float_common.h | 27 +++++++++---- include/fast_float/parse_number.h | 16 ++++---- 8 files changed, 67 insertions(+), 57 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a2a42123..889968ab 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -84,10 +84,10 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) { } fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { - return simd_read8_to_u64(_mm_loadu_si128(reinterpret_cast<__m128i const *>( - chars))); // TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ - // The pointer 'chars' is cast to a more strictly aligned - // pointer type. + FASTFLOAT_SIMD_DISABLE_WARNINGS + return simd_read8_to_u64( + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS } #elif defined(FASTFLOAT_NEON) @@ -98,8 +98,10 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) { } fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { + FASTFLOAT_SIMD_DISABLE_WARNINGS return simd_read8_to_u64( vld1q_u16(reinterpret_cast(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS } #endif @@ -118,9 +120,9 @@ uint64_t simd_read8_to_u64(UC const *) { // credit @aqrit fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t parse_eight_digits_unrolled(uint64_t val) noexcept { - constexpr uint64_t mask = 0x000000FF000000FF; - constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) - constexpr uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) + uint64_t const mask = 0x000000FF000000FF; + uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) val -= 0x3030303030303030; val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; @@ -156,11 +158,11 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, return false; } #ifdef FASTFLOAT_SSE2 + FASTFLOAT_SIMD_DISABLE_WARNINGS // Load 8 UTF-16 characters (16 bytes) - __m128i const data = _mm_loadu_si128(reinterpret_cast<__m128i const *>( - chars)); // TODO: V1032 https://pvs-studio.com/en/docs/warnings/v1032/ The - // pointer 'chars' is cast to a more strictly aligned pointer - // type. + __m128i const data = + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); + FASTFLOAT_SIMD_RESTORE_WARNINGS // Branchless "are all digits?" trick from Lemire: // (x - '0') <= 9 <=> (x + 32720) <= 32729 @@ -175,7 +177,9 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars, return true; } #elif defined(FASTFLOAT_NEON) + FASTFLOAT_SIMD_DISABLE_WARNINGS uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); + FASTFLOAT_SIMD_RESTORE_WARNINGS // (x - '0') <= 9 // http://0x80.pl/articles/simd-parsing-int-sequences.html @@ -286,7 +290,7 @@ report_parse_error(UC const *p, parse_error error) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity // Consider refactoring the 'parse_number_string' function. // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. @@ -295,8 +299,8 @@ parse_number_string(UC const *p, UC const *pend, FASTFLOAT_ASSUME(p < pend); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN answer.negative = (*p == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if (answer.negative || - // C++17 20.19.3.(7.1) explicitly forbids '+' sign here ((chars_format_t(options.format & chars_format::allow_leading_plus)) && (!basic_json_fmt && *p == UC('+')))) { ++p; @@ -400,8 +404,11 @@ parse_number_string(UC const *p, UC const *pend, #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN ++p; #else - if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || - (UC('D') == *p)) { + if ((UC('e') == *p) || (UC('E') == *p) +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + || (UC('d') == *p) || (UC('D') == *p) +#endif + ) { ++p; } #endif @@ -483,8 +490,8 @@ parse_number_string(UC const *p, UC const *pend, p = answer.integer.ptr; UC const *int_end = p + answer.integer.len(); constexpr am_mant_t minimal_nineteen_digit_integer{1000000000000000000}; - while ((answer.mantissa < minimal_nineteen_digit_integer) && - (p != int_end)) { + while ((p != int_end) && + (answer.mantissa < minimal_nineteen_digit_integer)) { answer.mantissa = static_cast( answer.mantissa * 10 + static_cast(*p - UC('0'))); ++p; @@ -496,8 +503,8 @@ parse_number_string(UC const *p, UC const *pend, // We have a value with a significant fractional component. p = answer.fraction.ptr; UC const *const frac_end = p + answer.fraction.len(); - while ((answer.mantissa < minimal_nineteen_digit_integer) && - (p != frac_end)) { + while ((p != frac_end) && + (answer.mantissa < minimal_nineteen_digit_integer)) { answer.mantissa = static_cast( answer.mantissa * 10 + static_cast(*p - UC('0'))); ++p; @@ -514,7 +521,7 @@ parse_number_string(UC const *p, UC const *pend, template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_int_string(UC const *p, UC const *pend, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { from_chars_result_t answer; @@ -645,14 +652,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible } while (p != pend) { -#ifdef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED - const auto digit = *p; - if (!is_integer(digit)) { - break; - } -#else auto const digit = ch_to_digit(*p); -#endif if (digit >= options.base) { break; } diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index f3f61ecd..5aa3faf7 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -281,7 +281,7 @@ template inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, limb y) noexcept { limb carry = 0; - for (limb_t index = 0; index++ != vec.len();) { + for (limb_t index = 0; index != vec.len(); ++index) { vec[index] = scalar_mul(vec[index], y, carry); } if (carry != 0) { @@ -302,7 +302,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, } bool carry = false; - for (limb_t index = 0; index++ != y.len();) { + for (limb_t index = 0; index != y.len(); ++index) { limb xi = x[index + start]; limb yi = y[index]; bool c1 = false; @@ -487,7 +487,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (limb_t index = vec.len(); index-- != 0;) { + for (limb_t index = vec.len(); index != 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -514,7 +514,7 @@ struct bigint : pow5_tables<> { bigint_bits_t const shl = n; bigint_bits_t const shr = limb_bits - shl; limb prev = 0; - for (limb_t index = 0; index++ != vec.len();) { + for (limb_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 5732f0d2..8d4b6a21 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -139,8 +139,8 @@ compute_float(int64_t q, uint64_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - limb_t const upperbit = limb_t(product.high >> 63); - limb_t const shift = + auto const upperbit = limb_t(product.high >> 63); + auto const shift = limb_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); answer.mantissa = product.high >> shift; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 084b36d7..22c8dd34 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -58,18 +58,18 @@ scientific_exponent(am_mant_t mantissa, am_pow_t exponent) noexcept { // this converts a native floating-point number to an extended-precision float. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended(T const &value) noexcept { +to_extended(T const value) noexcept { using equiv_uint = equiv_uint_t; constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); + adjusted_mantissa am; constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); equiv_uint const bits = bit_cast(value); - adjusted_mantissa am; if ((bits & exponent_mask) == 0) { // denormal am.power2 = 1 - bias; @@ -90,7 +90,7 @@ to_extended(T const &value) noexcept { // halfway between b and b+u. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -to_extended_halfway(T const &value) noexcept { +to_extended_halfway(T const value) noexcept { adjusted_mantissa am = to_extended(value); am.mantissa <<= 1; am.mantissa += 1; @@ -253,7 +253,7 @@ round_up_bigint(bigint &big, am_digits &count) noexcept { // parse the significant digits into a big integer template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits +inline FASTFLOAT_CONSTEXPR20 am_digits parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { // 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 @@ -369,8 +369,7 @@ template inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(bigint &real_digits, adjusted_mantissa am, am_pow_t const real_exp) noexcept { - // get the value of `b`, rounded down, and get a bigint representation of - // b+h + // get the value of `b`, rounded down, and get a bigint representation of b+h adjusted_mantissa am_b = am; // gcc7 bug: use a lambda to remove the noexcept qualifier bug with // -Wnoexcept-type. diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 0d70a8dc..8540e78f 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -43,7 +43,7 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept; + parse_options_t const options) noexcept; /** * This function multiplies an integer number by a power of 10 and returns diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index 536e1499..6a6f901a 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -1,8 +1,6 @@ #ifndef FASTFLOAT_FAST_TABLE_H #define FASTFLOAT_FAST_TABLE_H -#include - namespace fast_float { /** diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 4b596528..51ee29db 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -205,6 +205,21 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { #define FASTFLOAT_HAS_SIMD 1 #endif +#if defined(__GNUC__) +// disable -Wcast-align=strict (GCC only) +#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-align\"") +#else +#define FASTFLOAT_SIMD_DISABLE_WARNINGS +#endif + +#if defined(__GNUC__) +#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +#else +#define FASTFLOAT_SIMD_RESTORE_WARNINGS +#endif + #ifdef FASTFLOAT_VISUAL_STUDIO #define fastfloat_really_inline __forceinline #else @@ -288,7 +303,7 @@ template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, uint_fast8_t const length) noexcept { - for (uint_fast8_t i = 0; i++ != length;) { + for (uint_fast8_t i = 0; i != length; ++i) { UC const actual = actual_mixedcase[i]; if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { return false; @@ -450,8 +465,10 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // slow emulation routine for 32-bit #if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t -_umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t_umul128(uint64_t ab, + uint64_t cd, + uint64_t *hi) + noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ @@ -1186,7 +1203,6 @@ template <> constexpr char8_t const *str_const_inf() { #endif template struct int_luts { -#ifndef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED static constexpr uint8_t chdigit[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, @@ -1206,7 +1222,6 @@ template struct int_luts { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; -#endif static constexpr uint_fast8_t maxdigits_u64[] = { 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, @@ -1237,7 +1252,6 @@ template constexpr uint64_t int_luts::min_safe_u64[]; #endif -#ifndef FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED template fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { // wchar_t and char can be signed, so we need to be careful. @@ -1247,7 +1261,6 @@ fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { static_cast( -((static_cast(c) & ~0xFFull) == 0)))]; } -#endif fastfloat_really_inline constexpr uint_fast8_t max_digits_u64(uint_fast8_t base) noexcept { diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 0a324f62..eb30818c 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -148,7 +148,7 @@ template struct from_chars_caller { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_advanced(first, last, value, options); } }; @@ -322,7 +322,7 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -400,7 +400,7 @@ FASTFLOAT_CONSTEXPR20 return value; adjusted_mantissa am = - compute_float>(decimal_exponent, mantissa); + compute_float>(decimal_exponent, mantissa); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, @@ -415,7 +415,7 @@ FASTFLOAT_CONSTEXPR20 integer_times_pow10(int64_t const mantissa, int_fast16_t const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - FASTFLOAT_ASSUME(mantissa > 0); + FASTFLOAT_ASSUME(mantissa >= 0); const am_mant_t m = static_cast(mantissa); #else const bool is_negative = mantissa < 0; @@ -493,7 +493,7 @@ integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_int_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); @@ -533,7 +533,7 @@ template <> struct from_chars_advanced_caller<1> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_float_advanced(first, last, value, options); } }; @@ -542,7 +542,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_int_advanced(first, last, value, options); } }; @@ -550,7 +550,7 @@ template <> struct from_chars_advanced_caller<2> { template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, - parse_options_t const &options) noexcept { + parse_options_t const options) noexcept { return from_chars_advanced_caller< size_t(is_supported_float_type::value) + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, From 350ad6ecac01bab9515d54de6dc5e182a1272477 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 00:22:44 +0300 Subject: [PATCH 207/252] unfck lint --- include/fast_float/ascii_number.h | 2 +- include/fast_float/float_common.h | 6 ++---- tests/basictest.cpp | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 889968ab..bf356043 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -406,7 +406,7 @@ parse_number_string(UC const *p, UC const *pend, #else if ((UC('e') == *p) || (UC('E') == *p) #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - || (UC('d') == *p) || (UC('D') == *p) + || (UC('d') == *p) || (UC('D') == *p) #endif ) { ++p; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 51ee29db..76de233d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -465,10 +465,8 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // slow emulation routine for 32-bit #if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t_umul128(uint64_t ab, - uint64_t cd, - uint64_t *hi) - noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 +uint64_t_umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 92cb6516..d30bc87b 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -26,9 +26,9 @@ // compile-time tests in this file on MSVC; disable the constexpr tests when // compiling with MSVC (but allow them for clang/clang-cl). #if defined(_MSC_VER) && !defined(__clang__) -# ifdef FASTFLOAT_CONSTEXPR_TESTS -# undef FASTFLOAT_CONSTEXPR_TESTS -# endif +#ifdef FASTFLOAT_CONSTEXPR_TESTS +#undef FASTFLOAT_CONSTEXPR_TESTS +#endif #endif #if FASTFLOAT_HAS_BIT_CAST From c119cdda05468e07e634ea7b223432462b7b7b27 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 00:32:56 +0300 Subject: [PATCH 208/252] revert workflows. --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu24.yml | 2 +- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 6 +++--- .github/workflows/lint_and_format_check.yml | 4 ++-- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/risc.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24-cxx20.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 4 ++-- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 20 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index 6fdc85c9..9b24bdef 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v5 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml index 0353dc6f..ca57ff65 100644 --- a/.github/workflows/amalgamate-ubuntu24.yml +++ b/.github/workflows/amalgamate-ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 2d0bdaa5..bd9e1e6c 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -20,7 +20,7 @@ jobs: fuzz-seconds: 300 output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v5 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 9f8f07b4..399f0c9e 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -4,13 +4,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4.2.2 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v3.6.0 + uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v3.6.0 - name: Configure run: emcmake cmake -B build - name: Build # We build but do not test diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index 72f8fa5a..ce6a2af5 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,10 +24,10 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v4.1.7 + - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 - name: Run clang-format - uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 + uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0 with: clang-format-version: '17' diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index 59baaf1f..7697bb59 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 416ef810..4bd814e6 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 5b78e24b..26ef5d58 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index 70e0c198..8bc85588 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Install packages run: | sudo apt-get update -q -y diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 21403a44..6bdc2be7 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index 359aef43..f8af4374 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index 9ea6c993..91abf7ce 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index c31a9fa4..08fe8d73 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index de4cb7d2..71543954 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24-cxx20.yml b/.github/workflows/ubuntu24-cxx20.yml index b5e8d205..85167601 100644 --- a/.github/workflows/ubuntu24-cxx20.yml +++ b/.github/workflows/ubuntu24-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 3b002f87..511c7ce3 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6.0.1 + - uses: actions/checkout@v5 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index bf15121b..6769a2a4 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v5 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 10a4c0ac..091b1c5b 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -11,12 +11,12 @@ jobs: matrix: include: - {gen: Visual Studio 17 2022, arch: Win32, cfg: Release} - - {gen: Visual Studio 17 2022, arch: Win32, cfg: Debug} + #- {gen: Visual Studio 17 2022, arch: Win32, cfg: Debug} - {gen: Visual Studio 17 2022, arch: x64, cfg: Release} - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v5 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index ac9de08f..56b51611 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v5 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index 85544c3c..aecbca8f 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v5 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From 0d36a018ef5c2e7b97e0868af950071716350414 Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 00:49:05 +0300 Subject: [PATCH 209/252] Doctest DOCTEST_CONFIG_SUPER_FAST_ASSERTS --- tests/basictest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index d30bc87b..fa974d1e 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1,4 +1,4 @@ -// DOCTEST_CONFIG_SUPER_FAST_ASSERTS // don't enable this biodegradable code! +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include "doctest/doctest.h" From 54d1f5afcf401de7e0aaacd6cbb89eea2cac462c Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 01:07:59 +0300 Subject: [PATCH 210/252] fucking lint --- include/fast_float/float_common.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 76de233d..2dd450d8 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -465,8 +465,10 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // slow emulation routine for 32-bit #if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 -uint64_t_umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, + uint64_t cd, + uint64_t *hi) + noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ From 5652a168af08483187da044f093496fe37f8d20e Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 20:33:43 +0300 Subject: [PATCH 211/252] Update the Readme with fmt to the high performance example. --- README.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3746a6ab..626b57ad 100644 --- a/README.md +++ b/README.md @@ -378,33 +378,36 @@ int main() { } ``` -## You also can also use some additional options (currently only configure by macroses): +## You also can use some additional options to maximize performance and reduce size (made by HedgehogInTheCPP): There is a really common use case in mathematical and other abstract syntax tree (AST)-like parsers that already processes the sign and all other symbols before any number by itself. In this case you can use FastFloat to only parse positive numbers in all supported formats with macros `FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, which significantly reduce the code size -and improve performance. An additional option for high performance and very fast processing is -`FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED`; it reduces data size and speeds up parsing because a data cache is used for your -real data, not for a 256-byte table that flushes out at least 3 cache lines on x86. You also can use macros -`FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds; it's very likely because all parsers need to check the first -character by itself before parsing. Additionally, you can use macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need -`FE_TONEAREST` rounding mode in the parsing; this option also improves performance a bit and reduces code size. +and improve performance. You also can use macros `FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds; +it's very likely because all parsers need to check the first character by itself before parsing. Additionally, you can use +macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need `FE_TONEAREST` rounding mode in the parsing; this option +also improves performance a bit and reduces code size. In the high-performance example, I also use the [fmt library](https://github.com/fmtlib/fmt), which also +supports all C++ standards since C++11. I also recommend using `string_view` everywhere if it's possible; it's available +since C++17, and if you want maximum performance, use the latest compiler with the latest C++ with O3 optimization and LTO! ```C++ #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -#define FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED #define FASTFLOAT_ISNOT_CHECKED_BOUNDS #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #include "fast_float/fast_float.h" -#include +#include "fmt/base.h" +#include int main() { - std::string input = "23.14069263277926900572"; + std::string_view input = "23.14069263277926900572"; double result; auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result); if ((answer.ec != std::errc()) || ((result != 23.14069263277927 /*properly rounded value */))) - { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } - - return EXIT_SUCCESS; + { + fmt::print(stderr, "parsing failure!\n the number {}.", result); + return 1; + } + fmt::print("parsed the number {}.", result); + return 0; } ``` From 3ae10eecaec9853b8d07bea8f2585030651db320 Mon Sep 17 00:00:00 2001 From: HedgehogInTheCPP Date: Fri, 26 Dec 2025 21:36:32 +0300 Subject: [PATCH 212/252] Enhance README with compiler optimization details Updated performance recommendations and compiler flags for C++. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 626b57ad..d6002253 100644 --- a/README.md +++ b/README.md @@ -388,7 +388,10 @@ it's very likely because all parsers need to check the first character by itself macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need `FE_TONEAREST` rounding mode in the parsing; this option also improves performance a bit and reduces code size. In the high-performance example, I also use the [fmt library](https://github.com/fmtlib/fmt), which also supports all C++ standards since C++11. I also recommend using `string_view` everywhere if it's possible; it's available -since C++17, and if you want maximum performance, use the latest compiler with the latest C++ with O3 optimization and LTO! +since C++17, and if you want maximum performance, use the latest compiler with the latest C++ with maximum optimization: +``` +-O3 -DNDEBUG + LTO +``` ```C++ #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #define FASTFLOAT_ISNOT_CHECKED_BOUNDS From 8a518f4308aaf5fbc1f9190b049fc8744a984f6b Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 22:05:09 +0300 Subject: [PATCH 213/252] am_pow_t is probably needs to be 64 bit because some hard coded values that I can't find. --- include/fast_float/float_common.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 2dd450d8..22499cc1 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -86,11 +86,11 @@ template struct parse_options_t { : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ - chars_format format; + const chars_format format; /** The character used as decimal point */ - UC decimal_point; + const UC decimal_point; /** The base used for integers */ - uint_fast8_t base; /* only allowed from 2 to 36 */ + const uint_fast8_t base; /* only allowed from 2 to 36 */ }; using parse_options = parse_options_t; @@ -465,10 +465,8 @@ umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // slow emulation routine for 32-bit #if !defined(__MINGW64__) -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, - uint64_t cd, - uint64_t *hi) - noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +_umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { return umul128_generic(ab, cd, hi); } #endif // !__MINGW64__ @@ -510,7 +508,7 @@ typedef int_fast8_t am_bits_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int_fast16_t am_pow_t; +typedef int_fast64_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = -0x8000; From 7ce53435fc4f7f033780d914433c80cbf4028dfa Mon Sep 17 00:00:00 2001 From: IRainman Date: Fri, 26 Dec 2025 22:11:13 +0300 Subject: [PATCH 214/252] try again. need test refactoring. --- include/fast_float/float_common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 22499cc1..763f7990 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -86,11 +86,11 @@ template struct parse_options_t { : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ - const chars_format format; + chars_format format; /** The character used as decimal point */ - const UC decimal_point; + UC decimal_point; /** The base used for integers */ - const uint_fast8_t base; /* only allowed from 2 to 36 */ + uint_fast8_t base; /* only allowed from 2 to 36 */ }; using parse_options = parse_options_t; From 6cefbb53ba98d81719afbee41b565571aa7d0ca3 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 27 Dec 2025 12:27:02 +0300 Subject: [PATCH 215/252] remove format.cmd: use IDE. --- format.cmd | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 format.cmd diff --git a/format.cmd b/format.cmd deleted file mode 100644 index cc0d283f..00000000 --- a/format.cmd +++ /dev/null @@ -1,28 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -echo Searching for clang-format... -where clang-format >nul 2>&1 -if %errorlevel% neq 0 ( - echo Error: clang-format not found in PATH. Install LLVM or add it to PATH. - exit /b 1 -) - -echo Checking for .clang-format... -if not exist ".clang-format" ( - echo Error: .clang-format config file not found in the current directory. - exit /b 1 -) - -echo Formatting files with .clang-format... -set count=0 -for /R ".\" %%f in (*.cpp, *.h, *.c, *.hpp) do ( - echo "%%f" | findstr /i "\\build\\ \\.vs\\ \\.git\\ \\.github\\" >nul - if !errorlevel! equ 1 ( - echo Formatting "%%f" - clang-format -i -style=file "%%f" - set /a count+=1 - ) -) - -echo Done. Processed !count! files. \ No newline at end of file From 3745f4b00998b233851788d1f8345a2f54d87e77 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 27 Dec 2025 12:56:51 +0300 Subject: [PATCH 216/252] * documentation in the code updated, fixed errors with parsing some special very big exponent numbers. --- include/fast_float/ascii_number.h | 23 ++++++++++++----------- include/fast_float/fast_float.h | 16 ++++++++-------- include/fast_float/float_common.h | 16 +++++++++++----- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index bf356043..01ad6ac7 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -435,7 +435,7 @@ parse_number_string(UC const *p, UC const *pend, } else { // Now let's parse the explicit exponent. while ((p != pend) && is_integer(*p)) { - if (exp_number < std::numeric_limits::max()) { + if (exp_number < am_bias_limit) { // check for exponent overflow if we have too many digits. auto const digit = uint8_t(*p - UC('0')); exp_number = 10 * exp_number + digit; @@ -561,7 +561,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const size_t len = (size_t)(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -581,7 +581,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, if (cpp20_and_in_constexpr()) { digits.as_int = 0; - for (size_t j = 0; j < 4 && j < len; ++j) { + for (uint_fast8_t j = 0; j < 4 && j < len; ++j) { digits.as_str[j] = static_cast(p[j]); } } else if (len >= 4) { @@ -598,12 +598,13 @@ parse_int_string(UC const *p, UC const *pend, T &value, #endif } - uint32_t magic = + const uint32_t magic = ((digits.as_int + 0x46464646u) | (digits.as_int - 0x30303030u)) & 0x80808080u; - uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32 + const auto tz = + static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = (uint32_t)std::min((size_t)nd, len); + nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { value = 0; @@ -617,7 +618,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - size_t rem = len - nd; + uint_fast8_t rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; @@ -632,15 +633,15 @@ parse_int_string(UC const *p, UC const *pend, T &value, digits.as_int ^= 0x30303030u; digits.as_int <<= ((4 - nd) * 8); - uint32_t check = ((digits.as_int >> 24) & 0xff) | - ((digits.as_int >> 8) & 0xff00) | - ((digits.as_int << 8) & 0xff0000); + const uint32_t check = ((digits.as_int >> 24) & 0xff) | + ((digits.as_int >> 8) & 0xff00) | + ((digits.as_int << 8) & 0xff0000); if (check > 0x00020505) { answer.ec = std::errc::result_out_of_range; answer.ptr = p + nd; return answer; } - value = (uint8_t)((0x640a01 * digits.as_int) >> 24); + value = static_cast((0x640a01 * digits.as_int) >> 24); answer.ec = std::errc(); answer.ptr = p + nd; return answer; diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 8540e78f..bfef0223 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -59,11 +59,11 @@ from_chars_advanced(UC const *first, UC const *last, T &value, * `new` or `malloc`). */ FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept; +integer_times_pow10(am_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept; +integer_times_pow10(am_sign_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept; /** * This function is a template overload of `integer_times_pow10()` @@ -73,13 +73,13 @@ integer_times_pow10(int64_t const mantissa, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept; + integer_times_pow10(am_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept; + integer_times_pow10(am_sign_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept; /** * from_chars for integer types. diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 763f7990..ad3e7dc9 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -500,18 +500,24 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { return answer; } -// Value of the mantissa. An unsigned int avoids signed overflows (which are -// bad) +// 64 bit integer is used because mantissa can be up to 53 bits for double. +// Value of the int mantissa in the API. +typedef int_fast64_t am_sign_mant_t; +// An unsigned int avoids signed overflows (which are bad) typedef uint_fast64_t am_mant_t; + // Size of bits in the mantissa and path and rounding shifts typedef int_fast8_t am_bits_t; +// 16 bit signed integer is used for power to cover all double exponents. // Power bias is signed for handling a denormal float // or an invalid mantissa. -typedef int_fast64_t am_pow_t; - +typedef int_fast16_t am_pow_t; // Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static am_pow_t invalid_am_bias = -0x8000; +constexpr static am_pow_t invalid_am_bias = + std::numeric_limits::min() + 1; +constexpr static am_pow_t am_bias_limit = + (std::numeric_limits::max() + 1) / 8; struct alignas(16) adjusted_mantissa { am_mant_t mantissa; From 22605807b8a31bb890967c7c3309a04843050bbe Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 27 Dec 2025 13:01:56 +0300 Subject: [PATCH 217/252] fix compilation error in uint8_t parsing. --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 01ad6ac7..d05b51ba 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -604,7 +604,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, const auto tz = static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = std::min(nd, len); + nd = std::min(static_cast(nd), len); if (nd == 0) { if (has_leading_zeros) { value = 0; From fb1e92c0e2c7b44a512f168ee8fb184dec1e3963 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 27 Dec 2025 15:42:58 +0300 Subject: [PATCH 218/252] code cleanup and type usage fixes. --- include/fast_float/ascii_number.h | 8 ++-- include/fast_float/bigint.h | 62 ++++++++++++++------------ include/fast_float/decimal_to_binary.h | 7 ++- include/fast_float/digit_comparison.h | 2 +- include/fast_float/float_common.h | 54 +++++++++++----------- include/fast_float/parse_number.h | 40 +++++++++-------- 6 files changed, 92 insertions(+), 81 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index d05b51ba..a3ce62be 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -602,9 +602,9 @@ parse_int_string(UC const *p, UC const *pend, T &value, ((digits.as_int + 0x46464646u) | (digits.as_int - 0x30303030u)) & 0x80808080u; const auto tz = - static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 - uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = std::min(static_cast(nd), len); + static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 + am_digits nd = (tz == 32) ? 4 : (tz >> 3); + nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { value = 0; @@ -618,7 +618,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - uint_fast8_t rem = len - nd; + am_digits rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 5aa3faf7..6f4856cf 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -41,7 +41,7 @@ constexpr limb_t bigint_limbs = bigint_bits / limb_bits; template struct stackvec { limb data[size]; // we never need more than 150 limbs - uint_fast8_t length{0}; + limb_t length{0}; FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default; stackvec(stackvec const &) = delete; @@ -100,7 +100,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { limb *ptr = data + length; std::copy_n(s.ptr, s.len(), ptr); - set_len(limb_t(len() + s.len())); + set_len(static_cast(len() + s.len())); } // try to add items to the vector, returning if items were added @@ -123,17 +123,20 @@ template struct stackvec { limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); + set_len(new_len); + } else { + set_len(new_len); } - set_len(new_len); } // try to resize the vector, returning if the vector was resized. FASTFLOAT_CONSTEXPR20 bool try_resize(limb_t new_len, limb value) noexcept { if (new_len > capacity()) { return false; + } else { + resize_unchecked(new_len, value); + return true; } - resize_unchecked(new_len, value); - return true; } // check if any limbs are non-zero after the given index. @@ -259,9 +262,10 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, limb_t start) noexcept { limb carry = y; bool overflow; - while (carry != 0 && start++ != vec.len()) { + while (carry != 0 && start < vec.len()) { vec[start] = scalar_add(vec[start], carry, overflow); carry = limb(overflow); + ++start; } if (carry != 0) { FASTFLOAT_TRY(vec.try_push(carry)); @@ -297,8 +301,8 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, limb_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. - if (x.len() < start || y.len() > limb_t(x.len() - start)) { - FASTFLOAT_TRY(x.try_resize(limb_t(y.len() + start), 0)); + if (x.len() < start || y.len() > static_cast(x.len() - start)) { + FASTFLOAT_TRY(x.try_resize(static_cast(y.len() + start), 0)); } bool carry = false; @@ -317,7 +321,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, // handle overflow if (carry) { - FASTFLOAT_TRY(small_add_from(x, 1, limb_t(y.len() + start))); + FASTFLOAT_TRY(small_add_from(x, 1, static_cast(y.len() + start))); } return true; } @@ -369,7 +373,7 @@ FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { } template struct pow5_tables { - static constexpr uint_fast8_t large_step = 135; + static constexpr limb_t large_step = 135; static constexpr uint64_t small_power_of_5[] = { 1UL, 5UL, @@ -413,7 +417,7 @@ template struct pow5_tables { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint_fast8_t pow5_tables::large_step; +template constexpr limb_t pow5_tables::large_step; template constexpr uint64_t pow5_tables::small_power_of_5[]; @@ -487,7 +491,7 @@ struct bigint : pow5_tables<> { } else if (vec.len() < other.vec.len()) { return -1; } else { - for (limb_t index = vec.len(); index != 0; --index) { + for (limb_t index = vec.len(); index > 0; --index) { limb xi = vec[index - 1]; limb yi = other.vec[index - 1]; if (xi > yi) { @@ -502,7 +506,7 @@ struct bigint : pow5_tables<> { // shift left each limb n bits, carrying over to the new limb // returns true if we were able to shift all the digits. - FASTFLOAT_CONSTEXPR20 bool shl_bits(bigint_bits_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_bits(limb_t n) noexcept { // Internally, for each item, we shift left by n, and add the previous // right shifted limb-bits. // For example, we transform (for u8) shifted left 2, to: @@ -511,10 +515,10 @@ struct bigint : pow5_tables<> { FASTFLOAT_DEBUG_ASSERT(n != 0); FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); - bigint_bits_t const shl = n; - bigint_bits_t const shr = limb_bits - shl; + limb_t const shl = n; + limb_t const shr = limb_bits - shl; limb prev = 0; - for (limb_t index = 0; index != vec.len(); ++index) { + for (limb_t index = 0; index < vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; @@ -528,13 +532,12 @@ struct bigint : pow5_tables<> { } // move the limbs left by `n` limbs. - FASTFLOAT_CONSTEXPR20 bool shl_limbs(bigint_bits_t n) noexcept { + FASTFLOAT_CONSTEXPR20 bool shl_limbs(limb_t n) noexcept { FASTFLOAT_DEBUG_ASSERT(n != 0); if (n + vec.len() > vec.capacity()) { // we can't shift more than the capacity of the vector. return false; - } - if (!vec.is_empty()) { + } else if (!vec.is_empty()) { // move limbs limb *dst = vec.data + n; limb const *src = vec.data; @@ -543,15 +546,17 @@ struct bigint : pow5_tables<> { limb *first = vec.data; limb *last = first + n; ::std::fill(first, last, 0); - vec.set_len(limb_t(n + vec.len())); + vec.set_len(n + vec.len()); + return true; + } else { + return true; } - return true; } // move the limbs left by `n` bits. FASTFLOAT_CONSTEXPR20 bool shl(bigint_bits_t n) noexcept { - bigint_bits_t const rem = n % limb_bits; - bigint_bits_t const div = n / limb_bits; + auto const rem = static_cast(n % limb_bits); + auto const div = static_cast(n / limb_bits); if (rem != 0) { FASTFLOAT_TRY(shl_bits(rem)); } @@ -566,14 +571,15 @@ struct bigint : pow5_tables<> { if (vec.is_empty()) { // empty vector, no bits, no zeros. return 0; - } + } else { #ifdef FASTFLOAT_64BIT_LIMB - return leading_zeroes(vec.rindex(0)); + return leading_zeroes(vec.rindex(0)); #else - // no use defining a specialized leading_zeroes for a 32-bit type. - uint64_t r0 = vec.rindex(0); - return leading_zeroes(r0 << 32); + // no use defining a specialized leading_zeroes for a 32-bit type. + uint64_t r0 = vec.rindex(0); + return leading_zeroes(r0 << 32); #endif + } } // get the number of bits in the bigint. diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 8d4b6a21..a10d3c8d 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -72,7 +72,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, limb_t lz) noexcept { - limb_t const hilz = static_cast((w >> 63) ^ 1); + auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = @@ -139,9 +139,8 @@ compute_float(int64_t q, uint64_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - auto const upperbit = limb_t(product.high >> 63); - auto const shift = - limb_t(upperbit + 64 - binary::mantissa_explicit_bits() - 3); + limb_t const upperbit = static_cast(product.high >> 63); + limb_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; answer.mantissa = product.high >> shift; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 22c8dd34..c7837e1c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -139,7 +139,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round_nearest_tie_even(adjusted_mantissa &am, am_pow_t shift, callback cb) noexcept { am_mant_t const mask = - (shift == 64) ? UINT64_MAX : (am_mant_t(1) << shift) - 1; + (shift == 64) ? std::numeric_limits::max() : (am_mant_t(1) << shift) - 1; am_mant_t const halfway = (shift == 0) ? 0 : am_mant_t(1) << (shift - 1); am_mant_t truncated_bits = am.mantissa & mask; bool is_above = truncated_bits > halfway; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index ad3e7dc9..7d54548b 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -41,6 +41,8 @@ typedef uint_fast8_t limb_t; typedef uint_fast8_t chars_format_t; +typedef uint_fast8_t base_t; + enum class chars_format : chars_format_t; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -82,7 +84,7 @@ using from_chars_result = from_chars_result_t; template struct parse_options_t { constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), - uint_fast8_t const b = 10) noexcept + base_t const b = 10) noexcept : format(fmt), decimal_point(dot), base(b) {} /** Which number formats are accepted */ @@ -90,7 +92,7 @@ template struct parse_options_t { /** The character used as decimal point */ UC decimal_point; /** The base used for integers */ - uint_fast8_t base; /* only allowed from 2 to 36 */ + base_t base; /* only allowed from 2 to 36 */ }; using parse_options = parse_options_t; @@ -298,6 +300,10 @@ struct is_supported_char_type }; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN + +// TODO use SSE4.2 there when SSE2 compiler switch in MSVC +// or in other compiler SSE4.2 available. + // Compares two ASCII strings in a case insensitive manner. template inline FASTFLOAT_CONSTEXPR14 bool @@ -320,16 +326,17 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - am_digits length; + uint_fast16_t length; - constexpr span(T const *_ptr, am_digits _length) noexcept + constexpr span(T const *_ptr, uint_fast16_t _length) noexcept : ptr(_ptr), length(_length) {} constexpr span() noexcept : ptr(nullptr), length(0) {} - constexpr am_digits len() const noexcept { return length; } + constexpr uint_fast16_t len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T &operator[](am_digits index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T & + operator[](uint_fast16_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -345,7 +352,7 @@ struct alignas(16) value128 { constexpr value128() noexcept : low(0), high(0) {} }; -/* Helper C++14 constexpr generic implementation of leading_zeroes */ +/* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0xffffffff00000000)) { @@ -371,7 +378,7 @@ leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - (limb_t)last_bit; + return 63 - static_cast(last_bit); } /* result might be undefined when input_num is zero */ @@ -388,22 +395,22 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return (limb_t)(63 - leading_zero); + return static_cast(63 - leading_zero); #else - return (limb_t)leading_zeroes_generic(input_num); + return static_cast(leading_zeroes_generic(input_num)); #endif #else - return (limb_t)__builtin_clzll(input_num); + return static_cast(__builtin_clzll(input_num)); #endif } /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t countr_zero_generic_32(uint32_t input_num) { if (input_num == 0) { return 32; } - int last_bit = 0; + uint32_t last_bit = 0; if (!(input_num & 0x0000FFFF)) { input_num >>= 16; last_bit |= 16; @@ -1099,7 +1106,6 @@ binary_format::hidden_bit_mask() { return 0x0010000000000000; } -// Fix for C2672: Ensure bit_cast is called with explicit template arguments template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -1120,7 +1126,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN template struct space_lut { - static constexpr uint_fast8_t value[] = { + static constexpr uint8_t value[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1136,12 +1142,12 @@ template struct space_lut { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint_fast8_t space_lut::value[]; +template constexpr uint8_t space_lut::value[]; #endif template constexpr bool is_space(UC c) { - return c < 256 && space_lut<>::value[uint_fast8_t(c)]; + return c < 256 && space_lut<>::value[uint8_t(c)]; } #endif @@ -1227,7 +1233,7 @@ template struct int_luts { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - static constexpr uint_fast8_t maxdigits_u64[] = { + static constexpr limb_t maxdigits_u64[] = { 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; @@ -1248,16 +1254,16 @@ template struct int_luts { #if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE -template constexpr uint_fast8_t int_luts::chdigit[]; +template constexpr uint8_t int_luts::chdigit[]; -template constexpr uint_fast8_t int_luts::maxdigits_u64[]; +template constexpr limb_t int_luts::maxdigits_u64[]; template constexpr uint64_t int_luts::min_safe_u64[]; #endif template -fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { +fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) noexcept { // wchar_t and char can be signed, so we need to be careful. using UnsignedUC = typename std::make_unsigned::type; return int_luts<>::chdigit[static_cast( @@ -1266,15 +1272,13 @@ fastfloat_really_inline constexpr uint_fast8_t ch_to_digit(UC c) noexcept { -((static_cast(c) & ~0xFFull) == 0)))]; } -fastfloat_really_inline constexpr uint_fast8_t -max_digits_u64(uint_fast8_t base) noexcept { +fastfloat_really_inline constexpr limb_t max_digits_u64(base_t base) noexcept { return int_luts<>::maxdigits_u64[base - 2]; } // If a u64 is exactly max_digits_u64() in length, this is // the value below which it has definitely overflowed. -fastfloat_really_inline constexpr uint64_t -min_safe_u64(uint_fast8_t base) noexcept { +fastfloat_really_inline constexpr uint64_t min_safe_u64(base_t base) noexcept { return int_luts<>::min_safe_u64[base - 2]; } diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index eb30818c..97cbf04e 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -27,12 +27,13 @@ from_chars_result_t const chars_format fmt) noexcept { from_chars_result_t answer{}; answer.ptr = first; - answer.ec = std::errc(); // be optimistic + answer.ec = std::errc(); // be optimistic + FASTFLOAT_ASSUME(first < last); // so dereference without checks bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if ((*first == UC('-')) || + if (minusSign || ((chars_format_t(fmt & chars_format::allow_leading_plus)) && (*first == UC('+')))) { ++first; @@ -375,7 +376,7 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - uint_fast8_t const base) noexcept { + base_t const base) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); @@ -389,8 +390,8 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(uint64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept { + integer_times_pow10(am_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -412,8 +413,8 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(int64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept { + integer_times_pow10(am_sign_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept { #ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN FASTFLOAT_ASSUME(mantissa >= 0); const am_mant_t m = static_cast(mantissa); @@ -441,14 +442,14 @@ FASTFLOAT_CONSTEXPR20 } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(uint64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept { +integer_times_pow10(am_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(int64_t const mantissa, - int_fast16_t const decimal_exponent) noexcept { +integer_times_pow10(am_sign_mant_t const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } @@ -460,8 +461,8 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && !std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), + integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -471,23 +472,24 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), + integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), decimal_exponent); +integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, int_fast16_t decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), decimal_exponent); +integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + return integer_times_pow10(static_cast(mantissa), + decimal_exponent); } template From 812d89ec9b674a34a586aa89626bf21ed1c11c8f Mon Sep 17 00:00:00 2001 From: IRainman Date: Sat, 27 Dec 2025 15:55:58 +0300 Subject: [PATCH 219/252] type usage fixes. --- include/fast_float/ascii_number.h | 8 ++++---- include/fast_float/digit_comparison.h | 4 ++-- include/fast_float/float_common.h | 10 +++++----- include/fast_float/parse_number.h | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a3ce62be..d42da421 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -561,7 +561,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const auto len = static_cast(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -602,8 +602,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, ((digits.as_int + 0x46464646u) | (digits.as_int - 0x30303030u)) & 0x80808080u; const auto tz = - static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 - am_digits nd = (tz == 32) ? 4 : (tz >> 3); + static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 + limb_t nd = (tz == 32) ? 4 : (tz >> 3); nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { @@ -618,7 +618,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - am_digits rem = len - nd; + limb_t rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index c7837e1c..b49acea6 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -138,8 +138,8 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round_nearest_tie_even(adjusted_mantissa &am, am_pow_t shift, callback cb) noexcept { - am_mant_t const mask = - (shift == 64) ? std::numeric_limits::max() : (am_mant_t(1) << shift) - 1; + am_mant_t const mask = (shift == 64) ? std::numeric_limits::max() + : (am_mant_t(1) << shift) - 1; am_mant_t const halfway = (shift == 0) ? 0 : am_mant_t(1) << (shift - 1); am_mant_t truncated_bits = am.mantissa & mask; bool is_above = truncated_bits > halfway; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7d54548b..69b3c932 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -405,7 +405,7 @@ leading_zeroes(uint64_t input_num) noexcept { } /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t countr_zero_generic_32(uint32_t input_num) { if (input_num == 0) { return 32; @@ -430,11 +430,11 @@ countr_zero_generic_32(uint32_t input_num) { if (!(input_num & 0x1)) { last_bit |= 1; } - return last_bit; + return static_cast(last_bit); } /* count trailing zeroes for 32-bit integers */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t countr_zero_32(uint32_t input_num) { if (cpp20_and_in_constexpr()) { return countr_zero_generic_32(input_num); @@ -442,11 +442,11 @@ countr_zero_32(uint32_t input_num) { #ifdef FASTFLOAT_VISUAL_STUDIO unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, input_num)) { - return (int)trailing_zero; + return static_cast(trailing_zero); } return 32; #else - return input_num == 0 ? 32 : __builtin_ctz(input_num); + return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); #endif } diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 97cbf04e..750ad32a 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -33,9 +33,8 @@ from_chars_result_t bool const minusSign = (*first == UC('-')); // C++17 20.19.3.(7.1) explicitly forbids '+' sign here - if (minusSign || - ((chars_format_t(fmt & chars_format::allow_leading_plus)) && - (*first == UC('+')))) { + if (minusSign || ((chars_format_t(fmt & chars_format::allow_leading_plus)) && + (*first == UC('+')))) { ++first; } @@ -481,7 +480,8 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), decimal_exponent); + return integer_times_pow10(static_cast(mantissa), + decimal_exponent); } template From 62bc4b4458dfbfd549e93b3453d53840b9b843a5 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 14:16:14 +0300 Subject: [PATCH 220/252] type usage fixes. --- include/fast_float/ascii_number.h | 6 +++--- include/fast_float/float_common.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 3a032591..8ccb7361 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -561,7 +561,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const auto len = static_cast(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -605,7 +605,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, const uint32_t magic = ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; const auto tz = - static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 + static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 limb_t nd = (tz == 32) ? 4 : (tz >> 3); nd = std::min(nd, len); if (nd == 0) { @@ -621,7 +621,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - limb_t rem = len - nd; + am_digits rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 73a1f077..ae1c26b6 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -410,7 +410,7 @@ countr_zero_generic_32(uint32_t input_num) { if (input_num == 0) { return 32; } - uint32_t last_bit = 0; + uint_fast16_t last_bit = 0; if (!(input_num & 0x0000FFFF)) { input_num >>= 16; last_bit |= 16; From 59c873d028f81cfd0e01d8cac524cc0afd67f256 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 16:43:33 +0300 Subject: [PATCH 221/252] cleanup. --- tests/basictest.cpp | 58 ++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index fa974d1e..1a5537bb 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -21,16 +21,6 @@ #endif // #ifndef FASTFLOAT_CONSTEXPR_TESTS #endif // FASTFLOAT_IS_CONSTEXPR -// MSVC's constexpr evaluation and some constexpr-friendly std library pieces -// (like i/o and certain std::numeric_limits members) aren't suitable for the -// compile-time tests in this file on MSVC; disable the constexpr tests when -// compiling with MSVC (but allow them for clang/clang-cl). -#if defined(_MSC_VER) && !defined(__clang__) -#ifdef FASTFLOAT_CONSTEXPR_TESTS -#undef FASTFLOAT_CONSTEXPR_TESTS -#endif -#endif - #if FASTFLOAT_HAS_BIT_CAST #include #endif @@ -79,7 +69,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -constexpr std::string_view round_name(int const d) noexcept { +char const *round_name(int d) { switch (d) { case FE_UPWARD: return "FE_UPWARD"; @@ -117,9 +107,9 @@ TEST_CASE("system_info") { #endif #ifdef FASTFLOAT_IS_BIG_ENDIAN #if FASTFLOAT_IS_BIG_ENDIAN - std::cout << "big endian" << std::endl; + printf("big endian\n"); #else - std::cout << "little endian" << std::endl; + printf("little endian\n"); #endif #endif #ifdef FASTFLOAT_32BIT @@ -628,7 +618,7 @@ TEST_CASE("issue8") { "752384674818467669405132000568127145263560827785771342757789609173637178" "721468440901224953430146549585371050792279689258923542019956112129021960" "864034418159813629774771309960518707211349999998372978"; - for (int i = 0; i != 16; ++i) { + for (int i = 0; i < 16; i++) { // Parse all but the last i chars. We should still get 3.141ish. double d = 0.0; auto answer = fast_float::from_chars(s, s + strlen(s) - i, d); @@ -929,9 +919,9 @@ uint16_t get_mantissa(std::bfloat16_t f) { } #endif -std::string append_zeros(std::string_view str, size_t const number_of_zeros) { +std::string append_zeros(std::string str, size_t number_of_zeros) { std::string answer(str); - for (size_t i = 0; i++ != number_of_zeros;) { + for (size_t i = 0; i < number_of_zeros; i++) { answer += "0"; } return answer; @@ -957,7 +947,7 @@ constexpr void check_basic_test_result(stringtype str, result_type result, #define FASTFLOAT_CHECK_EQ(...) \ if constexpr (diag == Diag::runtime) { \ char narrow[global_string_capacity]{}; \ - for (size_t i = 0; i++ != str.size();) { \ + for (size_t i = 0; i < str.size(); i++) { \ narrow[i] = char(str[i]); \ } \ INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \ @@ -1016,7 +1006,7 @@ constexpr void basic_test(std::string_view str, T expected, // We give plenty of memory: 2048 characters. char16_t u16[global_string_capacity]{}; - for (size_t i = 0; i++ != str.size();) { + for (size_t i = 0; i < str.size(); i++) { u16[i] = char16_t(str[i]); } @@ -1025,7 +1015,7 @@ constexpr void basic_test(std::string_view str, T expected, actual, expected, expected_ec); char32_t u32[global_string_capacity]{}; - for (size_t i = 0; i++ != str.size();) { + for (size_t i = 0; i < str.size(); i++) { u32[i] = char32_t(str[i]); } @@ -2136,9 +2126,8 @@ TEST_CASE("bfloat16.general") { #endif template -void verify_integer_times_pow10_result(Int const mantissa, - int_fast16_t const decimal_exponent, - T const actual, U const expected) { +void verify_integer_times_pow10_result(Int mantissa, int decimal_exponent, + T actual, U expected) { static_assert(std::is_same::value, "expected and actual types must match"); @@ -2155,8 +2144,8 @@ void verify_integer_times_pow10_result(Int const mantissa, } template -T calculate_integer_times_pow10_expected_result( - Int const mantissa, int_fast16_t const decimal_exponent) { +T calculate_integer_times_pow10_expected_result(Int mantissa, + int decimal_exponent) { std::string constructed_string = std::to_string(mantissa) + "e" + std::to_string(decimal_exponent); T expected_result; @@ -2169,9 +2158,8 @@ T calculate_integer_times_pow10_expected_result( } template -void verify_integer_times_pow10_dflt(Int const mantissa, - int_fast16_t const decimal_exponent, - double const expected) { +void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent, + double expected) { static_assert(std::is_integral::value); // the "default" overload @@ -2183,8 +2171,7 @@ void verify_integer_times_pow10_dflt(Int const mantissa, } template -void verify_integer_times_pow10_dflt(Int const mantissa, - int_fast16_t const decimal_exponent) { +void verify_integer_times_pow10_dflt(Int mantissa, int decimal_exponent) { static_assert(std::is_integral::value); const auto expected_result = @@ -2195,9 +2182,8 @@ void verify_integer_times_pow10_dflt(Int const mantissa, } template -void verify_integer_times_pow10(Int const mantissa, - int_fast16_t const decimal_exponent, - T const expected) { +void verify_integer_times_pow10(Int mantissa, int decimal_exponent, + T expected) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2210,8 +2196,7 @@ void verify_integer_times_pow10(Int const mantissa, } template -void verify_integer_times_pow10(Int const mantissa, - int_fast16_t const decimal_exponent) { +void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { static_assert(std::is_floating_point::value); static_assert(std::is_integral::value); @@ -2223,8 +2208,7 @@ void verify_integer_times_pow10(Int const mantissa, namespace all_supported_types { template -void verify_integer_times_pow10(Int const mantissa, - int_fast16_t const decimal_exponent) { +void verify_integer_times_pow10(Int mantissa, int decimal_exponent) { static_assert(std::is_integral::value); // verify the "default" overload @@ -2329,7 +2313,7 @@ TEST_CASE("integer_times_pow10") { for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) { fesetround(mode); - INFO("fesetround(): " << round_name(mode)); + INFO("fesetround(): " << std::string{round_name(mode)}); struct Guard { ~Guard() { fesetround(FE_TONEAREST); } From 5bc96372bdd8879a2344d29d922e3d877ef60aa2 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 17:41:04 +0300 Subject: [PATCH 222/252] type usage fixes. fix for FASTFLOAT_ISNOT_CHECKED_BOUNDS if FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN isn't enabled. --- include/fast_float/fast_float.h | 2 +- include/fast_float/parse_number.h | 32 ++++++++++++++++++------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index bfef0223..38c34e43 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -88,7 +88,7 @@ template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - uint_fast8_t const base = 10) noexcept; + base_t const base = 10) noexcept; } // namespace fast_float diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 750ad32a..913fc083 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -336,11 +336,13 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, ++first; } } -#endif +#else #ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS // We are in parser code with external loop that checks bounds. FASTFLOAT_ASSUME(first < last); -#else +#endif +#endif +#ifndef FASTFLOAT_ISNOT_CHECKED_BOUNDS if (first == last) { answer.ec = std::errc::invalid_argument; answer.ptr = first; @@ -414,13 +416,12 @@ FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(am_sign_mant_t const mantissa, am_pow_t const decimal_exponent) noexcept { -#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - FASTFLOAT_ASSUME(mantissa >= 0); - const am_mant_t m = static_cast(mantissa); -#else +#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN const bool is_negative = mantissa < 0; - const am_mant_t m = - static_cast(is_negative ? -mantissa : mantissa); + const auto m = static_cast(is_negative ? -mantissa : mantissa); +#else + FASTFLOAT_ASSUME(mantissa >= 0); + const auto m = static_cast(mantissa); #endif T value; if (clinger_fast_path_impl(m, decimal_exponent, @@ -460,7 +461,8 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && !std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + integer_times_pow10(Int const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -471,7 +473,8 @@ FASTFLOAT_CONSTEXPR20 std::is_integral::value && std::is_signed::value, T>::type - integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { + integer_times_pow10(Int const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -479,7 +482,8 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { +integer_times_pow10(Int const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -487,7 +491,8 @@ integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int mantissa, am_pow_t decimal_exponent) noexcept { +integer_times_pow10(Int const mantissa, + am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -508,10 +513,11 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value, ++first; } } -#endif +#else #ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS // We are in parser code with external loop that checks bounds. FASTFLOAT_ASSUME(first < last); +#endif #endif if ( #ifndef FASTFLOAT_ISNOT_CHECKED_BOUNDS From 5c6a6c274262d01f2d19a51c39abaa662474c8e9 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 18:35:11 +0300 Subject: [PATCH 223/252] type usage fixes. --- include/fast_float/ascii_number.h | 5 ++--- include/fast_float/bigint.h | 4 ++-- include/fast_float/decimal_to_binary.h | 8 ++++---- include/fast_float/float_common.h | 22 +++++++++++----------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 8ccb7361..9fa72c23 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -604,9 +604,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, const uint32_t magic = ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; - const auto tz = - static_cast(countr_zero_32(magic)); // 7, 15, 23, 31, or 32 - limb_t nd = (tz == 32) ? 4 : (tz >> 3); + const auto tz = countr_zero_32(magic); // 7, 15, 23, 31, or 32 + am_digits nd = (tz == 32) ? 4 : (tz >> 3); nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 6f4856cf..8baf86c8 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -567,7 +567,7 @@ struct bigint : pow5_tables<> { } // get the number of leading zeros in the bigint. - FASTFLOAT_CONSTEXPR20 limb_t ctlz() const noexcept { + FASTFLOAT_CONSTEXPR20 bigint_bits_t ctlz() const noexcept { if (vec.is_empty()) { // empty vector, no bits, no zeros. return 0; @@ -584,7 +584,7 @@ struct bigint : pow5_tables<> { // get the number of bits in the bigint. FASTFLOAT_CONSTEXPR20 bigint_bits_t bit_length() const noexcept { - limb_t lz = ctlz(); + bigint_bits_t lz = ctlz(); return static_cast(limb_bits * vec.len() - lz); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index a10d3c8d..dd022c96 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -71,8 +71,8 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(int64_t q, uint64_t w, limb_t lz) noexcept { - auto const hilz = static_cast((w >> 63) ^ 1); +compute_error_scaled(int64_t q, uint64_t w, am_digits lz) noexcept { + auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = @@ -87,7 +87,7 @@ compute_error_scaled(int64_t q, uint64_t w, limb_t lz) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept { - limb_t const lz = leading_zeroes(w); + am_digits const lz = leading_zeroes(w); w <<= lz; value128 product = compute_product_approximation(q, w); @@ -119,7 +119,7 @@ compute_float(int64_t q, uint64_t w) noexcept { // powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. - limb_t const lz = leading_zeroes(w); + am_digits const lz = leading_zeroes(w); w <<= lz; // The required precision is binary::mantissa_explicit_bits() + 3 because diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index ae1c26b6..4a430043 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -353,7 +353,7 @@ struct alignas(16) value128 { }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; @@ -378,11 +378,11 @@ leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - static_cast(last_bit); + return 63 - static_cast(last_bit); } /* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); @@ -395,17 +395,17 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return static_cast(63 - leading_zero); + return static_cast(63 - leading_zero); #else - return static_cast(leading_zeroes_generic(input_num)); + return static_cast(leading_zeroes_generic(input_num)); #endif #else - return static_cast(__builtin_clzll(input_num)); + return static_cast(__builtin_clzll(input_num)); #endif } /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits countr_zero_generic_32(uint32_t input_num) { if (input_num == 0) { return 32; @@ -430,11 +430,11 @@ countr_zero_generic_32(uint32_t input_num) { if (!(input_num & 0x1)) { last_bit |= 1; } - return static_cast(last_bit); + return static_cast(last_bit); } /* count trailing zeroes for 32-bit integers */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits countr_zero_32(uint32_t input_num) { if (cpp20_and_in_constexpr()) { return countr_zero_generic_32(input_num); @@ -442,11 +442,11 @@ countr_zero_32(uint32_t input_num) { #ifdef FASTFLOAT_VISUAL_STUDIO unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, input_num)) { - return static_cast(trailing_zero); + return static_cast(trailing_zero); } return 32; #else - return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); + return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); #endif } From 8f49511980262d967d55ce4f3c22f10e7797d5fe Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 19:57:45 +0300 Subject: [PATCH 224/252] noexcept --- include/fast_float/float_common.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 4a430043..cd5e32e6 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -39,8 +39,10 @@ typedef uint_fast16_t am_digits; // The number of bits in the limb. typedef uint_fast8_t limb_t; +// Type for enum chars_format. typedef uint_fast8_t chars_format_t; +// Type for base. typedef uint_fast8_t base_t; enum class chars_format : chars_format_t; @@ -105,7 +107,7 @@ using parse_options = parse_options_t; namespace fast_float { template -FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) { +FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) noexcept { #if FASTFLOAT_HAS_BIT_CAST return std::bit_cast(from); #else From 489703f99dfcb186479101aef624c578ef5a80cd Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 19:59:46 +0300 Subject: [PATCH 225/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 16 +++++++--------- include/fast_float/digit_comparison.h | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index dd022c96..81b28f2c 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -19,7 +19,7 @@ namespace fast_float { // template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 -compute_product_approximation(int64_t q, uint64_t w) noexcept { +compute_product_approximation(am_pow_t q, am_mant_t w) noexcept { am_pow_t const index = 2 * am_pow_t(q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact // because The line value128 firstproduct = full_multiplication(w, @@ -71,14 +71,13 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(int64_t q, uint64_t w, am_digits lz) noexcept { - auto const hilz = static_cast((w >> 63) ^ 1); +compute_error_scaled(am_pow_t q, am_mant_t w, am_digits lz) noexcept { + auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); - answer.power2 = am_pow_t(detail::power(am_pow_t(q)) + bias - hilz - lz - 62 + - invalid_am_bias); + answer.power2 = detail::power(q) + bias - hilz - lz - 62 + invalid_am_bias; return answer; } @@ -86,7 +85,7 @@ compute_error_scaled(int64_t q, uint64_t w, am_digits lz) noexcept { // the power2 in the exponent will be adjusted by invalid_am_bias. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -compute_error(int64_t q, uint64_t w) noexcept { +compute_error(am_pow_t q, am_mant_t w) noexcept { am_digits const lz = leading_zeroes(w); w <<= lz; value128 product = @@ -101,7 +100,7 @@ compute_error(int64_t q, uint64_t w) noexcept { // should recompute in such cases. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa -compute_float(int64_t q, uint64_t w) noexcept { +compute_float(am_pow_t q, am_mant_t w) noexcept { adjusted_mantissa answer; if ((w == 0) || (q < binary::smallest_power_of_ten())) { answer.power2 = 0; @@ -144,8 +143,7 @@ compute_float(int64_t q, uint64_t w) noexcept { answer.mantissa = product.high >> shift; - answer.power2 = am_pow_t(detail::power(am_pow_t(q)) + upperbit - lz - - binary::minimum_exponent()); + answer.power2 = detail::power(q) + upperbit - lz - binary::minimum_exponent(); if (answer.power2 <= 0) { // we have a subnormal or very small value. // Here have that answer.power2 <= 0 so -answer.power2 >= 0 if (-answer.power2 + 1 >= diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index b49acea6..d7a3c95f 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -76,8 +76,8 @@ to_extended(T const value) noexcept { am.mantissa = bits & mantissa_mask; } else { // normal - am.power2 = am_pow_t((bits & exponent_mask) >> - binary_format::mantissa_explicit_bits()); + am.power2 = static_cast(bits & exponent_mask) >> + binary_format::mantissa_explicit_bits(); am.power2 -= bias; am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; } From 37152ead573ad72ed2806c013544658f07850179 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 21:52:57 +0300 Subject: [PATCH 226/252] type usage fixes. --- include/fast_float/ascii_number.h | 6 +- include/fast_float/bigint.h | 6 +- include/fast_float/decimal_to_binary.h | 10 +-- include/fast_float/fast_table.h | 2 +- include/fast_float/float_common.h | 104 +++++++++++++------------ 5 files changed, 65 insertions(+), 63 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9fa72c23..14b37bc7 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -561,7 +561,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const auto len = static_cast(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -605,7 +605,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, const uint32_t magic = ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; const auto tz = countr_zero_32(magic); // 7, 15, 23, 31, or 32 - am_digits nd = (tz == 32) ? 4 : (tz >> 3); + am_bits_t nd = (tz == 32) ? 4 : (tz >> 3); nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { @@ -620,7 +620,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - am_digits rem = len - nd; + am_bits_t rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index 8baf86c8..bac994fe 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -169,18 +169,18 @@ empty_hi64(bool &truncated) noexcept { fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t uint64_hi64(uint64_t r0, bool &truncated) noexcept { truncated = false; - int shl = leading_zeroes(r0); + auto shl = leading_zeroes(r0); return r0 << shl; } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept { - int shl = leading_zeroes(r0); + auto shl = leading_zeroes(r0); if (shl == 0) { truncated = r1 != 0; return r0; } else { - int shr = 64 - shl; + limb_t shr = 64 - shl; truncated = (r1 << shl) != 0; return (r0 << shl) | (r1 >> shr); } diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 81b28f2c..5c67e7bf 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -20,7 +20,7 @@ namespace fast_float { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(am_pow_t q, am_mant_t w) noexcept { - am_pow_t const index = 2 * am_pow_t(q - powers::smallest_power_of_five); + am_pow_t const index = 2 * (q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact // because The line value128 firstproduct = full_multiplication(w, // power_of_five_128[index]); gives the exact answer. @@ -71,7 +71,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(am_pow_t q, am_mant_t w, am_digits lz) noexcept { +compute_error_scaled(am_pow_t q, am_mant_t w, am_bits_t lz) noexcept { auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; @@ -86,7 +86,7 @@ compute_error_scaled(am_pow_t q, am_mant_t w, am_digits lz) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(am_pow_t q, am_mant_t w) noexcept { - am_digits const lz = leading_zeroes(w); + auto const lz = leading_zeroes(w); w <<= lz; value128 product = compute_product_approximation(q, w); @@ -118,7 +118,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // powers::largest_power_of_five]. // We want the most significant bit of i to be 1. Shift if needed. - am_digits const lz = leading_zeroes(w); + auto const lz = leading_zeroes(w); w <<= lz; // The required precision is binary::mantissa_explicit_bits() + 3 because @@ -138,7 +138,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - limb_t const upperbit = static_cast(product.high >> 63); + auto const upperbit = static_cast(product.high >> 63); limb_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; answer.mantissa = product.high >> shift; diff --git a/include/fast_float/fast_table.h b/include/fast_float/fast_table.h index 6a6f901a..c3c5c5c2 100644 --- a/include/fast_float/fast_table.h +++ b/include/fast_float/fast_table.h @@ -33,7 +33,7 @@ template struct powers_template { binary_format::smallest_power_of_ten(); constexpr static am_pow_t largest_power_of_five = binary_format::largest_power_of_ten(); - constexpr static am_digits number_of_entries = + constexpr static am_pow_t number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1); // Powers of five from 5^-342 all the way to 5^308 rounded toward one. constexpr static am_mant_t power_of_five_128[number_of_entries] = { diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index cd5e32e6..345631e4 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -33,12 +33,31 @@ namespace fast_float { +// 64 bit integer is used because mantissa can be up to 53 bits for double. +// Value of the int mantissa in the API. +typedef int_fast64_t am_sign_mant_t; +// An unsigned int avoids signed overflows (which are bad) +typedef uint_fast64_t am_mant_t; + // The number of digits in the mantissa. typedef uint_fast16_t am_digits; // The number of bits in the limb. typedef uint_fast8_t limb_t; +// Size of bits in the mantissa and path and rounding shifts +typedef int_fast8_t am_bits_t; + +// 16 bit signed integer is used for power to cover all double exponents. +typedef int16_t am_pow_t; +// Power bias is signed for handling a denormal float +// or an invalid mantissa. +// Bias so we can get the real exponent with an invalid adjusted_mantissa. +constexpr static am_pow_t invalid_am_bias = + std::numeric_limits::min() + 1; +constexpr static am_pow_t am_bias_limit = + (std::numeric_limits::max() / 8) - 1; + // Type for enum chars_format. typedef uint_fast8_t chars_format_t; @@ -355,8 +374,11 @@ struct alignas(16) value128 { }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits -leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t +leading_zeroes_generic(uint64_t input_num) noexcept { + assert(input_num > 0); + FASTFLOAT_ASSUME(input_num > 0); + uint_fast32_t last_bit = 0; if (input_num & uint64_t(0xffffffff00000000)) { input_num >>= 32; last_bit |= 32; @@ -380,11 +402,11 @@ leading_zeroes_generic(uint64_t input_num, uint32_t last_bit = 0) noexcept { if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ last_bit |= 1; } - return 63 - static_cast(last_bit); + return 63 - static_cast(last_bit); } /* result might be undefined when input_num is zero */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t leading_zeroes(uint64_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); @@ -397,21 +419,20 @@ leading_zeroes(uint64_t input_num) noexcept { // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); - return static_cast(63 - leading_zero); + return static_cast(63 - leading_zero); #else - return static_cast(leading_zeroes_generic(input_num)); + return static_cast(leading_zeroes_generic(input_num)); #endif #else - return static_cast(__builtin_clzll(input_num)); + return static_cast(__builtin_clzll(input_num)); #endif } /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR14 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t countr_zero_generic_32(uint32_t input_num) { - if (input_num == 0) { - return 32; - } + assert(input_num > 0); + FASTFLOAT_ASSUME(input_num > 0); uint_fast16_t last_bit = 0; if (!(input_num & 0x0000FFFF)) { input_num >>= 16; @@ -432,11 +453,11 @@ countr_zero_generic_32(uint32_t input_num) { if (!(input_num & 0x1)) { last_bit |= 1; } - return static_cast(last_bit); + return static_cast(last_bit); } /* count trailing zeroes for 32-bit integers */ -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 am_digits +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t countr_zero_32(uint32_t input_num) { if (cpp20_and_in_constexpr()) { return countr_zero_generic_32(input_num); @@ -444,11 +465,11 @@ countr_zero_32(uint32_t input_num) { #ifdef FASTFLOAT_VISUAL_STUDIO unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, input_num)) { - return static_cast(trailing_zero); + return static_cast(trailing_zero); } return 32; #else - return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); + return input_num == 0 ? 32 : static_cast(__builtin_ctz(input_num)); #endif } @@ -509,25 +530,6 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { return answer; } -// 64 bit integer is used because mantissa can be up to 53 bits for double. -// Value of the int mantissa in the API. -typedef int_fast64_t am_sign_mant_t; -// An unsigned int avoids signed overflows (which are bad) -typedef uint_fast64_t am_mant_t; - -// Size of bits in the mantissa and path and rounding shifts -typedef int_fast8_t am_bits_t; - -// 16 bit signed integer is used for power to cover all double exponents. -// Power bias is signed for handling a denormal float -// or an invalid mantissa. -typedef int_fast16_t am_pow_t; -// Bias so we can get the real exponent with an invalid adjusted_mantissa. -constexpr static am_pow_t invalid_am_bias = - std::numeric_limits::min() + 1; -constexpr static am_pow_t am_bias_limit = - (std::numeric_limits::max() + 1) / 8; - struct alignas(16) adjusted_mantissa { am_mant_t mantissa; am_pow_t power2; @@ -550,21 +552,21 @@ template struct binary_format_lookup_tables; template struct binary_format : binary_format_lookup_tables { using equiv_uint = equiv_uint_t; - static constexpr limb_t mantissa_explicit_bits(); + static constexpr am_bits_t mantissa_explicit_bits(); static constexpr am_pow_t minimum_exponent(); static constexpr am_pow_t infinite_power(); static constexpr am_bits_t sign_index(); static constexpr am_bits_t min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_bits_t max_exponent_fast_path(); - static constexpr am_bits_t max_exponent_round_to_even(); - static constexpr am_bits_t min_exponent_round_to_even(); - static constexpr equiv_uint max_mantissa_fast_path(am_pow_t power); + static constexpr am_pow_t max_exponent_round_to_even(); + static constexpr am_pow_t min_exponent_round_to_even(); + static constexpr equiv_uint max_mantissa_fast_path(am_pow_t const power); static constexpr equiv_uint max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_pow_t largest_power_of_ten(); static constexpr am_pow_t smallest_power_of_ten(); - static constexpr T exact_power_of_ten(am_pow_t power); + static constexpr T exact_power_of_ten(am_pow_t const power); static constexpr am_digits max_digits(); static constexpr equiv_uint exponent_mask(); static constexpr equiv_uint mantissa_mask(); @@ -673,32 +675,32 @@ inline constexpr am_bits_t binary_format::min_exponent_fast_path() { } template <> -inline constexpr limb_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 52; } template <> -inline constexpr limb_t binary_format::mantissa_explicit_bits() { +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 23; } template <> -inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 23; } template <> -inline constexpr am_bits_t binary_format::max_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 10; } template <> -inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -4; } template <> -inline constexpr am_bits_t binary_format::min_exponent_round_to_even() { +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -17; } @@ -807,7 +809,7 @@ binary_format::max_exponent_fast_path() { } template <> -inline constexpr limb_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 10; } @@ -829,13 +831,13 @@ binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 5; } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -22; } @@ -934,7 +936,7 @@ binary_format::hidden_bit_mask() { } template <> -inline constexpr limb_t +inline constexpr am_bits_t binary_format::mantissa_explicit_bits() { return 7; } @@ -956,13 +958,13 @@ binary_format::min_exponent_fast_path() { } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::max_exponent_round_to_even() { return 3; } template <> -inline constexpr am_bits_t +inline constexpr am_pow_t binary_format::min_exponent_round_to_even() { return -24; } From 054004f779d20f4f7c3478dbba5b31eb35038e23 Mon Sep 17 00:00:00 2001 From: IRainman Date: Sun, 28 Dec 2025 23:24:24 +0300 Subject: [PATCH 227/252] cleanup and type usage fixes. --- include/fast_float/ascii_number.h | 16 +++++-------- include/fast_float/bigint.h | 24 +++++++++---------- include/fast_float/constexpr_feature_detect.h | 9 ------- include/fast_float/decimal_to_binary.h | 6 ++--- include/fast_float/digit_comparison.h | 2 +- include/fast_float/float_common.h | 12 +++++----- 6 files changed, 28 insertions(+), 41 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 14b37bc7..bc20df71 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -291,9 +291,6 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, parse_options_t const options) noexcept { - // Cyclomatic complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity - // Consider refactoring the 'parse_number_string' function. - // FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN fix this. parsed_number_string_t answer; // so dereference without checks FASTFLOAT_ASSUME(p < pend); @@ -460,12 +457,12 @@ parse_number_string(UC const *p, UC const *pend, // Now we can check for errors. - // TODO: If we frequently had to deal with long strings of digits, + // If we frequently had to deal with long strings of digits, // we could extend our code by using a 128-bit integer instead // of a 64-bit integer. However, this is uncommon. - + // // We can deal with up to 19 digits. - if (digit_count > 19) { + if (digit_count > 19) { // this is uncommon // It is possible that the integer had an overflow. // We have to handle the case where we have 0.0000somenumber. // We need to be mindful of the case where we only have zeroes... @@ -479,8 +476,7 @@ parse_number_string(UC const *p, UC const *pend, ++start; } - // We have to check if we have a number with more than 19 significant - // digits. + // We have to check if number has more than 19 significant digits. if (digit_count > 19) { answer.too_many_digits = true; // Let us start again, this time, avoiding overflows. @@ -492,8 +488,8 @@ parse_number_string(UC const *p, UC const *pend, constexpr am_mant_t minimal_nineteen_digit_integer{1000000000000000000}; while ((p != int_end) && (answer.mantissa < minimal_nineteen_digit_integer)) { - answer.mantissa = static_cast( - answer.mantissa * 10 + static_cast(*p - UC('0'))); + answer.mantissa = + answer.mantissa * 10 + static_cast(*p - UC('0')); ++p; } if (answer.mantissa >= minimal_nineteen_digit_integer) { diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index bac994fe..b089292c 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -67,7 +67,7 @@ template struct stackvec { // index from the end of the container FASTFLOAT_CONSTEXPR14 const limb &rindex(limb_t index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); - limb_t rindex = static_cast(length - index - 1); + auto rindex = length - index - 1; return data[rindex]; } @@ -100,7 +100,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { limb *ptr = data + length; std::copy_n(s.ptr, s.len(), ptr); - set_len(static_cast(len() + s.len())); + set_len(len() + static_cast(s.len())); } // try to add items to the vector, returning if items were added @@ -119,7 +119,7 @@ template struct stackvec { FASTFLOAT_CONSTEXPR20 void resize_unchecked(limb_t new_len, limb value) noexcept { if (new_len > len()) { - limb_t count = new_len - len(); + auto count = new_len - len(); limb *first = data + len(); limb *last = first + count; ::std::fill(first, last, value); @@ -258,9 +258,8 @@ scalar_mul(limb x, limb y, limb &carry) noexcept { // add scalar value to bigint starting from offset. // used in grade school multiplication template -inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, - limb_t start) noexcept { - limb carry = y; +inline FASTFLOAT_CONSTEXPR20 bool +small_add_from(stackvec &vec, limb carry, limb_t start) noexcept { bool overflow; while (carry != 0 && start < vec.len()) { vec[start] = scalar_add(vec[start], carry, overflow); @@ -301,8 +300,9 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, limb_t start) noexcept { // the effective x buffer is from `xstart..x.len()`, so exit early // if we can't get that current range. - if (x.len() < start || y.len() > static_cast(x.len() - start)) { - FASTFLOAT_TRY(x.try_resize(static_cast(y.len() + start), 0)); + if (x.len() < start || + y.len() > static_cast(x.len() - start)) { + FASTFLOAT_TRY(x.try_resize(static_cast(y.len()) + start, 0)); } bool carry = false; @@ -321,7 +321,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, // handle overflow if (carry) { - FASTFLOAT_TRY(small_add_from(x, 1, static_cast(y.len() + start))); + FASTFLOAT_TRY(small_add_from(x, 1, static_cast(y.len()) + start)); } return true; } @@ -343,7 +343,7 @@ FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { if (y.len() != 0) { limb y0 = y[0]; FASTFLOAT_TRY(small_mul(x, y0)); - for (limb_t index = 1; index != y.len(); ++index) { + for (limb_t index = 1; index < y.len(); ++index) { limb yi = y[index]; stackvec zi; if (yi != 0) { @@ -584,8 +584,8 @@ struct bigint : pow5_tables<> { // get the number of bits in the bigint. FASTFLOAT_CONSTEXPR20 bigint_bits_t bit_length() const noexcept { - bigint_bits_t lz = ctlz(); - return static_cast(limb_bits * vec.len() - lz); + auto lz = ctlz(); + return limb_bits * vec.len() - lz; } FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } diff --git a/include/fast_float/constexpr_feature_detect.h b/include/fast_float/constexpr_feature_detect.h index 6c97f14f..7d0338be 100644 --- a/include/fast_float/constexpr_feature_detect.h +++ b/include/fast_float/constexpr_feature_detect.h @@ -76,15 +76,6 @@ #define FASTFLOAT_INLINE_VARIABLE static constexpr #endif -#if defined(__cpp_lib_is_constant_evaluated) && \ - __cpp_lib_is_constant_evaluated >= 201811L -#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 -#define FASTFLOAT_CONSTEVAL consteval -#else -#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 -#define FASTFLOAT_CONSTEVAL FASTFLOAT_CONSTEXPR14 -#endif - // Testing for relevant C++20 constexpr library features #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ defined(__cpp_lib_constexpr_algorithms) && \ diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 5c67e7bf..a2a14818 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -72,7 +72,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa compute_error_scaled(am_pow_t q, am_mant_t w, am_bits_t lz) noexcept { - auto const hilz = static_cast((w >> 63) ^ 1); + auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; constexpr am_pow_t bias = @@ -138,8 +138,8 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - auto const upperbit = static_cast(product.high >> 63); - limb_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + auto const upperbit = static_cast(product.high >> 63); + am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; answer.mantissa = product.high >> shift; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index d7a3c95f..88e7efe1 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -68,7 +68,7 @@ to_extended(T const value) noexcept { constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - equiv_uint const bits = bit_cast(value); + auto const bits = bit_cast(value); if ((bits & exponent_mask) == 0) { // denormal diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 345631e4..b23edc5d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -49,19 +49,19 @@ typedef uint_fast8_t limb_t; typedef int_fast8_t am_bits_t; // 16 bit signed integer is used for power to cover all double exponents. -typedef int16_t am_pow_t; +typedef int_fast16_t am_pow_t; // Power bias is signed for handling a denormal float // or an invalid mantissa. // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static am_pow_t invalid_am_bias = - std::numeric_limits::min() + 1; + std::numeric_limits::min() + 1; constexpr static am_pow_t am_bias_limit = - (std::numeric_limits::max() / 8) - 1; + (std::numeric_limits::max() / 16) - 1; // Type for enum chars_format. typedef uint_fast8_t chars_format_t; -// Type for base. +// Type for base, only allowed from 2 to 36. typedef uint_fast8_t base_t; enum class chars_format : chars_format_t; @@ -110,10 +110,10 @@ template struct parse_options_t { /** Which number formats are accepted */ chars_format format; - /** The character used as decimal point */ + /** The character used as decimal point for floats */ UC decimal_point; /** The base used for integers */ - base_t base; /* only allowed from 2 to 36 */ + base_t base; }; using parse_options = parse_options_t; From ebc2ee8ceb9c5cc1cc1ad319cf0522fbb219be3f Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 00:06:46 +0300 Subject: [PATCH 228/252] optimization for the report_parse_error. --- include/fast_float/ascii_number.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index bc20df71..4fe726b3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -277,8 +277,8 @@ using parsed_number_string = parsed_number_string_t; template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t -report_parse_error(UC const *p, parse_error error) noexcept { - parsed_number_string_t answer; +report_parse_error(parsed_number_string_t &answer, UC const *p, + parse_error error) noexcept { answer.invalid = true; answer.lastmatch = p; answer.error = error; @@ -303,12 +303,12 @@ parse_number_string(UC const *p, UC const *pend, ++p; if (p == pend) { return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); + answer, p, parse_error::missing_integer_or_dot_after_sign); } FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // a sign must be followed by an integer if (!is_integer(*p)) { - return report_parse_error(p, + return report_parse_error(answer, p, parse_error::missing_integer_after_sign); } } @@ -316,7 +316,7 @@ parse_number_string(UC const *p, UC const *pend, // a sign must be followed by an integer or the dot if (!is_integer(*p) && (*p != options.decimal_point)) { return report_parse_error( - p, parse_error::missing_integer_or_dot_after_sign); + answer, p, parse_error::missing_integer_or_dot_after_sign); } } } @@ -343,10 +343,11 @@ parse_number_string(UC const *p, UC const *pend, FASTFLOAT_IF_CONSTEXPR17(basic_json_fmt) { // at least 1 digit in integer part, without leading zeros if (digit_count == 0) { - return report_parse_error(p, parse_error::no_digits_in_integer_part); + return report_parse_error(answer, p, + parse_error::no_digits_in_integer_part); } if ((start_digits[0] == UC('0') && digit_count > 1)) { - return report_parse_error(start_digits, + return report_parse_error(answer, start_digits, parse_error::leading_zeros_in_integer_part); } } @@ -376,13 +377,14 @@ parse_number_string(UC const *p, UC const *pend, // at least 1 digit in fractional part if (answer.exponent == 0) { return report_parse_error( - p, parse_error::no_digits_in_fractional_part); + answer, p, parse_error::no_digits_in_fractional_part); } } #endif } else if (digit_count == 0) { // We must have encountered at least one integer! - return report_parse_error(p, parse_error::no_digits_in_mantissa); + return report_parse_error(answer, p, + parse_error::no_digits_in_mantissa); } // We have now parsed the integer and the fraction part of the mantissa. @@ -425,7 +427,8 @@ parse_number_string(UC const *p, UC const *pend, // The exponential part is invalid for scientific notation, so it // must be a trailing token for fixed notation. However, fixed // notation is disabled, so report a scientific notation error. - return report_parse_error(p, parse_error::missing_exponential_part); + return report_parse_error(answer, p, + parse_error::missing_exponential_part); } // Otherwise, we will be ignoring the 'e'. p = location_of_e; @@ -448,7 +451,8 @@ parse_number_string(UC const *p, UC const *pend, // If it scientific and not fixed, we have to bail out. if ((chars_format_t(options.format & chars_format::scientific)) && !(chars_format_t(options.format & chars_format::fixed))) { - return report_parse_error(p, parse_error::missing_exponential_part); + return report_parse_error(answer, p, + parse_error::missing_exponential_part); } } From dad07cc054bcb48f416a3db45364d0faac4a66da Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 16:17:44 +0300 Subject: [PATCH 229/252] initialization cleanup and improve caches usage. --- include/fast_float/ascii_number.h | 13 ++++++++----- include/fast_float/decimal_to_binary.h | 14 ++++++++++---- include/fast_float/float_common.h | 10 +++++----- include/fast_float/parse_number.h | 5 +++-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 4fe726b3..e999bcb2 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -259,17 +259,20 @@ enum class parse_error : uint_fast8_t { template struct parsed_number_string_t { am_mant_t mantissa{0}; - am_pow_t exponent{0}; - // contains the range of the significant digits - span integer{}; // non-nullable - span fraction{}; // nullable - UC const *lastmatch{nullptr}; + #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN bool negative{false}; #endif bool invalid{false}; // be optimistic bool too_many_digits{false}; // be optimistic parse_error error{parse_error::no_error}; // be optimistic + + am_pow_t exponent{0}; + + // contains the range of the significant digits + span integer; // non-nullable + span fraction; // nullable + UC const *lastmatch; }; using byte_span = span; diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index a2a14818..1db1055d 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -31,14 +31,16 @@ compute_product_approximation(am_pow_t q, am_mant_t w) noexcept { constexpr uint64_t precision_mask = (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) : uint64_t(0xFFFFFFFFFFFFFFFF); + if ((firstproduct.high & precision_mask) == precision_mask) { // could further guard with (lower + w < lower) // regarding the second product, we only need secondproduct.high, but our // expectation is that the compiler will optimize this extra work away if // needed. - value128 secondproduct = + value128 const secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]); firstproduct.low += secondproduct.high; + if (secondproduct.high > firstproduct.low) { ++firstproduct.high; } @@ -62,7 +64,7 @@ namespace detail { * where * p = log(5**-q)/log(2) = -q * log(5)/log(2) */ -constexpr fastfloat_really_inline am_pow_t power(am_pow_t q) noexcept { +constexpr fastfloat_really_inline am_pow_t power(am_pow_t const q) noexcept { return (((152170 + 65536) * q) >> 16) + 63; } } // namespace detail @@ -103,9 +105,9 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_float(am_pow_t q, am_mant_t w) noexcept { adjusted_mantissa answer; if ((w == 0) || (q < binary::smallest_power_of_ten())) { + // we want to get zero: answer.power2 = 0; answer.mantissa = 0; - // result should be zero return answer; } if (q > binary::largest_power_of_ten()) { @@ -114,6 +116,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { answer.mantissa = 0; return answer; } + // At this point in time q is in [powers::smallest_power_of_five, // powers::largest_power_of_five]. @@ -127,7 +130,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // 3. We might lose a bit due to the "upperbit" routine (result too small, // requiring a shift) - value128 product = + value128 const product = compute_product_approximation(q, w); // The computed 'product' is always sufficient. // Mathematical proof: @@ -141,6 +144,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { auto const upperbit = static_cast(product.high >> 63); am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; answer.power2 = detail::power(q) + upperbit - lz - binary::minimum_exponent(); @@ -192,6 +196,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { } } + // Normal rounding answer.mantissa += (answer.mantissa & 1); // round up answer.mantissa >>= 1; if (answer.mantissa >= (am_mant_t(2) << binary::mantissa_explicit_bits())) { @@ -199,6 +204,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { ++answer.power2; // undo previous addition } + // Check if we have infinity after computation answer.mantissa &= ~(am_mant_t(1) << binary::mantissa_explicit_bits()); if (answer.power2 >= binary::infinite_power()) { // infinity answer.power2 = binary::infinite_power(); diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index b23edc5d..bbd2d71d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -110,10 +110,10 @@ template struct parse_options_t { /** Which number formats are accepted */ chars_format format; - /** The character used as decimal point for floats */ - UC decimal_point; /** The base used for integers */ base_t base; + /** The character used as decimal point for floats */ + UC decimal_point; }; using parse_options = parse_options_t; @@ -370,7 +370,7 @@ struct alignas(16) value128 { constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} - constexpr value128() noexcept : low(0), high(0) {} + constexpr value128() noexcept {} }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ @@ -415,7 +415,7 @@ leading_zeroes(uint64_t input_num) noexcept { } #ifdef FASTFLOAT_VISUAL_STUDIO #if defined(_M_X64) || defined(_M_ARM64) - unsigned long leading_zero = 0; + unsigned long leading_zero; // Search the mask data from most significant bit (MSB) // to least significant bit (LSB) for a set bit (1). _BitScanReverse64(&leading_zero, input_num); @@ -533,7 +533,7 @@ full_multiplication(uint64_t a, uint64_t b) noexcept { struct alignas(16) adjusted_mantissa { am_mant_t mantissa; am_pow_t power2; - adjusted_mantissa() noexcept = default; + adjusted_mantissa() noexcept {}; constexpr bool operator==(adjusted_mantissa const &o) const noexcept { return mantissa == o.mantissa && power2 == o.power2; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 913fc083..2c7e9d40 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -417,7 +417,7 @@ FASTFLOAT_CONSTEXPR20 integer_times_pow10(am_sign_mant_t const mantissa, am_pow_t const decimal_exponent) noexcept { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - const bool is_negative = mantissa < 0; + const auto is_negative = mantissa < 0; const auto m = static_cast(is_negative ? -mantissa : mantissa); #else FASTFLOAT_ASSUME(mantissa >= 0); @@ -431,8 +431,9 @@ FASTFLOAT_CONSTEXPR20 value)) return value; - adjusted_mantissa am = + adjusted_mantissa const am = compute_float>(decimal_exponent, m); + to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is_negative, From 59da568ec65f1c501aa91d86c3aecb2f8ebd9665 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 16:31:32 +0300 Subject: [PATCH 230/252] type usage fix. --- include/fast_float/decimal_to_binary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 1db1055d..799c074b 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -73,7 +73,7 @@ constexpr fastfloat_really_inline am_pow_t power(am_pow_t const q) noexcept { // for significant digits already multiplied by 10 ** q. template fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa -compute_error_scaled(am_pow_t q, am_mant_t w, am_bits_t lz) noexcept { +compute_error_scaled(am_pow_t q, am_mant_t w, limb_t lz) noexcept { auto const hilz = static_cast((w >> 63) ^ 1); adjusted_mantissa answer; answer.mantissa = w << hilz; From 5857b98bfd0a0a0a2a5be02e2c39b9320d279ae7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 16:43:54 +0300 Subject: [PATCH 231/252] some warnings fix in CI builds. --- include/fast_float/float_common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index bbd2d71d..acd15d68 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -106,7 +106,7 @@ template struct parse_options_t { constexpr explicit parse_options_t( chars_format const fmt = chars_format::general, UC const dot = UC('.'), base_t const b = 10) noexcept - : format(fmt), decimal_point(dot), base(b) {} + : format(fmt), base(b), decimal_point(dot) {} /** Which number formats are accepted */ chars_format format; @@ -154,7 +154,7 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) noexcept { (defined(__riscv) && __riscv_xlen == 32)) #define FASTFLOAT_32BIT 1 #else - // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. +// Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. // We can never tell the register width, but the SIZE_MAX is a good // approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max // portability. From a28e112d8fdf30ce3d6c1d9d579187f209231d06 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 17:29:03 +0300 Subject: [PATCH 232/252] initialization cleanup. --- include/fast_float/ascii_number.h | 16 ++++++++-------- include/fast_float/float_common.h | 13 ++++++------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index e999bcb2..a0edaa92 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -258,16 +258,16 @@ enum class parse_error : uint_fast8_t { }; template struct parsed_number_string_t { - am_mant_t mantissa{0}; + am_mant_t mantissa; #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN - bool negative{false}; + bool negative; #endif - bool invalid{false}; // be optimistic - bool too_many_digits{false}; // be optimistic - parse_error error{parse_error::no_error}; // be optimistic + bool invalid; + bool too_many_digits; + parse_error error; - am_pow_t exponent{0}; + am_pow_t exponent; // contains the range of the significant digits span integer; // non-nullable @@ -294,7 +294,7 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const *pend, parse_options_t const options) noexcept { - parsed_number_string_t answer; + parsed_number_string_t answer{}; // so dereference without checks FASTFLOAT_ASSUME(p < pend); #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -514,8 +514,8 @@ parse_number_string(UC const *p, UC const *pend, } answer.exponent = am_pow_t(answer.fraction.ptr - p) + exp_number; } + // We now corrected both exponent and mantissa, to a truncated value } - // We have now corrected both exponent and mantissa, to a truncated value } return answer; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index acd15d68..0c2e8656 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -347,17 +347,16 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, // a pointer and a length to a contiguous block of memory template struct span { T const *ptr; - uint_fast16_t length; + am_digits length; - constexpr span(T const *_ptr, uint_fast16_t _length) noexcept + constexpr span(T const *_ptr, am_digits _length) noexcept : ptr(_ptr), length(_length) {} - constexpr span() noexcept : ptr(nullptr), length(0) {} + constexpr span() noexcept = default; - constexpr uint_fast16_t len() const noexcept { return length; } + constexpr am_digits len() const noexcept { return length; } - FASTFLOAT_CONSTEXPR14 const T & - operator[](uint_fast16_t index) const noexcept { + FASTFLOAT_CONSTEXPR14 const T &operator[](am_digits index) const noexcept { FASTFLOAT_DEBUG_ASSERT(index < length); return ptr[index]; } @@ -370,7 +369,7 @@ struct alignas(16) value128 { constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} - constexpr value128() noexcept {} + constexpr value128() noexcept = default; }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ From 38d0ab3f8eb882dcf0bbd6d293c8043c2c393854 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 17:48:38 +0300 Subject: [PATCH 233/252] initialization cleanup. --- include/fast_float/float_common.h | 35 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 0c2e8656..b9c2db0d 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -369,7 +369,7 @@ struct alignas(16) value128 { constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {} - constexpr value128() noexcept = default; + constexpr value128() noexcept : low(0), high(0) {} }; /* Helper C++14 constexpr generic implementation of leading_zeroes for 64-bit */ @@ -429,7 +429,7 @@ leading_zeroes(uint64_t input_num) noexcept { /* Helper C++14 constexpr generic implementation of countr_zero for 32-bit */ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 limb_t -countr_zero_generic_32(uint32_t input_num) { +countr_zero_generic_32(uint32_t input_num) noexcept { assert(input_num > 0); FASTFLOAT_ASSUME(input_num > 0); uint_fast16_t last_bit = 0; @@ -457,7 +457,7 @@ countr_zero_generic_32(uint32_t input_num) { /* count trailing zeroes for 32-bit integers */ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb_t -countr_zero_32(uint32_t input_num) { +countr_zero_32(uint32_t input_num) noexcept { if (cpp20_and_in_constexpr()) { return countr_zero_generic_32(input_num); } @@ -505,34 +505,35 @@ _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept { // compute 64-bit a*b fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 full_multiplication(uint64_t a, uint64_t b) noexcept { + value128 answer; if (cpp20_and_in_constexpr()) { - value128 answer; answer.low = umul128_generic(a, b, &answer.high); - return answer; - } - value128 answer; + } else { #if defined(_M_ARM64) && !defined(__MINGW32__) - // ARM64 has native support for 64-bit multiplications, no need to emulate - // But MinGW on ARM64 doesn't have native support for 64-bit multiplications - answer.high = __umulh(a, b); - answer.low = a * b; + // ARM64 has native support for 64-bit multiplications, no need to emulate + // But MinGW on ARM64 doesn't have native support for 64-bit multiplications + answer.high = __umulh(a, b); + answer.low = a * b; #elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__) && \ !defined(_M_ARM64) && !defined(__GNUC__)) - answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 + answer.low = + _umul128(a, b, &answer.high); // _umul128 not available on ARM64 #elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) - __uint128_t r = ((__uint128_t)a) * b; - answer.low = uint64_t(r); - answer.high = uint64_t(r >> 64); + __uint128_t r = (static_cast<__uint128_t>(a)) * b; + answer.low = static_cast(r); + answer.high = static_cast(r >> 64); #else - answer.low = umul128_generic(a, b, &answer.high); + answer.low = umul128_generic(a, b, &answer.high); #endif + } return answer; } struct alignas(16) adjusted_mantissa { am_mant_t mantissa; am_pow_t power2; - adjusted_mantissa() noexcept {}; + + constexpr adjusted_mantissa() noexcept : mantissa(0), power2(0) {} constexpr bool operator==(adjusted_mantissa const &o) const noexcept { return mantissa == o.mantissa && power2 == o.power2; From 147cf3b4c71ea9921c905096afcbd82822809a3e Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 18:23:06 +0300 Subject: [PATCH 234/252] type usage fix and cleanup. --- include/fast_float/decimal_to_binary.h | 7 +++-- include/fast_float/digit_comparison.h | 2 +- include/fast_float/float_common.h | 41 ++++++++++++-------------- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 799c074b..27d2aa50 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // most significant bits and the low part corresponding to the least significant // bits. // -template +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(am_pow_t q, am_mant_t w) noexcept { am_pow_t const index = 2 * (q - powers::smallest_power_of_five); @@ -90,7 +90,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(am_pow_t q, am_mant_t w) noexcept { auto const lz = leading_zeroes(w); w <<= lz; - value128 product = + value128 const product = compute_product_approximation(q, w); return compute_error_scaled(q, product.high, lz); } @@ -201,7 +201,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { answer.mantissa >>= 1; if (answer.mantissa >= (am_mant_t(2) << binary::mantissa_explicit_bits())) { answer.mantissa = (am_mant_t(1) << binary::mantissa_explicit_bits()); - ++answer.power2; // undo previous addition + ++answer.power2; // undo previous line addition } // Check if we have infinity after computation @@ -210,6 +210,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { answer.power2 = binary::infinite_power(); answer.mantissa = 0; } + return answer; } diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 88e7efe1..10a75981 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -68,7 +68,7 @@ to_extended(T const value) noexcept { constexpr am_pow_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); - auto const bits = bit_cast(value); + auto const bits = bit_cast(value); if ((bits & exponent_mask) == 0) { // denormal diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index b9c2db0d..c7d4d786 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -120,27 +120,6 @@ using parse_options = parse_options_t; } // namespace fast_float -#if FASTFLOAT_HAS_BIT_CAST -#include -#endif - -namespace fast_float { -template -FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) noexcept { -#if FASTFLOAT_HAS_BIT_CAST - return std::bit_cast(from); -#else - // Implementation of std::bit_cast for pre-C++20. - static_assert(sizeof(To) == sizeof(From), - "bit_cast requires source and destination to be the same size"); - auto to = To(); - // The cast suppresses a bogus -Wclass-memaccess on GCC. - std::memcpy(static_cast(&to), &from, sizeof(to)); - return to; -#endif -} -} // namespace fast_float - #if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ defined(__MINGW64__) || defined(__s390x__) || \ @@ -269,7 +248,25 @@ FASTFLOAT_CONSTEXPR20 To bit_cast(const From &from) noexcept { #define FASTFLOAT_ENABLE_IF(...) \ typename std::enable_if<(__VA_ARGS__), int>::type +#if FASTFLOAT_HAS_BIT_CAST +#include +#endif + namespace fast_float { +template +constexpr fastfloat_really_inline To bit_cast(const From &from) noexcept { +#if FASTFLOAT_HAS_BIT_CAST + return std::bit_cast(from); +#else + // Implementation of std::bit_cast for pre-C++20. + static_assert(sizeof(To) == sizeof(From), + "bit_cast requires source and destination to be the same size"); + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; +#endif +} fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED @@ -1124,7 +1121,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void to_float( word = equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); #endif - value = bit_cast(word); + value = bit_cast(word); } #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN From 351e4d30abccbc37a7ea219bcf23cba6072836a7 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 18:48:28 +0300 Subject: [PATCH 235/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 27d2aa50..aa7d7cc2 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,8 +141,8 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - auto const upperbit = static_cast(product.high >> 63); - am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + auto const upperbit = product.high >> 63; + auto const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; From 35bca9cb347b45ae570ebe13c4d7a9ffde5280d1 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:03:15 +0300 Subject: [PATCH 236/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index aa7d7cc2..2c30cc5e 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,13 +141,16 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - auto const upperbit = product.high >> 63; - auto const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + am_pow_t const upperbit = product.high >> 63; + am_pow_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; answer.power2 = detail::power(q) + upperbit - lz - binary::minimum_exponent(); + + // Now, we need to round the mantissa correctly. + if (answer.power2 <= 0) { // we have a subnormal or very small value. // Here have that answer.power2 <= 0 so -answer.power2 >= 0 if (-answer.power2 + 1 >= From 0d423367a5ee9ce37675b10031b968ac0f5ff0e3 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:08:10 +0300 Subject: [PATCH 237/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 2c30cc5e..f2ff571b 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,13 +141,15 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - am_pow_t const upperbit = product.high >> 63; - am_pow_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + auto const upperbit = product.high >> 63; + auto const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; - answer.power2 = detail::power(q) + upperbit - lz - binary::minimum_exponent(); + answer.power2 = + detail::power(q) + + static_cast(upperbit - lz - binary::minimum_exponent()); // Now, we need to round the mantissa correctly. From 8330f851f6b550b37a3ca93d865f886b7b579a8f Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:15:15 +0300 Subject: [PATCH 238/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index f2ff571b..18307ff9 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,15 +141,13 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - auto const upperbit = product.high >> 63; - auto const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + am_bits_t const upperbit = product.high >> 63; + am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; - answer.power2 = - detail::power(q) + - static_cast(upperbit - lz - binary::minimum_exponent()); + answer.power2 = detail::power(q) + upperbit - lz - binary::minimum_exponent(); // Now, we need to round the mantissa correctly. From 611cd927f1bd943d1555c11733d7eb3861ea8865 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:17:25 +0300 Subject: [PATCH 239/252] type usage fixes. --- include/fast_float/decimal_to_binary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 18307ff9..b1f88421 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,7 +141,7 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - am_bits_t const upperbit = product.high >> 63; + am_bits_t const upperbit = static_cast(product.high >> 63); am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; // Shift right the mantissa to the correct position From f4cae22b6e86403a71ce1eb3959fb615a7482d3a Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:25:10 +0300 Subject: [PATCH 240/252] type usage fix. --- include/fast_float/ascii_number.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index a0edaa92..c91aed3a 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -564,7 +564,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, auto const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const auto len = static_cast(pend - p); + const auto len = static_cast(pend - p); if (len == 0) { if (has_leading_zeros) { value = 0; @@ -608,7 +608,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, const uint32_t magic = ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; const auto tz = countr_zero_32(magic); // 7, 15, 23, 31, or 32 - am_bits_t nd = (tz == 32) ? 4 : (tz >> 3); + am_digits nd = (tz >> 3); nd = std::min(nd, len); if (nd == 0) { if (has_leading_zeros) { From 9a0fa4733cb0452f62985d95e847ced6275fff8b Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:41:17 +0300 Subject: [PATCH 241/252] cleanup. --- include/fast_float/digit_comparison.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 10a75981..bd662b40 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -76,8 +76,8 @@ to_extended(T const value) noexcept { am.mantissa = bits & mantissa_mask; } else { // normal - am.power2 = static_cast(bits & exponent_mask) >> - binary_format::mantissa_explicit_bits(); + am.power2 = static_cast( + (bits & exponent_mask) >> binary_format::mantissa_explicit_bits()); am.power2 -= bias; am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; } @@ -276,10 +276,10 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { while (p != pend) { while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + parse_eight_digits(p, value, counter, digits); } while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); + parse_one_digit(p, value, counter, digits); } if (digits == max_digits) { // add the temporary value, then check if we've truncated any digits @@ -310,10 +310,10 @@ parse_mantissa(bigint &result, const parsed_number_string_t &num) noexcept { while (p != pend) { while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + parse_eight_digits(p, value, counter, digits); } while (counter < step && p != pend && digits < max_digits) { - parse_one_digit(p, value, counter, digits); + parse_one_digit(p, value, counter, digits); } if (digits == max_digits) { // add the temporary value, then check if we've truncated any digits @@ -398,7 +398,7 @@ negative_digit_comp(bigint &real_digits, adjusted_mantissa am, } // compare digits, and use it to direct rounding - int const ord = real_digits.compare(theor_digits); + auto const ord = real_digits.compare(theor_digits); round(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round_nearest_tie_even( a, shift, [ord](bool is_odd, bool _, bool __) -> bool { @@ -440,8 +440,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa digit_comp( bigint bigmant; am_digits const digits = parse_mantissa(bigmant, num); // can't underflow, since digits is at most max_digits. - am_pow_t const exponent = - static_cast(sci_exp + 1 - static_cast(digits)); + am_pow_t const exponent = sci_exp + 1 - static_cast(digits); if (exponent >= 0) { return positive_digit_comp(bigmant, am, exponent); } else { From f556a6875f1087734ed839341c021f8499b88437 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 19:47:43 +0300 Subject: [PATCH 242/252] cleanup. --- include/fast_float/digit_comparison.h | 4 ++-- include/fast_float/float_common.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index bd662b40..fd8c61d5 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -386,8 +386,8 @@ negative_digit_comp(bigint &real_digits, adjusted_mantissa am, am_pow_t const theor_exp = theor.power2; // scale real digits and theor digits to be same power. - am_pow_t const pow2_exp = theor_exp - real_exp; - am_pow_t pow5_exp = -real_exp; + auto const pow2_exp = theor_exp - real_exp; + auto const pow5_exp = -real_exp; if (pow5_exp != 0) { FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); } diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index c7d4d786..16071bdd 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -254,7 +254,7 @@ using parse_options = parse_options_t; namespace fast_float { template -constexpr fastfloat_really_inline To bit_cast(const From &from) noexcept { +fastfloat_really_inline constexpr To bit_cast(const From &from) noexcept { #if FASTFLOAT_HAS_BIT_CAST return std::bit_cast(from); #else From 41d9632abc0b13b9c46837d257a8628431ad94e4 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 21:12:11 +0300 Subject: [PATCH 243/252] interface cleanup. --- include/fast_float/fast_float.h | 8 ++++---- include/fast_float/float_common.h | 2 -- include/fast_float/parse_number.h | 18 ++++++++---------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index 38c34e43..b478e658 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -59,10 +59,10 @@ from_chars_advanced(UC const *first, UC const *last, T &value, * `new` or `malloc`). */ FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(am_mant_t const mantissa, +integer_times_pow10(uint64_t const mantissa, am_pow_t const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(am_sign_mant_t const mantissa, +integer_times_pow10(int64_t const mantissa, am_pow_t const decimal_exponent) noexcept; /** @@ -73,12 +73,12 @@ integer_times_pow10(am_sign_mant_t const mantissa, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(am_mant_t const mantissa, + integer_times_pow10(uint64_t const mantissa, am_pow_t const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(am_sign_mant_t const mantissa, + integer_times_pow10(int64_t const mantissa, am_pow_t const decimal_exponent) noexcept; /** diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 16071bdd..149eb366 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -34,8 +34,6 @@ namespace fast_float { // 64 bit integer is used because mantissa can be up to 53 bits for double. -// Value of the int mantissa in the API. -typedef int_fast64_t am_sign_mant_t; // An unsigned int avoids signed overflows (which are bad) typedef uint_fast64_t am_mant_t; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 2c7e9d40..4a04ff1d 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -391,7 +391,7 @@ from_chars(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(am_mant_t const mantissa, + integer_times_pow10(uint64_t const mantissa, am_pow_t const decimal_exponent) noexcept { T value; if (clinger_fast_path_impl(mantissa, decimal_exponent, @@ -414,7 +414,7 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type - integer_times_pow10(am_sign_mant_t const mantissa, + integer_times_pow10(int64_t const mantissa, am_pow_t const decimal_exponent) noexcept { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN const auto is_negative = mantissa < 0; @@ -443,13 +443,13 @@ FASTFLOAT_CONSTEXPR20 } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(am_mant_t const mantissa, +integer_times_pow10(uint64_t const mantissa, am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double -integer_times_pow10(am_sign_mant_t const mantissa, +integer_times_pow10(int64_t const mantissa, am_pow_t const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } @@ -464,7 +464,7 @@ FASTFLOAT_CONSTEXPR20 T>::type integer_times_pow10(Int const mantissa, am_pow_t const decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -476,7 +476,7 @@ FASTFLOAT_CONSTEXPR20 T>::type integer_times_pow10(Int const mantissa, am_pow_t const decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -485,8 +485,7 @@ FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type integer_times_pow10(Int const mantissa, am_pow_t const decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), - decimal_exponent); + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template @@ -494,8 +493,7 @@ FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type integer_times_pow10(Int const mantissa, am_pow_t const decimal_exponent) noexcept { - return integer_times_pow10(static_cast(mantissa), - decimal_exponent); + return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template From 8f795017cbe0ead93b679b7f904f4282afab6333 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 21:51:47 +0300 Subject: [PATCH 244/252] * small cleanup in the tests/basictest.cpp --- tests/basictest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 1a5537bb..37e1863b 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -69,7 +69,7 @@ template std::string fHexAndDec(T v) { return ss.str(); } -char const *round_name(int d) { +constexpr std::string_view const round_name(int d) { switch (d) { case FE_UPWARD: return "FE_UPWARD"; @@ -2313,7 +2313,7 @@ TEST_CASE("integer_times_pow10") { for (int mode : {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, FE_TONEAREST}) { fesetround(mode); - INFO("fesetround(): " << std::string{round_name(mode)}); + INFO("fesetround(): " << round_name(mode)); struct Guard { ~Guard() { fesetround(FE_TONEAREST); } From 7ca9c84708e342cc8ea3e5d4da5cb26ab83595cd Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 23:02:07 +0300 Subject: [PATCH 245/252] type usage fixes. --- include/fast_float/float_common.h | 42 +++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 149eb366..2661c9f8 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -317,8 +317,8 @@ struct is_supported_char_type #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN -// TODO use SSE4.2 there when SSE2 compiler switch in MSVC -// or in other compiler SSE4.2 available. +// TODO? use SSE4.2 there when SSE2 compiler switch in MSVC +// or in other compiler SSE4.2 available? // Compares two ASCII strings in a case insensitive manner. template @@ -556,8 +556,8 @@ template struct binary_format : binary_format_lookup_tables { static constexpr am_bits_t max_exponent_fast_path(); static constexpr am_pow_t max_exponent_round_to_even(); static constexpr am_pow_t min_exponent_round_to_even(); - static constexpr equiv_uint max_mantissa_fast_path(am_pow_t const power); - static constexpr equiv_uint + static constexpr am_mant_t max_mantissa_fast_path(am_pow_t const power); + static constexpr am_mant_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST static constexpr am_pow_t largest_power_of_ten(); static constexpr am_pow_t smallest_power_of_ten(); @@ -738,10 +738,14 @@ inline constexpr am_bits_t binary_format::max_exponent_fast_path() { return 10; } -template -inline constexpr typename binary_format::equiv_uint -binary_format::max_mantissa_fast_path() { - return binary_format::equiv_uint(2) << mantissa_explicit_bits(); +template <> +inline constexpr am_mant_t binary_format::max_mantissa_fast_path() { + return am_mant_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr am_mant_t binary_format::max_mantissa_fast_path() { + return am_mant_t(2) << mantissa_explicit_bits(); } // credit: Jakub Jelínek @@ -810,7 +814,13 @@ binary_format::mantissa_explicit_bits() { } template <> -inline constexpr binary_format::equiv_uint +inline constexpr am_mant_t +binary_format::max_mantissa_fast_path() { + return am_mant_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr am_mant_t binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 4); @@ -894,7 +904,7 @@ constexpr std::bfloat16_t binary_format_lookup_tables::powers_of_ten[]; template -constexpr uint64_t +constexpr uint16_t binary_format_lookup_tables::max_mantissa[]; #endif @@ -937,7 +947,13 @@ binary_format::mantissa_explicit_bits() { } template <> -inline constexpr binary_format::equiv_uint +inline constexpr am_mant_t +binary_format::max_mantissa_fast_path() { + return am_mant_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr am_mant_t binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 3); @@ -1002,7 +1018,7 @@ inline constexpr am_digits binary_format::max_digits() { #endif // __STDCPP_BFLOAT16_T__ template <> -inline constexpr binary_format::equiv_uint +inline constexpr am_mant_t binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 22); @@ -1012,7 +1028,7 @@ binary_format::max_mantissa_fast_path(am_pow_t power) { } template <> -inline constexpr binary_format::equiv_uint +inline constexpr am_mant_t binary_format::max_mantissa_fast_path(am_pow_t power) { // caller is responsible to ensure that FASTFLOAT_ASSUME(power >= 0 && power <= 10); From 24231804ec0a8b9f6a4dd380ba71e558709c8724 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 23:49:30 +0300 Subject: [PATCH 246/252] cleanup --- tests/fast_int.cpp | 12 ++++++------ tests/fortran.cpp | 1 - tests/json_fmt.cpp | 17 ++++++++--------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/fast_int.cpp b/tests/fast_int.cpp index 0f06821b..94e76fdb 100644 --- a/tests/fast_int.cpp +++ b/tests/fast_int.cpp @@ -661,7 +661,7 @@ int main() { auto const &f = invalid_base_test_1[i]; int result; auto answer = - fast_float::from_chars(f.data(), f.data() + f.size(), result, 1); + fast_float::from_chars(f.data(), f.data() + f.size(), result, -1); if (answer.ec != std::errc::invalid_argument) { std::cerr << "expected error should be 'invalid_argument' for: \"" << f << "\"" << std::endl; @@ -762,7 +762,7 @@ int main() { auto const &f = int_out_of_range_base_test[i]; int64_t result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - uint_fast8_t(2 + (i / 2))); + int(2 + (i / 2))); if (answer.ec != std::errc::result_out_of_range) { std::cerr << "expected error for should be 'result_out_of_range': \"" << f << "\"" << std::endl; @@ -807,7 +807,7 @@ int main() { "7ORP63SH4DPHI", "5G24A25TWKWFG", "3W5E11264SGSG"}; - uint_fast8_t base_unsigned = 2; + int base_unsigned = 2; for (std::size_t i = 0; i < unsigned_out_of_range_base_test.size(); ++i) { auto const &f = unsigned_out_of_range_base_test[i]; uint64_t result; @@ -898,7 +898,7 @@ int main() { auto const &f = int_within_range_base_test[i]; int64_t result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - uint_fast8_t(2 + (i / 2))); + int(2 + (i / 2))); if (answer.ec != std::errc()) { std::cerr << "converting " << f << " to int failed (most likely out of range)" << std::endl; @@ -943,7 +943,7 @@ int main() { "7ORP63SH4DPHH", "5G24A25TWKWFF", "3W5E11264SGSF"}; - uint_fast8_t base_unsigned2 = 2; + int base_unsigned2 = 2; for (std::size_t i = 0; i < unsigned_within_range_base_test.size(); ++i) { auto const &f = unsigned_within_range_base_test[i]; uint64_t result; @@ -1001,7 +1001,7 @@ int main() { auto const &f = int_leading_zeros_test[i]; int result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result, - uint_fast8_t(i + 2)); + int(i + 2)); if (answer.ec != std::errc()) { std::cerr << "could not convert to int for input: \"" << f << "\"" << std::endl; diff --git a/tests/fortran.cpp b/tests/fortran.cpp index 38473548..9167593e 100644 --- a/tests/fortran.cpp +++ b/tests/fortran.cpp @@ -31,7 +31,6 @@ int main() { "1d-1", "1d-2", "1d-3", "1d-4"}; std::vector const fmt3{"+1+4", "+1+3", "+1+2", "+1+1", "+1+0", "+1-1", "+1-2", "+1-3", "+1-4"}; - fast_float::parse_options const options{ fast_float::chars_format::fortran | fast_float::chars_format::allow_leading_plus}; diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index ca4b46b6..aa9da9cc 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -10,7 +10,7 @@ int main_readme() { fast_float::parse_options options{ fast_float::chars_format::json | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto const answer = fast_float::from_chars_advanced( + auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -25,7 +25,7 @@ int main_readme2() { fast_float::parse_options options{ fast_float::chars_format::json | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto const answer = fast_float::from_chars_advanced( + auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec == std::errc()) { std::cerr << "should have failed\n"; @@ -41,7 +41,7 @@ int main_readme3() { fast_float::parse_options options{ fast_float::chars_format::json_or_infnan | fast_float::chars_format::allow_leading_plus}; // should be ignored - auto const answer = fast_float::from_chars_advanced( + auto answer = fast_float::from_chars_advanced( input.data(), input.data() + input.size(), result, options); if (answer.ec != std::errc() || (!std::isinf(result))) { std::cerr << "should have parsed infinity\n"; @@ -97,7 +97,7 @@ int main() { auto const &s = accept[i].input; auto const &expected = accept[i].expected; double result; - auto const answer = + auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, fast_float::chars_format::json_or_infnan); if (answer.ec != std::errc()) { @@ -120,8 +120,8 @@ int main() { for (std::size_t i = 0; i < reject.size(); ++i) { auto const &s = reject[i].input; double result; - auto const answer = fast_float::from_chars( - s.data(), s.data() + s.size(), result, fast_float::chars_format::json); + auto answer = fast_float::from_chars(s.data(), s.data() + s.size(), result, + fast_float::chars_format::json); if (answer.ec == std::errc()) { std::cerr << "json fmt accepted invalid json " << s << std::endl; return EXIT_FAILURE; @@ -131,12 +131,11 @@ int main() { for (std::size_t i = 0; i < reject.size(); ++i) { auto const &f = reject[i].input; auto const &expected_reason = reject[i].reason; - auto const answer = fast_float::parse_number_string( + auto answer = fast_float::parse_number_string( f.data(), f.data() + f.size(), fast_float::parse_options( fast_float::chars_format::json | - fast_float::chars_format::allow_leading_plus)); // should be - // ignored + fast_float::chars_format::allow_leading_plus)); // should be ignored if (!answer.invalid) { std::cerr << "json parse accepted invalid json " << f << std::endl; return EXIT_FAILURE; From 051d15119ed9c89aab946102f063197104f92587 Mon Sep 17 00:00:00 2001 From: IRainman Date: Mon, 29 Dec 2025 23:57:28 +0300 Subject: [PATCH 247/252] small performance improvement after full cleanup. --- include/fast_float/ascii_number.h | 2 +- include/fast_float/bigint.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 286b7d47..3c97c6a3 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -582,7 +582,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST if (std::is_constant_evaluated()) { uint8_t str[4]; - for (uint_fast8_t j = 0; j < 4 && j < len; ++j) { + for (uint_fast8_t j = 0; j != 4 && j != len; ++j) { str[j] = static_cast(p[j]); } digits = bit_cast(str); diff --git a/include/fast_float/bigint.h b/include/fast_float/bigint.h index b089292c..a25c201c 100644 --- a/include/fast_float/bigint.h +++ b/include/fast_float/bigint.h @@ -518,7 +518,7 @@ struct bigint : pow5_tables<> { limb_t const shl = n; limb_t const shr = limb_bits - shl; limb prev = 0; - for (limb_t index = 0; index < vec.len(); ++index) { + for (limb_t index = 0; index != vec.len(); ++index) { limb xi = vec[index]; vec[index] = (xi << shl) | (prev >> shr); prev = xi; From cd61547b63d72aa645e6e72a8d56cdd071a78232 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 30 Dec 2025 00:11:16 +0300 Subject: [PATCH 248/252] FASTFLOAT_HAS_BIT_CAST fix for old standards. --- include/fast_float/float_common.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 6e51143f..7191b045 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -251,11 +251,14 @@ using parse_options = parse_options_t; #endif namespace fast_float { +#if FASTFLOAT_HAS_BIT_CAST template fastfloat_really_inline constexpr To bit_cast(const From &from) noexcept { -#if FASTFLOAT_HAS_BIT_CAST return std::bit_cast(from); +} #else +template +fastfloat_really_inline To bit_cast(const From &from) noexcept { // Implementation of std::bit_cast for pre-C++20. static_assert(sizeof(To) == sizeof(From), "bit_cast requires source and destination to be the same size"); @@ -263,8 +266,8 @@ fastfloat_really_inline constexpr To bit_cast(const From &from) noexcept { // The cast suppresses a bogus -Wclass-memaccess on GCC. std::memcpy(static_cast(&to), &from, sizeof(to)); return to; -#endif } +#endif fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept { #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED From fcdb5869d4b5106d5e2e8efd32ec0fb3f8f1ae02 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 30 Dec 2025 00:39:02 +0300 Subject: [PATCH 249/252] cleanup in the API. --- include/fast_float/fast_float.h | 10 ++++----- include/fast_float/parse_number.h | 35 +++++++++++++++---------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index b478e658..4bb85446 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -60,10 +60,10 @@ from_chars_advanced(UC const *first, UC const *last, T &value, */ FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - am_pow_t const decimal_exponent) noexcept; + int const decimal_exponent) noexcept; FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - am_pow_t const decimal_exponent) noexcept; + int const decimal_exponent) noexcept; /** * This function is a template overload of `integer_times_pow10()` @@ -74,12 +74,12 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - am_pow_t const decimal_exponent) noexcept; + int const decimal_exponent) noexcept; template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - am_pow_t const decimal_exponent) noexcept; + int const decimal_exponent) noexcept; /** * from_chars for integer types. @@ -88,7 +88,7 @@ template ::value)> FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars(UC const *first, UC const *last, T &value, - base_t const base = 10) noexcept; + int const base = 10) noexcept; } // namespace fast_float diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 4a04ff1d..b3b83358 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -376,15 +376,15 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, template FASTFLOAT_CONSTEXPR20 from_chars_result_t -from_chars(UC const *first, UC const *last, T &value, - base_t const base) noexcept { +from_chars(UC const *first, UC const *last, T &value, int const base) noexcept { static_assert(is_supported_integer_type::value, "only integer types are supported"); static_assert(is_supported_char_type::value, "only char, wchar_t, char16_t and char32_t are supported"); - parse_options_t const options(chars_format::general, UC('.'), base); + parse_options_t const options(chars_format::general, UC('.'), + static_cast(base)); return from_chars_advanced(first, last, value, options); } @@ -392,17 +392,17 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(uint64_t const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { T value; - if (clinger_fast_path_impl(mantissa, decimal_exponent, + const auto exponent = static_cast(decimal_exponent); + if (clinger_fast_path_impl(mantissa, exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, #endif value)) return value; - adjusted_mantissa am = - compute_float>(decimal_exponent, mantissa); + adjusted_mantissa am = compute_float>(exponent, mantissa); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN false, @@ -415,7 +415,7 @@ template FASTFLOAT_CONSTEXPR20 typename std::enable_if::value, T>::type integer_times_pow10(int64_t const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN const auto is_negative = mantissa < 0; const auto m = static_cast(is_negative ? -mantissa : mantissa); @@ -423,8 +423,9 @@ FASTFLOAT_CONSTEXPR20 FASTFLOAT_ASSUME(mantissa >= 0); const auto m = static_cast(mantissa); #endif + const auto exponent = static_cast(decimal_exponent); T value; - if (clinger_fast_path_impl(m, decimal_exponent, + if (clinger_fast_path_impl(m, exponent, #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN is_negative, #endif @@ -432,7 +433,7 @@ FASTFLOAT_CONSTEXPR20 return value; adjusted_mantissa const am = - compute_float>(decimal_exponent, m); + compute_float>(exponent, m); to_float( #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN @@ -444,13 +445,13 @@ FASTFLOAT_CONSTEXPR20 FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(uint64_t const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } FASTFLOAT_CONSTEXPR20 inline double integer_times_pow10(int64_t const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { return integer_times_pow10(mantissa, decimal_exponent); } @@ -463,7 +464,7 @@ FASTFLOAT_CONSTEXPR20 !std::is_signed::value, T>::type integer_times_pow10(Int const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -475,7 +476,7 @@ FASTFLOAT_CONSTEXPR20 std::is_signed::value, T>::type integer_times_pow10(Int const mantissa, - am_pow_t const decimal_exponent) noexcept { + int const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } @@ -483,16 +484,14 @@ FASTFLOAT_CONSTEXPR20 template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && !std::is_signed::value, double>::type -integer_times_pow10(Int const mantissa, - am_pow_t const decimal_exponent) noexcept { +integer_times_pow10(Int const mantissa, int const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } template FASTFLOAT_CONSTEXPR20 typename std::enable_if< std::is_integral::value && std::is_signed::value, double>::type -integer_times_pow10(Int const mantissa, - am_pow_t const decimal_exponent) noexcept { +integer_times_pow10(Int const mantissa, int const decimal_exponent) noexcept { return integer_times_pow10(static_cast(mantissa), decimal_exponent); } From 3d69a9593eef4ad72fe2af6da1b1e57f4efd6b0d Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 30 Dec 2025 00:45:13 +0300 Subject: [PATCH 250/252] type usage fix. --- include/fast_float/ascii_number.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 3c97c6a3..41cf9777 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -629,7 +629,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } if (nd > 3) { const UC *q = p + nd; - am_bits_t rem = len - nd; + am_digits rem = len - nd; while (rem) { if (*q < UC('0') || *q > UC('9')) break; From f9bac93deb61365fc5c6280dcd1f87c231a1f5ba Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 30 Dec 2025 01:04:02 +0300 Subject: [PATCH 251/252] type usage fix. --- include/fast_float/decimal_to_binary.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index b1f88421..661f8ddf 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -141,8 +141,9 @@ compute_float(am_pow_t q, am_mant_t w) noexcept { // branchless approach: value128 product = compute_product(q, w); but in // practice, we can win big with the compute_product_approximation if its // additional branch is easily predicted. Which is best is data specific. - am_bits_t const upperbit = static_cast(product.high >> 63); - am_bits_t const shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + auto const upperbit = static_cast(product.high >> 63); + auto const shift = static_cast( + upperbit + 64 - binary::mantissa_explicit_bits() - 3); // Shift right the mantissa to the correct position answer.mantissa = product.high >> shift; From 49106981a3b336971a7ccf7f3fa2e662d7eb2c00 Mon Sep 17 00:00:00 2001 From: IRainman Date: Tue, 30 Dec 2025 01:56:56 +0300 Subject: [PATCH 252/252] added compilation flags to the bench ip. --- benchmarks/bench_ip.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/benchmarks/bench_ip.cpp b/benchmarks/bench_ip.cpp index 825a6b0a..0421299b 100644 --- a/benchmarks/bench_ip.cpp +++ b/benchmarks/bench_ip.cpp @@ -1,3 +1,9 @@ + +// #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN +// #define FASTFLOAT_TABLE_HACK_CHAR_DIGIT_LUT_DISABLED +// #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED +// #define FASTFLOAT_ISNOT_CHECKED_BOUNDS + #include "counters/bench.h" #include "fast_float/fast_float.h" #include