From 63f6abebdf792c4ce6404b295d772655c986c8cb Mon Sep 17 00:00:00 2001 From: IRainman Date: Wed, 5 Mar 2025 23:21:24 +0300 Subject: [PATCH] * 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 9001016..ec34a1c 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 74901e3..e609f69 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 648b55d..26752ee 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 9487682..94d0a00 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 d7ef3d9..ea8457a 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 2d2afca..a08f72d 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 0dbb3a1..041bede 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,