diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 13c6d8e..ff7b7a5 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -4,13 +4,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@4f1f4aec02e41874fa0262ea8ff5172d7978ad1e # v4.2.2 + - uses: actions/checkout@e8d4307400f9427dba7cb98e488d6ab85f1cec5f # v4.2.2 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - uses: mymindstorm/setup-emsdk@4528d102f7230f0e7b276855c01ea1159be0e984 # v16 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@4f1f4aec02e41874fa0262ea8ff5172d7978ad1e # v3.6.0 + uses: actions/checkout@e8d4307400f9427dba7cb98e488d6ab85f1cec5f # v3.6.0 - name: Configure run: emcmake cmake -B build - name: Build # We build but do not test diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index 9441595..d307cd7 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,7 +24,7 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@4f1f4aec02e41874fa0262ea8ff5172d7978ad1e # v4.1.7 + - uses: actions/checkout@e8d4307400f9427dba7cb98e488d6ab85f1cec5f # v4.1.7 - name: Run clang-format uses: jidicula/clang-format-action@654a770daa28443dd111d133e4083e21c1075674 # v4.18.0 diff --git a/README.md b/README.md index 053af59..d40f9ee 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ struct from_chars_result { }; ``` -It parses the character sequence `[first, last]` for a number. It parses +It parses the character sequence `[first, last)` for a number. It parses floating-point numbers expecting a locale-independent format equivalent to the C++17 from_chars function. The resulting floating-point value is the closest floating-point values (using either `float` or `double`), using the "round to @@ -406,7 +406,7 @@ int main() { } ``` -## Advanced options: using commas as decimal separator, parse JSON, Fortran and more +## Advanced options: using commas as decimal separator, JSON and Fortran The C++ standard stipulate that `from_chars` has to be locale-independent. In particular, the decimal separator has to be the period (`.`). However, some @@ -539,6 +539,7 @@ float: 12345678 * 10^23 = 1.23456782e+30 (==expected) Overloads of `fast_float::integer_times_pow10()` are provided for signed and unsigned integer types: `int64_t`, `uint64_t`, etc. + ## Users and Related Work The fast_float library is part of: @@ -727,11 +728,6 @@ was originally published under the Apache 2.0 license. [PVS-Studio](https://pvs-studio.com/en/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code. -## Stars - - -[![Star History Chart](https://api.star-history.com/svg?repos=fastfloat/fast_float&type=Date)](https://www.star-history.com/#fastfloat/fast_float&Date) - ## License diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 566b6d3..3a747b9 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -249,7 +249,9 @@ loop_parse_if_digits(char const *&p, char const *const pend, uint64_t &i) { } // Consume a remaining 4-7 digit run in a single SWAR step instead of // byte-by-byte (reuses the existing 4-digit helpers). The parsed result is - // identical either way. + // identical either way. Historically gated to clang because gcc regressed on + // short remainders, but that verdict predates the span-elision restructure; + // with the leaner hot path the 4-digit step now wins on gcc as well. if (std::distance(p, pend) >= 4 /*sizeof(uint32_t)*/) { auto const val = read_chars_to_unsigned(p); if (is_made_of_four_digits_fast(val)) { @@ -302,7 +304,7 @@ using parsed_number_string = parsed_number_string_t; // Helper for error creating template -fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t& report_parse_error(parsed_number_string_t &answer, UC const *p, parse_error error) noexcept { answer.invalid = true; @@ -579,7 +581,7 @@ parse_number_string(UC const *p, UC const *pend, } answer.exponent = am_pow_t(answer.fraction.ptr - p) + exp_number; } - // We now corrected both exponent and mantissa, to a truncated value + // We have now corrected both exponent and mantissa, to a truncated value } } } @@ -660,7 +662,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; auto const tz = countr_zero_32(magic); // 7, 15, 23, 31, or 32 auto nd = static_cast(tz >> 3); - nd = std::min(nd, len); + nd = nd < len ? nd : len; if (nd == 0) { if (has_leading_zeros) { value = 0; @@ -725,13 +727,13 @@ parse_int_string(UC const *p, UC const *pend, T &value, answer.ptr = p + 5; return answer; } - value = uint16_t(v); + value = static_cast(v); answer.ec = std::errc(); answer.ptr = p + 5; return answer; } // 4 digits - value = uint16_t(v); + value = static_cast(v); answer.ec = std::errc(); answer.ptr = p + 4; return answer; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index d99a6a7..a50852a 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -16,7 +16,7 @@ namespace fast_float { namespace detail { #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN /** - * Special case inf, +inf, -inf, nan, infinity, -infinity. + * Special case +inf, -inf, nan, infinity, -infinity. * The case comparisons could be made much faster given that we know that the * strings a null-free and fixed. **/ @@ -163,10 +163,7 @@ template <> struct from_chars_caller { // 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 - float val = 0; - auto ret = from_chars_advanced(first, last, val, options); - value = val; - return ret; + return from_chars_advanced(first, last, value, options); } }; #endif @@ -180,10 +177,7 @@ template <> struct from_chars_caller { // 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 - double val = 0; - auto ret = from_chars_advanced(first, last, val, options); - value = val; - return ret; + return from_chars_advanced(first, last, value, options); } }; #endif @@ -209,7 +203,14 @@ clinger_fast_path_impl(am_mant_t const mantissa, am_pow_t const exponent, // We proceed optimistically, assuming that detail::rounds_to_nearest() // returns true. if (binary_format::min_exponent_fast_path() <= exponent && - exponent <= binary_format::max_exponent_fast_path()) { + exponent <= binary_format::max_exponent_fast_path() && + mantissa <= binary_format::max_mantissa_fast_path()) { + // The mantissa bound above is a necessary condition for BOTH branches + // below: the rounding-mode-dependent branch checks the tighter + // max_mantissa_fast_path(exponent) <= max_mantissa_fast_path(). Testing + // it before detail::rounds_to_nearest() spares long-mantissa inputs + // (which can never take the fast path) the volatile-float probe. + // // Unfortunately, the conventional Clinger's fast path is only possible // when the system rounds to the nearest float. // @@ -329,10 +330,10 @@ from_chars_advanced(parsed_number_string_t const &pns, T &value) noexcept { template FASTFLOAT_CONSTEXPR20 from_chars_result_t parse_number_slow_path(UC const *first, UC const *last, T &value, - parse_options_t options + parse_options_t const options #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN , - bool bjf + bool const bjf #endif ) noexcept { parsed_number_string_t const pns =