diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2023-06-09 11:27:03 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2023-06-09 11:27:03 +0300 |
commit | 5284a823d0ee2fff26807b65b8944450b3de632e (patch) | |
tree | 9e92978b7bcef0f7633bf8b983dba953e2191fcf /contrib/restricted/fast_float | |
parent | 083db20c17c2cf642bbac27c41ba1fa68645b4a8 (diff) | |
download | ydb-5284a823d0ee2fff26807b65b8944450b3de632e.tar.gz |
Update contrib/restricted/fast_float to 5.0.0
Diffstat (limited to 'contrib/restricted/fast_float')
9 files changed, 378 insertions, 186 deletions
diff --git a/contrib/restricted/fast_float/LICENSE-BOOST b/contrib/restricted/fast_float/LICENSE-BOOST new file mode 100644 index 0000000000..127a5bc39b --- /dev/null +++ b/contrib/restricted/fast_float/LICENSE-BOOST @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/contrib/restricted/fast_float/README.md b/contrib/restricted/fast_float/README.md index 10cd01b041..4f3eb22d76 100644 --- a/contrib/restricted/fast_float/README.md +++ b/contrib/restricted/fast_float/README.md @@ -1,4 +1,8 @@ + ## fast_float number parsing library: 4x faster than strtod +[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:fast_float) +[](https://github.com/fastfloat/fast_float/actions/workflows/vs17-ci.yml) +[](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml) The fast_float library provides fast header-only implementations for the C++ from_chars functions for `float` and `double` types. These functions convert ASCII strings representing @@ -93,6 +97,24 @@ constexpr double constexptest() { } ``` +## Non-ASCII Inputs + +We also support UTF-16 and UTF-32 inputs, as well as ASCII/UTF-8, as in the following example: + +``` C++ +#include "fast_float/fast_float.h" +#include <iostream> + +int main() { + const std::u16string input = u"3.1416 xyz "; + double result; + auto answer = fast_float::from_chars(input.data(), input.data()+input.size(), result); + if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return EXIT_FAILURE; } + std::cout << "parsed the number " << result << std::endl; + return EXIT_SUCCESS; +} +``` + ## Using commas as decimal separator @@ -189,11 +211,11 @@ It can parse random floating-point numbers at a speed of 1 GB/s on some systems. $ ./build/benchmarks/benchmark # parsing random integers in the range [0,1) volume = 2.09808 MB -netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s -doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s -strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s -abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s -fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s +netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s +doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s +strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s +abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s +fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/s ``` See https://github.com/lemire/simple_fastfloat_benchmark for our benchmarking code. @@ -257,7 +279,7 @@ under the Apache 2.0 license. <sup> Licensed under either of <a href="LICENSE-APACHE">Apache License, Version -2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. +2.0</a> or <a href="LICENSE-MIT">MIT license</a> or <a href="LICENSE-BOOST">BOOST license</a> . </sup> <br> @@ -265,5 +287,5 @@ Licensed under either of <a href="LICENSE-APACHE">Apache License, Version <sub> Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this repository by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. +shall be triple licensed as above, without any additional terms or conditions. </sub> diff --git a/contrib/restricted/fast_float/include/fast_float/ascii_number.h b/contrib/restricted/fast_float/include/fast_float/ascii_number.h index 72b8098eda..d506326ec9 100644 --- a/contrib/restricted/fast_float/include/fast_float/ascii_number.h +++ b/contrib/restricted/fast_float/include/fast_float/ascii_number.h @@ -12,8 +12,9 @@ namespace fast_float { // Next function can be micro-optimized, but compilers are entirely // able to optimize it well. -fastfloat_really_inline constexpr bool is_integer(char c) noexcept { - return c >= '0' && c <= '9'; +template <typename UC> +fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { + return !(c > UC('9') || c < UC('0')); } fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { @@ -75,6 +76,16 @@ uint32_t parse_eight_digits_unrolled(uint64_t val) { return uint32_t(val); } +fastfloat_really_inline constexpr +uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept { + return 0; +} + +fastfloat_really_inline constexpr +uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept { + return 0; +} + fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t parse_eight_digits_unrolled(const char *chars) noexcept { return parse_eight_digits_unrolled(read_u64(chars)); @@ -86,40 +97,51 @@ fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val 0x8080808080808080)); } +fastfloat_really_inline constexpr +bool is_made_of_eight_digits_fast(const char16_t *) noexcept { + return false; +} + +fastfloat_really_inline constexpr +bool is_made_of_eight_digits_fast(const char32_t *) noexcept { + return false; +} + fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool is_made_of_eight_digits_fast(const char *chars) noexcept { return is_made_of_eight_digits_fast(read_u64(chars)); } -typedef span<const char> byte_span; - -struct parsed_number_string { +template <typename UC> +struct parsed_number_string_t { int64_t exponent{0}; uint64_t mantissa{0}; - const char *lastmatch{nullptr}; + UC const * lastmatch{nullptr}; bool negative{false}; bool valid{false}; bool too_many_digits{false}; // contains the range of the significant digits - byte_span integer{}; // non-nullable - byte_span fraction{}; // nullable + span<const UC> integer{}; // non-nullable + span<const UC> fraction{}; // nullable }; - +using byte_span = span<char>; +using parsed_number_string = parsed_number_string_t<char>; // Assuming that you use no more than 19 digits, this will // parse an ASCII string. +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 -parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept { - const chars_format fmt = options.format; - const char decimal_point = options.decimal_point; +parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept { + chars_format const fmt = options.format; + UC const decimal_point = options.decimal_point; - parsed_number_string answer; + parsed_number_string_t<UC> answer; answer.valid = false; answer.too_many_digits = false; - answer.negative = (*p == '-'); -#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default - if ((*p == '-') || (*p == '+')) { + answer.negative = (*p == UC('-')); +#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default + if ((*p == UC('-')) || (*p == UC('+'))) { #else - if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here #endif ++p; if (p == pend) { @@ -129,7 +151,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ return answer; } } - const char *const start_digits = p; + UC const * const start_digits = p; uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) @@ -137,29 +159,31 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ // a multiplication by 10 is cheaper than an arbitrary integer // multiplication i = 10 * i + - uint64_t(*p - '0'); // might overflow, we will handle the overflow later + uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later ++p; } - const char *const end_of_integer_part = p; + UC const * const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits); - answer.integer = byte_span(start_digits, size_t(digit_count)); + answer.integer = span<const UC>(start_digits, size_t(digit_count)); int64_t exponent = 0; if ((p != pend) && (*p == decimal_point)) { ++p; - const char* before = p; + UC 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. - while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) { - i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok - p += 8; + if (std::is_same<UC,char>::value) { + while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) { + i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok + p += 8; + } } while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - '0'); + uint8_t digit = uint8_t(*p - UC('0')); ++p; i = i * 10 + digit; // in rare cases, this will overflow, but that's ok } exponent = before - p; - answer.fraction = byte_span(before, size_t(p - before)); + answer.fraction = span<const UC>(before, size_t(p - before)); digit_count -= exponent; } // we must have encountered at least one integer! @@ -167,14 +191,14 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ return answer; } int64_t exp_number = 0; // explicit exponential part - if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) { - const char * location_of_e = p; + if ((fmt & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) { + UC const * location_of_e = p; ++p; bool neg_exp = false; - if ((p != pend) && ('-' == *p)) { + if ((p != pend) && (UC('-') == *p)) { neg_exp = true; ++p; - } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + } else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) ++p; } if ((p == pend) || !is_integer(*p)) { @@ -186,7 +210,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ p = location_of_e; } else { while ((p != pend) && is_integer(*p)) { - uint8_t digit = uint8_t(*p - '0'); + uint8_t digit = uint8_t(*p - UC('0')); if (exp_number < 0x10000000) { exp_number = 10 * exp_number + digit; } @@ -212,9 +236,9 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ // 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. - const char *start = start_digits; - while ((start != pend) && (*start == '0' || *start == decimal_point)) { - if(*start == '0') { digit_count --; } + UC const * start = start_digits; + while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { + if(*start == UC('0')) { digit_count --; } start++; } if (digit_count > 19) { @@ -224,19 +248,19 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_ // pre-tokenized spans from above. i = 0; p = answer.integer.ptr; - const char* int_end = p + answer.integer.len(); + UC const * int_end = p + answer.integer.len(); const uint64_t minimal_nineteen_digit_integer{1000000000000000000}; while((i < minimal_nineteen_digit_integer) && (p != int_end)) { - i = i * 10 + uint64_t(*p - '0'); + i = i * 10 + uint64_t(*p - UC('0')); ++p; } if (i >= minimal_nineteen_digit_integer) { // We have a big integers exponent = end_of_integer_part - p + exp_number; } else { // We have a value with a fractional component. p = answer.fraction.ptr; - const char* frac_end = p + answer.fraction.len(); + UC const * frac_end = p + answer.fraction.len(); while((i < minimal_nineteen_digit_integer) && (p != frac_end)) { - i = i * 10 + uint64_t(*p - '0'); + i = i * 10 + uint64_t(*p - UC('0')); ++p; } exponent = answer.fraction.ptr - p + exp_number; diff --git a/contrib/restricted/fast_float/include/fast_float/constexpr_feature_detect.h b/contrib/restricted/fast_float/include/fast_float/constexpr_feature_detect.h index 9ec8611fd9..ba8b65c64a 100644 --- a/contrib/restricted/fast_float/include/fast_float/constexpr_feature_detect.h +++ b/contrib/restricted/fast_float/include/fast_float/constexpr_feature_detect.h @@ -14,13 +14,13 @@ #define FASTFLOAT_CONSTEXPR14 #endif -#if __cpp_lib_bit_cast >= 201806L +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L #define FASTFLOAT_HAS_BIT_CAST 1 #else #define FASTFLOAT_HAS_BIT_CAST 0 #endif -#if __cpp_lib_is_constant_evaluated >= 201811L +#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L #define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 #else #define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 diff --git a/contrib/restricted/fast_float/include/fast_float/decimal_to_binary.h b/contrib/restricted/fast_float/include/fast_float/decimal_to_binary.h index 6d0f73040f..fec916f3a0 100644 --- a/contrib/restricted/fast_float/include/fast_float/decimal_to_binary.h +++ b/contrib/restricted/fast_float/include/fast_float/decimal_to_binary.h @@ -48,9 +48,9 @@ namespace detail { * where * p = log(5**q)/log(2) = q * log(5)/log(2) * - * For negative values of q in (-400,0), we have that + * For negative values of q in (-400,0), we have that * f = (((152170 + 65536) * q ) >> 16); - * is equal to + * is equal to * -ceil(p) + q * where * p = log(5**-q)/log(2) = -q * log(5)/log(2) diff --git a/contrib/restricted/fast_float/include/fast_float/digit_comparison.h b/contrib/restricted/fast_float/include/fast_float/digit_comparison.h index 3959ba0ebd..f469f6b553 100644 --- a/contrib/restricted/fast_float/include/fast_float/digit_comparison.h +++ b/contrib/restricted/fast_float/include/fast_float/digit_comparison.h @@ -23,8 +23,9 @@ constexpr static uint64_t powers_of_ten_uint64[] = { // this algorithm is not even close to optimized, but it has no practical // effect on performance: in order to have a faster algorithm, we'd need // to slow down performance for faster algorithms, and this is still fast. +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR14 -int32_t scientific_exponent(parsed_number_string& num) noexcept { +int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept { uint64_t mantissa = num.mantissa; int32_t exponent = int32_t(num.exponent); while (mantissa >= 10000) { @@ -153,19 +154,19 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept { } am.power2 += shift; } - +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 -void skip_zeros(const char*& first, const char* last) noexcept { +void skip_zeros(UC const * & first, UC const * last) noexcept { uint64_t val; - while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) { + while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) { ::memcpy(&val, first, sizeof(uint64_t)); - if (val != 0x3030303030303030) { + if (val != int_cmp_zeros<UC>()) { break; } - first += 8; + first += int_cmp_len<UC>(); } while (first != last) { - if (*first != '0') { + if (*first != UC('0')) { break; } first++; @@ -174,32 +175,43 @@ void skip_zeros(const char*& first, const char* last) noexcept { // determine if any non-zero digits were truncated. // all characters must be valid digits. +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 -bool is_truncated(const char* first, const char* last) noexcept { +bool is_truncated(UC const * first, UC const * last) noexcept { // do 8-bit optimizations, can just compare to 8 literal 0s. uint64_t val; - while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) { + while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) { ::memcpy(&val, first, sizeof(uint64_t)); - if (val != 0x3030303030303030) { + if (val != int_cmp_zeros<UC>()) { return true; } - first += 8; + first += int_cmp_len<UC>(); } while (first != last) { - if (*first != '0') { + if (*first != UC('0')) { return true; } - first++; + ++first; } return false; } - +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR20 -bool is_truncated(byte_span s) noexcept { +bool is_truncated(span<const UC> s) noexcept { return is_truncated(s.ptr, s.ptr + s.len()); } fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +void parse_eight_digits(const char16_t*& , limb& , size_t& , size_t& ) noexcept { + // currently unused +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +void parse_eight_digits(const char32_t*& , limb& , size_t& , size_t& ) noexcept { + // currently unused +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; @@ -207,9 +219,10 @@ void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& co count += 8; } +template <typename UC> fastfloat_really_inline FASTFLOAT_CONSTEXPR14 -void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count) noexcept { - value = value * 10 + limb(*p - '0'); +void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept { + value = value * 10 + limb(*p - UC('0')); p++; counter++; count++; @@ -230,8 +243,9 @@ void round_up_bigint(bigint& big, size_t& count) noexcept { } // parse the significant digits into a big integer +template <typename UC> inline FASTFLOAT_CONSTEXPR20 -void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept { +void parse_mantissa(bigint& result, parsed_number_string_t<UC>& 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 // scalar value (9 or 19 digits) for each step. @@ -245,13 +259,15 @@ void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits #endif // process all integer digits. - const char* p = num.integer.ptr; - const char* pend = p + num.integer.len(); + UC const * p = num.integer.ptr; + UC const * pend = p + num.integer.len(); skip_zeros(p, pend); // process all digits, in increments of step per loop while (p != pend) { - while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + if (std::is_same<UC,char>::value) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } } while (counter < step && p != pend && digits < max_digits) { parse_one_digit(p, value, counter, digits); @@ -283,8 +299,10 @@ void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits } // process all digits, in increments of step per loop while (p != pend) { - while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { - parse_eight_digits(p, value, counter, digits); + if (std::is_same<UC,char>::value) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } } while (counter < step && p != pend && digits < max_digits) { parse_one_digit(p, value, counter, digits); @@ -395,9 +413,9 @@ adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int // `b` as a big-integer type, scaled to the same binary exponent as // the actual digits. we then compare the big integer representations // of both, and use that to direct rounding. -template <typename T> +template <typename T, typename UC> inline FASTFLOAT_CONSTEXPR20 -adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept { +adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; diff --git a/contrib/restricted/fast_float/include/fast_float/fast_float.h b/contrib/restricted/fast_float/include/fast_float/fast_float.h index 65704da4b5..04efa877ee 100644 --- a/contrib/restricted/fast_float/include/fast_float/fast_float.h +++ b/contrib/restricted/fast_float/include/fast_float/fast_float.h @@ -1,35 +1,10 @@ + #ifndef FASTFLOAT_FAST_FLOAT_H #define FASTFLOAT_FAST_FLOAT_H -#include <system_error> - -#include "constexpr_feature_detect.h" +#include "float_common.h" namespace fast_float { -enum chars_format { - scientific = 1<<0, - fixed = 1<<2, - hex = 1<<3, - general = fixed | scientific -}; - - -struct from_chars_result { - const char *ptr; - std::errc ec; -}; - -struct parse_options { - constexpr explicit parse_options(chars_format fmt = chars_format::general, - char dot = '.') - : format(fmt), decimal_point(dot) {} - - /** Which number formats are accepted */ - chars_format format; - /** The character used as decimal point */ - char decimal_point; -}; - /** * This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting * a locale-indepent format equivalent to what is used by std::strtod in the default ("C") locale. @@ -49,18 +24,18 @@ struct parse_options { * to determine whether we allow the fixed point and scientific notation respectively. * The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`. */ -template<typename T> +template<typename T, typename UC = char> FASTFLOAT_CONSTEXPR20 -from_chars_result from_chars(const char *first, const char *last, +from_chars_result_t<UC> from_chars(UC const * first, UC const * last, T &value, chars_format fmt = chars_format::general) noexcept; /** * Like from_chars, but accepts an `options` argument to govern number parsing. */ -template<typename T> +template<typename T, typename UC = char> FASTFLOAT_CONSTEXPR20 -from_chars_result from_chars_advanced(const char *first, const char *last, - T &value, parse_options options) noexcept; +from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last, + T &value, parse_options_t<UC> options) noexcept; } // namespace fast_float #include "parse_number.h" diff --git a/contrib/restricted/fast_float/include/fast_float/float_common.h b/contrib/restricted/fast_float/include/fast_float/float_common.h index c878486b9a..2465ea66a0 100644 --- a/contrib/restricted/fast_float/include/fast_float/float_common.h +++ b/contrib/restricted/fast_float/include/fast_float/float_common.h @@ -6,6 +6,40 @@ #include <cassert> #include <cstring> #include <type_traits> +#include <system_error> + +#include "constexpr_feature_detect.h" + +namespace fast_float { + +enum chars_format { + scientific = 1 << 0, + fixed = 1 << 2, + hex = 1 << 3, + general = fixed | scientific +}; + +template <typename UC> +struct from_chars_result_t { + UC const* ptr; + std::errc ec; +}; +using from_chars_result = from_chars_result_t<char>; + +template <typename UC> +struct parse_options_t { + constexpr explicit parse_options_t(chars_format fmt = chars_format::general, + UC dot = UC('.')) + : format(fmt), decimal_point(dot) {} + + /** Which number formats are accepted */ + chars_format format; + /** The character used as decimal point */ + UC decimal_point; +}; +using parse_options = parse_options_t<char>; + +} #if FASTFLOAT_HAS_BIT_CAST #include <bit> @@ -106,11 +140,12 @@ fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { } // Compares two ASCII strings in a case insensitive manner. +template <typename UC> inline FASTFLOAT_CONSTEXPR14 bool -fastfloat_strncasecmp(const char *input1, const char *input2, size_t length) { +fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) { char running_diff{0}; - for (size_t i = 0; i < length; i++) { - running_diff |= (input1[i] ^ input2[i]); + for (size_t i = 0; i < length; ++i) { + running_diff |= (char(input1[i]) ^ char(input2[i])); } return (running_diff == 0) || (running_diff == 32); } @@ -251,16 +286,43 @@ struct adjusted_mantissa { // Bias so we can get the real exponent with an invalid adjusted_mantissa. constexpr static int32_t invalid_am_bias = -0x8000; -constexpr static double powers_of_ten_double[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, - 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; -constexpr static float powers_of_ten_float[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, - 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; -// used for max_mantissa_double and max_mantissa_float +// used for binary_format_lookup_tables<T>::max_mantissa constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; -// Largest integer value v so that (5**index * v) <= 1<<53. -// 0x10000000000000 == 1 << 53 -constexpr static uint64_t max_mantissa_double[] = { + +template <typename T, typename U = void> +struct binary_format_lookup_tables; + +template <typename T> struct binary_format : binary_format_lookup_tables<T> { + using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; + + static inline constexpr int mantissa_explicit_bits(); + static inline constexpr int minimum_exponent(); + static inline constexpr int infinite_power(); + static inline constexpr int sign_index(); + static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int max_exponent_fast_path(); + static inline constexpr int max_exponent_round_to_even(); + static inline constexpr int min_exponent_round_to_even(); + static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); + static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST + static inline constexpr int largest_power_of_ten(); + static inline constexpr int smallest_power_of_ten(); + static inline constexpr T exact_power_of_ten(int64_t power); + static inline constexpr size_t max_digits(); + static inline constexpr equiv_uint exponent_mask(); + static inline constexpr equiv_uint mantissa_mask(); + static inline constexpr equiv_uint hidden_bit_mask(); +}; + +template <typename U> +struct binary_format_lookup_tables<double, U> { + static constexpr double powers_of_ten[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + + // Largest integer value v so that (5**index * v) <= 1<<53. + // 0x10000000000000 == 1 << 53 + static constexpr uint64_t max_mantissa[] = { 0x10000000000000, 0x10000000000000 / 5, 0x10000000000000 / (5 * 5), @@ -285,44 +347,42 @@ constexpr static uint64_t max_mantissa_double[] = { 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5), 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5), 0x10000000000000 / (constant_55555 * constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5)}; +}; + +template <typename U> +constexpr double binary_format_lookup_tables<double, U>::powers_of_ten[]; + +template <typename U> +constexpr uint64_t binary_format_lookup_tables<double, U>::max_mantissa[]; + +template <typename U> +struct binary_format_lookup_tables<float, U> { + static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, + 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; + // Largest integer value v so that (5**index * v) <= 1<<24. // 0x1000000 == 1<<24 - constexpr static uint64_t max_mantissa_float[] = { - 0x1000000, - 0x1000000 / 5, - 0x1000000 / (5 * 5), - 0x1000000 / (5 * 5 * 5), - 0x1000000 / (5 * 5 * 5 * 5), - 0x1000000 / (constant_55555), - 0x1000000 / (constant_55555 * 5), - 0x1000000 / (constant_55555 * 5 * 5), - 0x1000000 / (constant_55555 * 5 * 5 * 5), - 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), - 0x1000000 / (constant_55555 * constant_55555), - 0x1000000 / (constant_55555 * constant_55555 * 5)}; - -template <typename T> struct binary_format { - using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type; - - static inline constexpr int mantissa_explicit_bits(); - static inline constexpr int minimum_exponent(); - static inline constexpr int infinite_power(); - static inline constexpr int sign_index(); - static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST - static inline constexpr int max_exponent_fast_path(); - static inline constexpr int max_exponent_round_to_even(); - static inline constexpr int min_exponent_round_to_even(); - static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); - static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST - static inline constexpr int largest_power_of_ten(); - static inline constexpr int smallest_power_of_ten(); - static inline constexpr T exact_power_of_ten(int64_t power); - static inline constexpr size_t max_digits(); - static inline constexpr equiv_uint exponent_mask(); - static inline constexpr equiv_uint mantissa_mask(); - static inline constexpr equiv_uint hidden_bit_mask(); + static constexpr uint64_t max_mantissa[] = { + 0x1000000, + 0x1000000 / 5, + 0x1000000 / (5 * 5), + 0x1000000 / (5 * 5 * 5), + 0x1000000 / (5 * 5 * 5 * 5), + 0x1000000 / (constant_55555), + 0x1000000 / (constant_55555 * 5), + 0x1000000 / (constant_55555 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * constant_55555), + 0x1000000 / (constant_55555 * constant_55555 * 5)}; }; +template <typename U> +constexpr float binary_format_lookup_tables<float, U>::powers_of_ten[]; + +template <typename U> +constexpr uint64_t binary_format_lookup_tables<float, U>::max_mantissa[]; + template <> inline constexpr int binary_format<double>::min_exponent_fast_path() { #if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) return 0; @@ -385,6 +445,7 @@ template <> inline constexpr int binary_format<double>::max_exponent_fast_path() template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { return 10; } + template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { return uint64_t(2) << mantissa_explicit_bits(); } @@ -392,7 +453,8 @@ template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_p // caller is responsible to ensure that // power >= 0 && power <= 22 // - return max_mantissa_double[power]; + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; } template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { return uint64_t(2) << mantissa_explicit_bits(); @@ -401,17 +463,19 @@ template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_pa // caller is responsible to ensure that // power >= 0 && power <= 10 // - return max_mantissa_float[power]; + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; } template <> inline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) { - return powers_of_ten_double[power]; + // 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<float>::exact_power_of_ten(int64_t power) { - - return powers_of_ten_float[power]; + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; } @@ -481,7 +545,7 @@ void to_float(bool negative, adjusted_mantissa am, T &value) { #endif } -#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default +#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default template <typename = void> struct space_lut { static constexpr bool value[] = { @@ -503,6 +567,68 @@ constexpr bool space_lut<T>::value[]; inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; } #endif + +template<typename UC> +static constexpr uint64_t int_cmp_zeros() +{ + static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), "Unsupported character size"); + return (sizeof(UC) == 1) ? 0x3030303030303030 : (sizeof(UC) == 2) ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | uint64_t(UC('0')) << 16 | UC('0')) : (uint64_t(UC('0')) << 32 | UC('0')); +} +template<typename UC> +static constexpr int int_cmp_len() +{ + return sizeof(uint64_t) / sizeof(UC); +} +template<typename UC> +static constexpr UC const * str_const_nan() +{ + return nullptr; +} +template<> +constexpr char const * str_const_nan<char>() +{ + return "nan"; +} +template<> +constexpr wchar_t const * str_const_nan<wchar_t>() +{ + return L"nan"; +} +template<> +constexpr char16_t const * str_const_nan<char16_t>() +{ + return u"nan"; +} +template<> +constexpr char32_t const * str_const_nan<char32_t>() +{ + return U"nan"; +} +template<typename UC> +static constexpr UC const * str_const_inf() +{ + return nullptr; +} +template<> +constexpr char const * str_const_inf<char>() +{ + return "infinity"; +} +template<> +constexpr wchar_t const * str_const_inf<wchar_t>() +{ + return L"infinity"; +} +template<> +constexpr char16_t const * str_const_inf<char16_t>() +{ + return u"infinity"; +} +template<> +constexpr char32_t const * str_const_inf<char32_t>() +{ + return U"infinity"; +} } // namespace fast_float #endif diff --git a/contrib/restricted/fast_float/include/fast_float/parse_number.h b/contrib/restricted/fast_float/include/fast_float/parse_number.h index 6e4f6eb833..4541d70262 100644 --- a/contrib/restricted/fast_float/include/fast_float/parse_number.h +++ b/contrib/restricted/fast_float/include/fast_float/parse_number.h @@ -4,6 +4,7 @@ #include "ascii_number.h" #include "decimal_to_binary.h" #include "digit_comparison.h" +#include "float_common.h" #include <cmath> #include <cstring> @@ -19,41 +20,41 @@ namespace detail { * The case comparisons could be made much faster given that we know that the * strings a null-free and fixed. **/ -template <typename T> -from_chars_result FASTFLOAT_CONSTEXPR14 -parse_infnan(const char *first, const char *last, T &value) noexcept { - from_chars_result answer{}; +template <typename T, typename UC> +from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14 +parse_infnan(UC const * first, UC const * last, T &value) noexcept { + from_chars_result_t<UC> answer{}; answer.ptr = first; answer.ec = std::errc(); // be optimistic bool minusSign = false; - if (*first == '-') { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here + if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here minusSign = true; ++first; } -#if FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default - if (*first == '+') { +#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default + if (*first == UC('+')) { ++first; } #endif if (last - first >= 3) { - if (fastfloat_strncasecmp(first, "nan", 3)) { + if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) { answer.ptr = (first += 3); value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::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 == '(') { - for(const char* ptr = first + 1; ptr != last; ++ptr) { - if (*ptr == ')') { + if(first != last && *first == UC('(')) { + for(UC const * ptr = first + 1; ptr != last; ++ptr) { + if (*ptr == UC(')')) { answer.ptr = ptr + 1; // valid nan(n-char-seq-opt) break; } - else if(!(('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z') || ('0' <= *ptr && *ptr <= '9') || *ptr == '_')) + else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_'))) break; // forbidden char, not nan(n-char-seq-opt) } } return answer; } - if (fastfloat_strncasecmp(first, "inf", 3)) { - if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, "inity", 5)) { + if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) { + if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) { answer.ptr = first + 8; } else { answer.ptr = first + 3; @@ -109,7 +110,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { // // Note: This may fail to be accurate if fast-math has been // enabled, as rounding conventions may not apply. - #if FASTFLOAT_VISUAL_STUDIO + #ifdef FASTFLOAT_VISUAL_STUDIO # pragma warning(push) // todo: is there a VS warning? // see https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013 @@ -121,7 +122,7 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { # pragma GCC diagnostic ignored "-Wfloat-equal" #endif return (fmini + 1.0f == 1.0f - fmini); - #if FASTFLOAT_VISUAL_STUDIO + #ifdef FASTFLOAT_VISUAL_STUDIO # pragma warning(pop) #elif defined(__clang__) # pragma clang diagnostic pop @@ -132,23 +133,26 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { } // namespace detail -template<typename T> +template<typename T, typename UC> FASTFLOAT_CONSTEXPR20 -from_chars_result from_chars(const char *first, const char *last, +from_chars_result_t<UC> from_chars(UC const * first, UC const * last, T &value, chars_format fmt /*= chars_format::general*/) noexcept { - return from_chars_advanced(first, last, value, parse_options{fmt}); + return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt}); } -template<typename T> +template<typename T, typename UC> FASTFLOAT_CONSTEXPR20 -from_chars_result from_chars_advanced(const char *first, const char *last, - T &value, parse_options options) noexcept { +from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last, + T &value, parse_options_t<UC> options) noexcept { static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported"); + static_assert (std::is_same<UC, char>::value || + std::is_same<UC, wchar_t>::value || + std::is_same<UC, char16_t>::value || + std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported"); - - from_chars_result answer; -#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default + from_chars_result_t<UC> answer; +#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default while ((first != last) && fast_float::is_space(uint8_t(*first))) { first++; } @@ -158,7 +162,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last, answer.ptr = first; return answer; } - parsed_number_string pns = parse_number_string(first, last, options); + parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options); if (!pns.valid) { return detail::parse_infnan(first, last, value); } |