From b0b1954c871b9abf0bbc4f5dce3be5389a3dd35d Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 5 Mar 2025 23:21:24 +0300 Subject: [PATCH 001/131] * 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/131] * 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/131] 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/131] 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/131] 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/131] # 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] #### # 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] . --- 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] . --- 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] * 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/131] # 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/131] 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/131] 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/131] * 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/131] 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/131] * 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/131] # 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/131] * 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] . --- .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/131] . --- .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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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/131] 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;