diff --git a/changelog/current.md b/changelog/current.md index 8ff5e5df..25dfa160 100644 --- a/changelog/current.md +++ b/changelog/current.md @@ -1,9 +1,5 @@ -- [PR#169](https://github.com/biojppm/c4core/pull/169) atof()/atod(): - - disable assertions that prevent returning false - - c4/std/std.hpp: remove tuple.hpp -- [PR#171](https://github.com/biojppm/c4core/pull/171): - - fix warnings from names with underscores (clang: -Wreserved-identifier) - - c4/std/std.hpp: remove tuple.hpp +- [PR#175](https://github.com/biojppm/c4core/pull/175): update fastfloat to 8.2.10 +- [PR#174](https://github.com/biojppm/c4core/pull/174): improve amalgamate_utils.py - [PR#172](https://github.com/biojppm/c4core/pull/172): - [**BREAKING**] `C4_LIKELY()` and `C4_UNLIKELY()` now use `[[likely]]` and `[[unlikely]]` in C++20. Every use of this macro needs to refactored: ```c++ @@ -14,3 +10,10 @@ ``` - Add `C4_LIKELY20` and `C4_UNLIKELY20`, which resolve directly into `[[likely]]` and `[[unlikely]]` when C++ is 20 or later, or nothing otherwise. - Add C++23 detection (`C4_CPP` and `C4_CPP23`) +- [PR#171](https://github.com/biojppm/c4core/pull/171): + - fix warnings from names with underscores (clang: -Wreserved-identifier) + - c4/std/std.hpp: remove tuple.hpp +- [PR#170](https://github.com/biojppm/c4core/pull/170) add option to use fastfloat from system: `C4CORE_WITH_FASTFLOAT_SYSTEM` +- [PR#169](https://github.com/biojppm/c4core/pull/169) `atof()`/`atod()`: + - disable assertions that prevent returning false + - c4/std/std.hpp: remove tuple.hpp diff --git a/src/c4/ext/fast_float b/src/c4/ext/fast_float index 8234a896..34164f54 160000 --- a/src/c4/ext/fast_float +++ b/src/c4/ext/fast_float @@ -1 +1 @@ -Subproject commit 8234a896236a6c98ee66cf214b31ca15e24579ca +Subproject commit 34164f547b7df3f5d794ff67e9f885c36819ebfc diff --git a/src/c4/ext/fast_float_all.h b/src/c4/ext/fast_float_all.h index f9e91796..f9b9e2da 100644 --- a/src/c4/ext/fast_float_all.h +++ b/src/c4/ext/fast_float_all.h @@ -119,7 +119,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 9 +#define FASTFLOAT_VERSION_PATCH 10 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) @@ -2430,9 +2430,27 @@ parse_int_string(UC const *p, UC const *pend, T &value, } // 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)) { - answer.ec = std::errc::result_out_of_range; - return answer; + if (digit_count == max_digits) { + // At the max_digits boundary the accumulator `i` may have wrapped around + // 2^64. A plain `i < min_safe_u64(base)` test is not sufficient: for any + // base whose max_digits-length range exceeds 2^64 (base 10 reaches + // ~5.4 * 2^64 at 20 digits) the value can wrap a whole multiple of 2^64 and + // land back above min_safe, slipping through. Decide exactly in O(1) using + // the leading digit, following the approach used in simdjson: + // ms == min_safe_u64(base) == base^(max_digits-1), the smallest + // max_digits-length value. + // dmax == the largest leading digit whose number can still fit in u64. + // The leading-digit band [d*ms, (d+1)*ms) has width ms < 2^64, so within + // the single band where d == dmax the value straddles 2^64 at most once, + // and a single threshold separates wrapped from non-wrapped values. A + // leading digit above dmax always overflows; below dmax always fits. + uint64_t const ms = min_safe_u64(base); + uint64_t const dmax = (std::numeric_limits::max)() / ms; + uint64_t const lead = ch_to_digit(*start_digits); + if (lead > dmax || (lead == dmax && i < dmax * ms)) { + answer.ec = std::errc::result_out_of_range; + return answer; + } } // check other types overflow