From 265cb849f3ef03028f80f6d058fc400bca41e1d1 Mon Sep 17 00:00:00 2001 From: sleepingieght Date: Tue, 30 Dec 2025 01:15:22 +0530 Subject: [PATCH 01/37] optimise fastfloat_strncasecmp --- include/fast_float/float_common.h | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 88efe85f..dc0c4173 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -2,6 +2,7 @@ #define FASTFLOAT_FLOAT_COMMON_H #include +#include #include #include #include @@ -272,9 +273,27 @@ template inline FASTFLOAT_CONSTEXPR14 bool fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, size_t length) { - for (size_t i = 0; i < length; ++i) { - UC const actual = actual_mixedcase[i]; - if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { + uint64_t mask{0}; + FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { + mask = 0x0020002000200020; + } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { + mask = 0x0000002000000020; + } + else { + return false; + } + uint64_t val1{0}, val2{0}; + size_t sz{8 / (sizeof(UC))}; + for (size_t i = 0; i < length; i += sz) { + val1 = val2 = 0; + sz = std::min(sz, length - i); + ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); + ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); + val1 |= mask; + val2 |= mask; + if (val1 != val2) { return false; } } From 4eb0d806fa9774849159501bcad627492a93b1f9 Mon Sep 17 00:00:00 2001 From: sleepingieght Date: Tue, 30 Dec 2025 20:27:45 +0530 Subject: [PATCH 02/37] add specialisations --- include/fast_float/float_common.h | 139 +++++++++++++++++++++++++++--- include/fast_float/parse_number.h | 6 +- 2 files changed, 130 insertions(+), 15 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index dc0c4173..6c1e812c 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -268,11 +268,10 @@ struct is_supported_char_type > { }; -// 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) { +fastfloat_strncasecmp3(UC const *actual_mixedcase, + UC const *expected_lowercase) { uint64_t mask{0}; FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { @@ -284,22 +283,138 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, else { return false; } + + uint64_t val1{0}, val2{0}; + if (cpp20_and_in_constexpr()) { + for (size_t i = 0; i < 3; i++) { + if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { + return false; + } + return true; + } + } else { + FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) { + ::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase, 3 * sizeof(UC)); + val1 |= mask; + val2 |= mask; + return val1 == val2; + } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { + ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); + val1 |= mask; + if (val1 != val2) { + return false; + } + return (actual_mixedcase[2] | 32) == (expected_lowercase[2]); + } + else { + return false; + } + } + + return true; +} + +template +inline FASTFLOAT_CONSTEXPR14 bool +fastfloat_strncasecmp5(UC const *actual_mixedcase, + UC const *expected_lowercase) { + uint64_t mask{0}; uint64_t val1{0}, val2{0}; - size_t sz{8 / (sizeof(UC))}; - for (size_t i = 0; i < length; i += sz) { - val1 = val2 = 0; - sz = std::min(sz, length - i); - ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); - ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); - val1 |= mask; - val2 |= mask; - if (val1 != val2) { + if (cpp20_and_in_constexpr()) { + for (size_t i = 0; i < 5; i++) { + if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { + return false; + } + return true; + } + } else { + FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { + mask = 0x2020202020202020; + ::memcpy(&val1, actual_mixedcase, 5 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase, 5 * sizeof(UC)); + val1 |= mask; + val2 |= mask; + return val1 == val2; + } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { + mask = 0x0020002000200020; + ::memcpy(&val1, actual_mixedcase, 4 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase, 4 * sizeof(UC)); + val1 |= mask; + if (val1 != val2) { + return false; + } + return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); + } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { + mask = 0x0000002000000020; + ::memcpy(&val1, actual_mixedcase, 2 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase, 2 * sizeof(UC)); + val1 |= mask; + if (val1 != val2) { + return false; + } + ::memcpy(&val1, actual_mixedcase + 2, 2 * sizeof(UC)); + ::memcpy(&val2, expected_lowercase + 2, 2 * sizeof(UC)); + val1 |= mask; + if (val1 != val2) { + return false; + } + return (actual_mixedcase[4] | 32) == (expected_lowercase[4]); + } + else { return false; } } + return true; } +// 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) { + uint64_t mask{0}; + FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 2) { + mask = 0x0020002000200020; + } + else FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 4) { + mask = 0x0000002000000020; + } + else { + return false; + } + + if (cpp20_and_in_constexpr()) { + for (size_t i = 0; i < length; i++) { + if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { + return false; + } + return true; + } + } else { + uint64_t val1{0}, val2{0}; + size_t sz{8 / (sizeof(UC))}; + for (size_t i = 0; i < length; i += sz) { + val1 = val2 = 0; + sz = std::min(sz, length - i); + ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); + ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); + val1 |= mask; + val2 |= mask; + if (val1 != val2) { + return false; + } + } + return true; + } +} + #ifndef FLT_EVAL_METHOD #error "FLT_EVAL_METHOD should be defined, please include cfloat." #endif diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index d453c145..c01bb15a 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -35,7 +35,7 @@ from_chars_result_t ++first; } if (last - first >= 3) { - if (fastfloat_strncasecmp(first, str_const_nan(), 3)) { + if (fastfloat_strncasecmp3(first, str_const_nan())) { answer.ptr = (first += 3); value = minusSign ? -std::numeric_limits::quiet_NaN() : std::numeric_limits::quiet_NaN(); @@ -54,9 +54,9 @@ from_chars_result_t } return answer; } - if (fastfloat_strncasecmp(first, str_const_inf(), 3)) { + if (fastfloat_strncasecmp3(first, str_const_inf())) { if ((last - first >= 8) && - fastfloat_strncasecmp(first + 3, str_const_inf() + 3, 5)) { + fastfloat_strncasecmp5(first + 3, str_const_inf() + 3)) { answer.ptr = first + 8; } else { answer.ptr = first + 3; From fb522b66d01365a4dd6d47a42b535a83b8497d83 Mon Sep 17 00:00:00 2001 From: Shikhar Date: Wed, 31 Dec 2025 21:51:23 +0530 Subject: [PATCH 03/37] fix endianess bug in uint8 parsing Signed-off-by: Shikhar --- include/fast_float/ascii_number.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index cac91606..aa2761aa 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -42,6 +42,11 @@ fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; } +fastfloat_really_inline constexpr uint32_t byteswap_32(uint32_t val) { + return (val >> 24) | ((val >> 8) & 0x0000FF00u) | ((val << 8) & 0x00FF0000u) | + (val << 24); +} + // Read 8 UC into a u64. Truncates UC if not char. template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t @@ -533,7 +538,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, } digits = std::bit_cast(str); #if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap(digits); + digits = byteswap_32(digits); #endif } #else @@ -543,18 +548,14 @@ parse_int_string(UC const *p, UC const *pend, T &value, else if (len >= 4) { ::memcpy(&digits, p, 4); #if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap(digits); + digits = byteswap_32(digits); #endif } else { uint32_t b0 = static_cast(p[0]); uint32_t b1 = (len > 1) ? static_cast(p[1]) : 0xFFu; uint32_t b2 = (len > 2) ? static_cast(p[2]) : 0xFFu; uint32_t b3 = 0xFFu; -#if FASTFLOAT_IS_BIG_ENDIAN - digits = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; -#else digits = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); -#endif } uint32_t magic = From 4dc522579746154de535f3866ff1c228332aa448 Mon Sep 17 00:00:00 2001 From: Shikhar Date: Wed, 31 Dec 2025 22:07:45 +0530 Subject: [PATCH 04/37] add base check for uint8 parsing Signed-off-by: Shikhar --- include/fast_float/ascii_number.h | 138 +++++++++++++++--------------- 1 file changed, 70 insertions(+), 68 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index aa2761aa..5609ba1a 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -515,93 +515,95 @@ parse_int_string(UC const *p, UC const *pend, T &value, UC const *const start_digits = p; FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { - const size_t len = (size_t)(pend - p); - if (len == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; - } else { - answer.ec = std::errc::invalid_argument; - answer.ptr = first; + if (base == 10) { + const size_t len = (size_t)(pend - p); + if (len == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + } else { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + } + return answer; } - return answer; - } - uint32_t digits; + uint32_t digits; #if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST - if (std::is_constant_evaluated()) { - uint8_t str[4]{}; - for (size_t j = 0; j < 4 && j < len; ++j) { - str[j] = static_cast(p[j]); - } - digits = std::bit_cast(str); + if (std::is_constant_evaluated()) { + uint8_t str[4]{}; + for (size_t j = 0; j < 4 && j < len; ++j) { + str[j] = static_cast(p[j]); + } + digits = std::bit_cast(str); #if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap_32(digits); + digits = byteswap_32(digits); #endif - } + } #else - if (false) { - } + if (false) { + } #endif - else if (len >= 4) { - ::memcpy(&digits, p, 4); + else if (len >= 4) { + ::memcpy(&digits, p, 4); #if FASTFLOAT_IS_BIG_ENDIAN - digits = byteswap_32(digits); + digits = byteswap_32(digits); #endif - } else { - uint32_t b0 = static_cast(p[0]); - uint32_t b1 = (len > 1) ? static_cast(p[1]) : 0xFFu; - uint32_t b2 = (len > 2) ? static_cast(p[2]) : 0xFFu; - uint32_t b3 = 0xFFu; - digits = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); - } + } else { + uint32_t b0 = static_cast(p[0]); + uint32_t b1 = (len > 1) ? static_cast(p[1]) : 0xFFu; + uint32_t b2 = (len > 2) ? static_cast(p[2]) : 0xFFu; + uint32_t b3 = 0xFFu; + digits = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + } - uint32_t magic = - ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; - uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32 - uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = (uint32_t)std::min((size_t)nd, len); - if (nd == 0) { - if (has_leading_zeros) { - value = 0; - answer.ec = std::errc(); - answer.ptr = p; + uint32_t magic = + ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; + uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32 + uint32_t nd = (tz == 32) ? 4 : (tz >> 3); + nd = (uint32_t)std::min((size_t)nd, len); + if (nd == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + return answer; + } + answer.ec = std::errc::invalid_argument; + answer.ptr = first; return answer; } - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - if (nd > 3) { - const UC *q = p + nd; - size_t rem = len - nd; - while (rem) { - if (*q < UC('0') || *q > UC('9')) - break; - ++q; - --rem; + if (nd > 3) { + const UC *q = p + nd; + size_t rem = len - nd; + while (rem) { + if (*q < UC('0') || *q > UC('9')) + break; + ++q; + --rem; + } + answer.ec = std::errc::result_out_of_range; + answer.ptr = q; + return answer; } - answer.ec = std::errc::result_out_of_range; - answer.ptr = q; - return answer; - } - digits ^= 0x30303030u; - digits <<= ((4 - nd) * 8); + digits ^= 0x30303030u; + digits <<= ((4 - nd) * 8); - uint32_t check = ((digits >> 24) & 0xff) | ((digits >> 8) & 0xff00) | - ((digits << 8) & 0xff0000); - if (check > 0x00020505) { - answer.ec = std::errc::result_out_of_range; + uint32_t check = ((digits >> 24) & 0xff) | ((digits >> 8) & 0xff00) | + ((digits << 8) & 0xff0000); + if (check > 0x00020505) { + answer.ec = std::errc::result_out_of_range; + answer.ptr = p + nd; + return answer; + } + value = (uint8_t)((0x640a01 * digits) >> 24); + answer.ec = std::errc(); answer.ptr = p + nd; return answer; } - value = (uint8_t)((0x640a01 * digits) >> 24); - answer.ec = std::errc(); - answer.ptr = p + nd; - return answer; } uint64_t i = 0; From 97b54ca9e75f5303507699d27c6b4f4efe4641a1 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 31 Dec 2025 13:12:46 -0500 Subject: [PATCH 05/37] v8.2.2 --- CMakeLists.txt | 2 +- README.md | 6 +++--- include/fast_float/float_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a220f600..83953908 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) -project(fast_float VERSION 8.2.1 LANGUAGES CXX) +project(fast_float VERSION 8.2.2 LANGUAGES CXX) set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) option(FASTFLOAT_TEST "Enable tests" OFF) diff --git a/README.md b/README.md index 71029ebe..d19283ff 100644 --- a/README.md +++ b/README.md @@ -533,7 +533,7 @@ sufficiently recent version of CMake (3.11 or better at least): FetchContent_Declare( fast_float GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.2.1 + GIT_TAG tags/v8.2.2 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) @@ -549,7 +549,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: CPMAddPackage( NAME fast_float GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.2.1) + GIT_TAG v8.2.2) ``` ## Using as single header @@ -561,7 +561,7 @@ if desired as described in the command line help. You may directly download automatically generated single-header files: - + ## Benchmarking diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 88efe85f..384b33ec 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -17,7 +17,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 1 +#define FASTFLOAT_VERSION_PATCH 2 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) From 011763f31c2af78da22029f6e2aa6f910d2ec577 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 31 Dec 2025 13:46:53 -0500 Subject: [PATCH 06/37] adding tests --- .github/workflows/s390x.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index bcce4c6c..91918f35 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -24,7 +24,7 @@ jobs: apt-get update -q -y apt-get install -y cmake make g++ run: | - cmake -DCMAKE_BUILD_TYPE=Release -B build + cmake -DCMAKE_BUILD_TYPE=Release -B build -DFASTFLOAT_TEST=ON cmake --build build -j=2 ctest --output-on-failure --test-dir build From 6440936afb5c0bd8dd1e9c88d2f35b3e185a4865 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 1 Jan 2026 17:49:15 -0500 Subject: [PATCH 07/37] see if this fixes the issue with s390x. --- .github/workflows/s390x.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 91918f35..0bc90d98 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -22,7 +22,7 @@ jobs: distro: ubuntu_latest install: | apt-get update -q -y - apt-get install -y cmake make g++ + apt-get install -y cmake make g++ git run: | cmake -DCMAKE_BUILD_TYPE=Release -B build -DFASTFLOAT_TEST=ON cmake --build build -j=2 From 36d3441dc03d1551d48aa424c55905b6c9e5c14d Mon Sep 17 00:00:00 2001 From: Shikhar Date: Thu, 1 Jan 2026 08:09:00 +0530 Subject: [PATCH 08/37] add bench_uint16 Signed-off-by: Shikhar --- benchmarks/CMakeLists.txt | 6 ++ benchmarks/bench_uint16.cpp | 139 ++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 benchmarks/bench_uint16.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 4ee57895..81ea92a6 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -11,7 +11,9 @@ FetchContent_MakeAvailable(counters) add_executable(realbenchmark benchmark.cpp) target_link_libraries(realbenchmark PRIVATE counters::counters) add_executable(bench_ip bench_ip.cpp) +add_executable(bench_uint16 bench_uint16.cpp) target_link_libraries(bench_ip PRIVATE counters::counters) +target_link_libraries(bench_uint16 PRIVATE counters::counters) set_property( TARGET realbenchmark @@ -19,8 +21,12 @@ set_property( set_property( TARGET bench_ip PROPERTY CXX_STANDARD 17) +set_property( + TARGET bench_uint16 + PROPERTY CXX_STANDARD 17) target_link_libraries(realbenchmark PUBLIC fast_float) target_link_libraries(bench_ip PUBLIC fast_float) +target_link_libraries(bench_uint16 PUBLIC fast_float) include(ExternalProject) diff --git a/benchmarks/bench_uint16.cpp b/benchmarks/bench_uint16.cpp new file mode 100644 index 00000000..c4cef81b --- /dev/null +++ b/benchmarks/bench_uint16.cpp @@ -0,0 +1,139 @@ +#include "counters/bench.h" +#include "fast_float/fast_float.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void pretty_print(size_t volume, size_t bytes, std::string name, + counters::event_aggregate agg) { + if (agg.inner_count > 1) { + printf("# (inner count: %d)\n", agg.inner_count); + } + printf("%-40s : ", name.c_str()); + printf(" %5.2f GB/s ", bytes / agg.fastest_elapsed_ns()); + printf(" %5.1f Mip/s ", volume * 1000.0 / agg.fastest_elapsed_ns()); + printf(" %5.2f ns/ip ", agg.fastest_elapsed_ns() / volume); + if (counters::event_collector().has_events()) { + printf(" %5.2f GHz ", agg.fastest_cycles() / agg.fastest_elapsed_ns()); + printf(" %5.2f c/ip ", agg.fastest_cycles() / volume); + printf(" %5.2f i/ip ", agg.fastest_instructions() / volume); + printf(" %5.2f c/b ", agg.fastest_cycles() / bytes); + printf(" %5.2f i/b ", agg.fastest_instructions() / bytes); + printf(" %5.2f i/c ", agg.fastest_instructions() / agg.fastest_cycles()); + } + printf("\n"); +} + +enum class parse_method { standard, fast_float }; + +void validate(const std::string &buffer, const std::vector &expected, + char delimiter) { + const char *p = buffer.data(); + const char *pend = p + buffer.size(); + + for (size_t i = 0; i < expected.size(); i++) { + uint16_t val; + auto r = fast_float::from_chars(p, pend, val); + if (r.ec != std::errc() || val != expected[i]) { + printf("Validation failed at index %zu: expected %u, got %u\n", i, + expected[i], val); + std::abort(); + } + p = r.ptr; + if (i + 1 < expected.size()) { + if (p >= pend || *p != delimiter) { + printf("Validation failed at index %zu: delimiter mismatch\n", i); + std::abort(); + } + ++p; + } + } + + if (p != pend) { + printf("Validation failed: trailing bytes remain\n"); + std::abort(); + } + printf("Validation passed!\n"); +} + +int main() { + constexpr size_t N = 500000; + constexpr char delimiter = ','; + std::mt19937 rng(1234); + std::uniform_int_distribution dist(0, 65535); + + std::vector expected; + expected.reserve(N); + + std::string buffer; + buffer.reserve(N * 6); // up to 5 digits + delimiter + + for (size_t i = 0; i < N; ++i) { + uint16_t val = (uint16_t)dist(rng); + expected.push_back(val); + std::string s = std::to_string(val); + buffer.append(s); + if (i + 1 < N) { + buffer.push_back(delimiter); + } + } + + size_t total_bytes = buffer.size(); + + validate(buffer, expected, delimiter); + + volatile uint64_t sink = 0; + + pretty_print(N, total_bytes, "parse_uint16_std_fromchars", + counters::bench([&]() { + uint64_t sum = 0; + const char *p = buffer.data(); + const char *pend = p + buffer.size(); + for (size_t i = 0; i < N; ++i) { + uint16_t value = 0; + auto r = std::from_chars(p, pend, value); + if (r.ec != std::errc()) + std::abort(); + sum += value; + p = r.ptr; + if (i + 1 < N) { + if (p >= pend || *p != delimiter) + std::abort(); + ++p; + } + } + if (p != pend) + std::abort(); + sink += sum; + })); + + pretty_print(N, total_bytes, "parse_uint16_fastfloat", counters::bench([&]() { + uint64_t sum = 0; + const char *p = buffer.data(); + const char *pend = p + buffer.size(); + for (size_t i = 0; i < N; ++i) { + uint16_t value = 0; + auto r = fast_float::from_chars(p, pend, value); + if (r.ec != std::errc()) + std::abort(); + sum += value; + p = r.ptr; + if (i + 1 < N) { + if (p >= pend || *p != delimiter) + std::abort(); + ++p; + } + } + if (p != pend) + std::abort(); + sink += sum; + })); + + return EXIT_SUCCESS; +} From d0af1cfdbd7dfa781f2e40c89bd6b85d886a538a Mon Sep 17 00:00:00 2001 From: Shikhar Date: Thu, 1 Jan 2026 08:29:14 +0530 Subject: [PATCH 09/37] optimize uint16 parsing Signed-off-by: Shikhar --- include/fast_float/ascii_number.h | 116 ++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 5609ba1a..b5826f6d 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -68,6 +68,26 @@ read8_to_u64(UC const *chars) { return val; } +// Read 4 UC into a u32. Truncates UC if not char. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t +read4_to_u32(UC const *chars) { + if (cpp20_and_in_constexpr() || !std::is_same::value) { + uint32_t val = 0; + for (int i = 0; i < 4; ++i) { + val |= uint32_t(uint8_t(*chars)) << (i * 8); + ++chars; + } + return val; + } + uint32_t val; + ::memcpy(&val, chars, sizeof(uint32_t)); +#if FASTFLOAT_IS_BIG_ENDIAN == 1 + val = byteswap(val); +#endif + return val; +} + #ifdef FASTFLOAT_SSE2 fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { @@ -149,6 +169,13 @@ is_made_of_eight_digits_fast(uint64_t val) noexcept { 0x8080808080808080)); } +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t +parse_four_digits_unrolled(uint32_t val) noexcept { + val -= 0x30303030; + val = (val * 10) + (val >> 8); + return (((val & 0x00FF00FF) * 0x00640001) >> 16) & 0xFFFF; +} + #ifdef FASTFLOAT_HAS_SIMD // Call this if chars might not be 8 digits. @@ -606,6 +633,95 @@ parse_int_string(UC const *p, UC const *pend, T &value, } } + FASTFLOAT_IF_CONSTEXPR17((std::is_same::value)) { + if (base == 10) { + const size_t len = size_t(pend - p); + if (len == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + } else { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + } + return answer; + } + + uint32_t digits; + if (len >= 4) { + digits = read4_to_u32(p); + } else { + uint32_t b0 = uint32_t(uint8_t(p[0])); + uint32_t b1 = (len > 1) ? uint32_t(uint8_t(p[1])) : 0xFFu; + uint32_t b2 = (len > 2) ? uint32_t(uint8_t(p[2])) : 0xFFu; + digits = b0 | (b1 << 8) | (b2 << 16) | (0xFFu << 24); + } + + uint32_t magic = + ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; + uint32_t nd = (magic == 0) ? 4u : (uint32_t(countr_zero_32(magic)) >> 3); + + if (nd == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + return answer; + } + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + + if (nd < 4) { + // mask out non-digit bytes and replace with '0' (0x30) + uint32_t mask = 0xFFFFFFFFu >> ((4u - nd) * 8u); + uint32_t padded = (digits & mask) | (~mask & 0x30303030u); + uint32_t v = parse_four_digits_unrolled(padded); + static constexpr uint32_t divs[] = {0, 1000, 100, 10}; + value = (uint16_t)(v / divs[nd]); + answer.ec = std::errc(); + answer.ptr = p + nd; + return answer; + } + + uint32_t v = parse_four_digits_unrolled(digits); + + uint32_t d4 = (len > 4) ? uint32_t(p[4] - '0') : 10u; + if (d4 > 9u) { + value = (uint16_t)v; + answer.ec = std::errc(); + answer.ptr = p + 4; + return answer; + } + + if (len > 5) { + uint32_t d5 = uint32_t(p[5]) - uint32_t('0'); + if (d5 <= 9u) { + const UC *q = p + 6; + while (q < pend && uint32_t(*q) - uint32_t('0') <= 9u) + ++q; + answer.ec = std::errc::result_out_of_range; + answer.ptr = q; + return answer; + } + } + + // overflow check + if (v > 6553u || (v == 6553u && d4 > 5u)) { + answer.ec = std::errc::result_out_of_range; + answer.ptr = p + 5; + return answer; + } + + value = (uint16_t)(v * 10u + d4); + answer.ec = std::errc(); + answer.ptr = p + 5; + return answer; + } + } + uint64_t i = 0; if (base == 10) { loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible From 13d4b9418364ab8c68b9f235065c700f88b3719a Mon Sep 17 00:00:00 2001 From: Shikhar Date: Thu, 1 Jan 2026 17:42:30 +0530 Subject: [PATCH 10/37] small fix --- 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 b5826f6d..7422e74f 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -679,7 +679,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, uint32_t mask = 0xFFFFFFFFu >> ((4u - nd) * 8u); uint32_t padded = (digits & mask) | (~mask & 0x30303030u); uint32_t v = parse_four_digits_unrolled(padded); - static constexpr uint32_t divs[] = {0, 1000, 100, 10}; + constexpr uint32_t divs[] = {0, 1000, 100, 10}; value = (uint16_t)(v / divs[nd]); answer.ec = std::errc(); answer.ptr = p + nd; From b14e6a466aba8813a9e8da2defb0671fa2db3410 Mon Sep 17 00:00:00 2001 From: Shikhar Date: Fri, 2 Jan 2026 02:45:11 +0530 Subject: [PATCH 11/37] simpler optimizations Signed-off-by: Shikhar --- include/fast_float/ascii_number.h | 103 ++++++++++-------------------- 1 file changed, 34 insertions(+), 69 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 7422e74f..85435373 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -32,7 +32,7 @@ template fastfloat_really_inline constexpr bool has_simd_opt() { // able to optimize it well. template fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { - return !(c > UC('9') || c < UC('0')); + return (unsigned)(c - UC('0')) <= 9u; } fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { @@ -83,11 +83,10 @@ read4_to_u32(UC const *chars) { uint32_t val; ::memcpy(&val, chars, sizeof(uint32_t)); #if FASTFLOAT_IS_BIG_ENDIAN == 1 - val = byteswap(val); + val = byteswap_32(val); #endif return val; } - #ifdef FASTFLOAT_SSE2 fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { @@ -169,6 +168,11 @@ is_made_of_eight_digits_fast(uint64_t val) noexcept { 0x8080808080808080)); } +fastfloat_really_inline constexpr bool +is_made_of_four_digits_fast(uint32_t val) noexcept { + return !((((val + 0x46464646) | (val - 0x30303030)) & 0x80808080)); +} + fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t parse_four_digits_unrolled(uint32_t val) noexcept { val -= 0x30303030; @@ -648,77 +652,38 @@ parse_int_string(UC const *p, UC const *pend, T &value, return answer; } - uint32_t digits; if (len >= 4) { - digits = read4_to_u32(p); - } else { - uint32_t b0 = uint32_t(uint8_t(p[0])); - uint32_t b1 = (len > 1) ? uint32_t(uint8_t(p[1])) : 0xFFu; - uint32_t b2 = (len > 2) ? uint32_t(uint8_t(p[2])) : 0xFFu; - digits = b0 | (b1 << 8) | (b2 << 16) | (0xFFu << 24); - } - - uint32_t magic = - ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; - uint32_t nd = (magic == 0) ? 4u : (uint32_t(countr_zero_32(magic)) >> 3); - - if (nd == 0) { - if (has_leading_zeros) { - value = 0; + uint32_t digits = read4_to_u32(p); + if (is_made_of_four_digits_fast(digits)) { + uint32_t v = parse_four_digits_unrolled(digits); + if (len >= 5 && is_integer(p[4])) { + v = v * 10 + uint32_t(p[4] - '0'); + if (len >= 6 && is_integer(p[5])) { + answer.ec = std::errc::result_out_of_range; + const UC *q = p + 5; + while (q != pend && is_integer(*q)) { + q++; + } + answer.ptr = q; + return answer; + } + if (v > 65535) { + answer.ec = std::errc::result_out_of_range; + answer.ptr = p + 5; + return answer; + } + value = uint16_t(v); + answer.ec = std::errc(); + answer.ptr = p + 5; + return answer; + } + // 4 digits + value = uint16_t(v); answer.ec = std::errc(); - answer.ptr = p; - return answer; - } - answer.ec = std::errc::invalid_argument; - answer.ptr = first; - return answer; - } - - if (nd < 4) { - // mask out non-digit bytes and replace with '0' (0x30) - uint32_t mask = 0xFFFFFFFFu >> ((4u - nd) * 8u); - uint32_t padded = (digits & mask) | (~mask & 0x30303030u); - uint32_t v = parse_four_digits_unrolled(padded); - constexpr uint32_t divs[] = {0, 1000, 100, 10}; - value = (uint16_t)(v / divs[nd]); - answer.ec = std::errc(); - answer.ptr = p + nd; - return answer; - } - - uint32_t v = parse_four_digits_unrolled(digits); - - uint32_t d4 = (len > 4) ? uint32_t(p[4] - '0') : 10u; - if (d4 > 9u) { - value = (uint16_t)v; - answer.ec = std::errc(); - answer.ptr = p + 4; - return answer; - } - - if (len > 5) { - uint32_t d5 = uint32_t(p[5]) - uint32_t('0'); - if (d5 <= 9u) { - const UC *q = p + 6; - while (q < pend && uint32_t(*q) - uint32_t('0') <= 9u) - ++q; - answer.ec = std::errc::result_out_of_range; - answer.ptr = q; + answer.ptr = p + 4; return answer; } } - - // overflow check - if (v > 6553u || (v == 6553u && d4 > 5u)) { - answer.ec = std::errc::result_out_of_range; - answer.ptr = p + 5; - return answer; - } - - value = (uint16_t)(v * 10u + d4); - answer.ec = std::errc(); - answer.ptr = p + 5; - return answer; } } From d1af5b18ac78bc76fdcb40ae9dedef803f7ab899 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 00:11:02 +0000 Subject: [PATCH 12/37] Bump the github-actions group across 1 directory with 4 updates Bumps the github-actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/setup-node](https://github.com/actions/setup-node) and [jidicula/clang-format-action](https://github.com/jidicula/clang-format-action). Updates `actions/checkout` from 5 to 6 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v5...v6) Updates `actions/upload-artifact` from 5 to 6 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) Updates `actions/setup-node` from 6.0.0 to 6.1.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/2028fbc5c25fe9cf00d9f06a71cc4710d4507903...395ad3262231945c25e8478fd5baf05154b1d79f) Updates `jidicula/clang-format-action` from 4.15.0 to 4.16.0 - [Release notes](https://github.com/jidicula/clang-format-action/releases) - [Commits](https://github.com/jidicula/clang-format-action/compare/4726374d1aa3c6aecf132e5197e498979588ebc8...6cd220de46c89139a0365edae93eee8eb30ca8fe) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: jidicula/clang-format-action dependency-version: 4.16.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu24.yml | 2 +- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 6 +++--- .github/workflows/lint_and_format_check.yml | 4 ++-- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/risc.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24-cxx20.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 2 +- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 20 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index 9b24bdef..b77fd44f 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml index ca57ff65..db822cb8 100644 --- a/.github/workflows/amalgamate-ubuntu24.yml +++ b/.github/workflows/amalgamate-ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index bd9e1e6c..2d0bdaa5 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -20,7 +20,7 @@ jobs: fuzz-seconds: 300 output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 399f0c9e..e5ddb06e 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@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2 - - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.2.2 + - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v3.6.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # 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 ce6a2af5..164cd225 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -24,10 +24,10 @@ jobs: lint-and-format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.1.7 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.1.7 - name: Run clang-format - uses: jidicula/clang-format-action@4726374d1aa3c6aecf132e5197e498979588ebc8 # v4.15.0 + uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 with: clang-format-version: '17' diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index 7697bb59..d263b6d4 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 4bd814e6..4848f2e0 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 26ef5d58..371cba0a 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index 8bc85588..a8f4d399 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install packages run: | sudo apt-get update -q -y diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 0bc90d98..0799e215 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index f8af4374..3e6df05e 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index 91abf7ce..b7bba1e0 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index 08fe8d73..c51524e1 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index 71543954..c8fb3c11 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24-cxx20.yml b/.github/workflows/ubuntu24-cxx20.yml index 85167601..c705631f 100644 --- a/.github/workflows/ubuntu24-cxx20.yml +++ b/.github/workflows/ubuntu24-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 511c7ce3..1b998099 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index 6769a2a4..f4fa84e4 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 091b1c5b..48f4985e 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index 56b51611..31b3a4b6 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index aecbca8f..93b7a896 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From 64a68590fd3e41826351003ee9b03f53d25f0aa2 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Sun, 18 Jan 2026 19:05:51 -0500 Subject: [PATCH 13/37] Clarify `std::from_chars` conversion method Updated explanation of `std::from_chars` conversion checks. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d19283ff..71a892db 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ int main() { } ``` -Though the C++17 standard has you do a comparison with `std::errc()` to check whether the conversion worked, you can avoid it by casting the result to a `bool` like so: +Prior to C++26, checking for a successful `std::from_chars` conversion requires comparing the `from_chars_result::ec` member to `std::errc()`. As an extension `fast_float::from_chars` supports the improved C++26 API that allows checking the result by converting it to `bool`, like so: ```cpp #include "fast_float/fast_float.h" From 71ab1cce81c126f9cbf34d1b29f75695d131861d Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Mon, 19 Jan 2026 20:36:29 -0500 Subject: [PATCH 14/37] Fix error message to display input instead of result --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71a892db..9bcae052 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ int main() { std::cout << "parsed the number " << result << std::endl; return EXIT_SUCCESS; } - std::cerr << "failed to parse " << result << std::endl; + std::cerr << "failed to parse " << input << std::endl; return EXIT_FAILURE; } ``` From 4fa83ccff44a36d8c8bc1dcf469a0cfe6929224b Mon Sep 17 00:00:00 2001 From: sleepingieght Date: Wed, 21 Jan 2026 19:21:06 +0530 Subject: [PATCH 15/37] fix early return error in fastfloat_strncasecmp --- 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 7aeb2c28..595f43a6 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -290,8 +290,8 @@ fastfloat_strncasecmp3(UC const *actual_mixedcase, if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { return false; } - return true; } + return true; } else { FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1 || sizeof(UC) == 2) { ::memcpy(&val1, actual_mixedcase, 3 * sizeof(UC)); @@ -328,8 +328,8 @@ fastfloat_strncasecmp5(UC const *actual_mixedcase, if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { return false; } - return true; } + return true; } else { FASTFLOAT_IF_CONSTEXPR17(sizeof(UC) == 1) { mask = 0x2020202020202020; @@ -395,8 +395,8 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, if ((actual_mixedcase[i] | 32) != expected_lowercase[i]) { return false; } - return true; } + return true; } else { uint64_t val1{0}, val2{0}; size_t sz{8 / (sizeof(UC))}; From cb299bdeccf428f64127674ce4bca4b00fea732d Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 28 Jan 2026 10:55:48 +0100 Subject: [PATCH 16/37] Clarify behavior for underflow In https://github.com/fastfloat/fast_float/pull/189 the behavior on underflow was changed to better match the standard's recommendations, but the README does not mention underflow explicitly. --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9bcae052..3490a583 100644 --- a/README.md +++ b/README.md @@ -141,9 +141,12 @@ Furthermore, we have the following restrictions: fixed-width floating-point types such as `std::float64_t`, `std::float32_t`, `std::float16_t`, and `std::bfloat16_t`. * We only support the decimal format: we do not support hexadecimal strings. -* For values that are either very large or very small (e.g., `1e9999`), we - represent it using the infinity or negative infinity value and the returned +* For values that are very large positives or negatives (e.g., `1e9999`), we + represent them using a positive or negative infinity and the returned `ec` is set to `std::errc::result_out_of_range`. +* For values that are very close to zero (e.g., `1e-9999`), we represent them + using a positive or negative zero and the returned `ec` is set to + `std::errc::result_out_of_range`. We support Visual Studio, macOS, Linux, freeBSD. We support big and little endian. We support 32-bit and 64-bit systems. From 95295d139802c92a0e3916a54a3b96652a677a94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 00:10:32 +0000 Subject: [PATCH 17/37] Bump the github-actions group with 2 updates Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/checkout` from 5.0.1 to 6.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v5.0.1...v6.0.1) Updates `actions/setup-node` from 6.1.0 to 6.2.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/395ad3262231945c25e8478fd5baf05154b1d79f...6044e13b5dc448c55e2357c09f80417699197238) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 6.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/alpine.yml | 2 +- .github/workflows/amalgamate-ubuntu24.yml | 2 +- .github/workflows/emscripten.yml | 6 +++--- .github/workflows/lint_and_format_check.yml | 2 +- .github/workflows/msys2-clang.yml | 2 +- .github/workflows/msys2.yml | 2 +- .github/workflows/on-release.yml | 2 +- .github/workflows/risc.yml | 2 +- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu22-clang.yml | 2 +- .github/workflows/ubuntu22-gcc12.yml | 2 +- .github/workflows/ubuntu22-sanitize.yml | 2 +- .github/workflows/ubuntu22.yml | 2 +- .github/workflows/ubuntu24-cxx20.yml | 2 +- .github/workflows/ubuntu24.yml | 2 +- .github/workflows/vs17-arm-ci.yml | 2 +- .github/workflows/vs17-ci.yml | 2 +- .github/workflows/vs17-clang-ci.yml | 2 +- .github/workflows/vs17-cxx20.yml | 2 +- 19 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index b77fd44f..7917a051 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -18,7 +18,7 @@ jobs: - riscv64 steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: Install latest Alpine Linux for ${{ matrix.arch }} uses: jirutka/setup-alpine@v1 diff --git a/.github/workflows/amalgamate-ubuntu24.yml b/.github/workflows/amalgamate-ubuntu24.yml index db822cb8..6d2d29e9 100644 --- a/.github/workflows/amalgamate-ubuntu24.yml +++ b/.github/workflows/amalgamate-ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Compile with amalgamation run: | mkdir build && diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index e5ddb06e..789aa66f 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@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.2.2 - - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.2.2 + - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v - name: Checkout - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v3.6.0 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # 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 164cd225..dd30d18e 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@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v4.1.7 + - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.7 - name: Run clang-format uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index d263b6d4..68b36ea1 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -23,7 +23,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index 4848f2e0..ae604c8b 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -29,7 +29,7 @@ jobs: CMAKE_GENERATOR: Ninja steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - uses: msys2/setup-msys2@v2 with: update: true diff --git a/.github/workflows/on-release.yml b/.github/workflows/on-release.yml index 371cba0a..a68df4ed 100644 --- a/.github/workflows/on-release.yml +++ b/.github/workflows/on-release.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Amalgamate fast_float.h run: | diff --git a/.github/workflows/risc.yml b/.github/workflows/risc.yml index a8f4d399..6609cffd 100644 --- a/.github/workflows/risc.yml +++ b/.github/workflows/risc.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Install packages run: | sudo apt-get update -q -y diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 0799e215..db7a03d3 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - uses: uraimo/run-on-arch-action@v3 name: Test id: runcmd diff --git a/.github/workflows/ubuntu22-clang.yml b/.github/workflows/ubuntu22-clang.yml index 3e6df05e..4d7f49fd 100644 --- a/.github/workflows/ubuntu22-clang.yml +++ b/.github/workflows/ubuntu22-clang.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Install clang++-14 run: sudo apt-get install -y clang++-14 - name: Use cmake diff --git a/.github/workflows/ubuntu22-gcc12.yml b/.github/workflows/ubuntu22-gcc12.yml index b7bba1e0..a32033c6 100644 --- a/.github/workflows/ubuntu22-gcc12.yml +++ b/.github/workflows/ubuntu22-gcc12.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22-sanitize.yml b/.github/workflows/ubuntu22-sanitize.yml index c51524e1..b7f96602 100644 --- a/.github/workflows/ubuntu22-sanitize.yml +++ b/.github/workflows/ubuntu22-sanitize.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu22.yml b/.github/workflows/ubuntu22.yml index c8fb3c11..09dac2b5 100644 --- a/.github/workflows/ubuntu22.yml +++ b/.github/workflows/ubuntu22.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24-cxx20.yml b/.github/workflows/ubuntu24-cxx20.yml index c705631f..1d451c98 100644 --- a/.github/workflows/ubuntu24-cxx20.yml +++ b/.github/workflows/ubuntu24-cxx20.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Use cmake run: | mkdir build && diff --git a/.github/workflows/ubuntu24.yml b/.github/workflows/ubuntu24.yml index 1b998099..09c82c8f 100644 --- a/.github/workflows/ubuntu24.yml +++ b/.github/workflows/ubuntu24.yml @@ -6,7 +6,7 @@ jobs: ubuntu-build: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v6.0.2 - name: Use cmake run: | set -xe diff --git a/.github/workflows/vs17-arm-ci.yml b/.github/workflows/vs17-arm-ci.yml index f4fa84e4..9eef0129 100644 --- a/.github/workflows/vs17-arm-ci.yml +++ b/.github/workflows/vs17-arm-ci.yml @@ -14,7 +14,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: ARM64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DCMAKE_CROSSCOMPILING=1 -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-ci.yml b/.github/workflows/vs17-ci.yml index 48f4985e..39a5bd40 100644 --- a/.github/workflows/vs17-ci.yml +++ b/.github/workflows/vs17-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination diff --git a/.github/workflows/vs17-clang-ci.yml b/.github/workflows/vs17-clang-ci.yml index 31b3a4b6..25a54b86 100644 --- a/.github/workflows/vs17-clang-ci.yml +++ b/.github/workflows/vs17-clang-ci.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: Configure run: | cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} -DFASTFLOAT_BENCHMARKS=ON -T ClangCL -DFASTFLOAT_TEST=ON diff --git a/.github/workflows/vs17-cxx20.yml b/.github/workflows/vs17-cxx20.yml index 93b7a896..dda7afc1 100644 --- a/.github/workflows/vs17-cxx20.yml +++ b/.github/workflows/vs17-cxx20.yml @@ -16,7 +16,7 @@ jobs: - {gen: Visual Studio 17 2022, arch: x64, cfg: Debug} steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: configure run: >- cmake -S . -B build -G "${{matrix.gen}}" -A ${{matrix.arch}} From 707fccb44505eb62c3736ec47473f964df883055 Mon Sep 17 00:00:00 2001 From: N'yoma Diamond Date: Mon, 2 Feb 2026 16:44:39 +0000 Subject: [PATCH 18/37] compile-time generator expression fixes overzealous /permissive- compiler option usage --- CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 83953908..b383b7bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,13 +57,7 @@ if(FASTFLOAT_SANITIZE) endif() endif() -include(CheckCXXCompilerFlag) -unset(FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE) -CHECK_CXX_COMPILER_FLAG(/permissive- FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE) - -if(FASTFLOAT_COMPILER_SUPPORTS_PERMISSIVE) - target_compile_options(fast_float INTERFACE /permissive-) -endif() +target_compile_options(fast_float INTERFACE $<$,$,19.10>>:/permissive->) if(FASTFLOAT_INSTALL) include(CMakePackageConfigHelpers) From 01ce95dfe46abccf3264fbccf9f5139ea9016cd2 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 3 Feb 2026 11:27:40 -0500 Subject: [PATCH 19/37] v8.2.3 --- CMakeLists.txt | 2 +- README.md | 6 +++--- include/fast_float/float_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b383b7bd..a75ad6dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) -project(fast_float VERSION 8.2.2 LANGUAGES CXX) +project(fast_float VERSION 8.2.3 LANGUAGES CXX) set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) option(FASTFLOAT_TEST "Enable tests" OFF) diff --git a/README.md b/README.md index 3490a583..c2b2b386 100644 --- a/README.md +++ b/README.md @@ -536,7 +536,7 @@ sufficiently recent version of CMake (3.11 or better at least): FetchContent_Declare( fast_float GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.2.2 + GIT_TAG tags/v8.2.3 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) @@ -552,7 +552,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: CPMAddPackage( NAME fast_float GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.2.2) + GIT_TAG v8.2.3) ``` ## Using as single header @@ -564,7 +564,7 @@ if desired as described in the command line help. You may directly download automatically generated single-header files: - + ## Benchmarking diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 595f43a6..f35920ba 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -18,7 +18,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 2 +#define FASTFLOAT_VERSION_PATCH 3 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) From f43d6711bca415677ef88b9f3604288ffbd895cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=AC=EC=9A=B1?= Date: Wed, 4 Feb 2026 15:27:46 +0900 Subject: [PATCH 20/37] Add additional verification cases for double and float limits --- tests/basictest.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 1a5537bb..5f50ac5a 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1167,6 +1167,9 @@ TEST_CASE("double.general") { // DBL_TRUE_MIN / 2 + 0.0000000000000001e-324 verify("2.4703282292062328e-324", 0x0.0000000000001p-1022); + verify("0.2470328229206232720e-323", 0.0, std::errc::result_out_of_range); + verify("0.2470328229206232721e-323", 0x0.0000000000001p-1022); + verify("-2.2222222222223e-322", -0x1.68p-1069); verify("9007199254740993.0", 0x1p+53); verify("860228122.6654514319E+90", 0x1.92bb20990715fp+328); @@ -1262,8 +1265,14 @@ TEST_CASE("double.general") { verify("4.9406564584124654e-324", 0x0.0000000000001p-1022); verify("2.2250738585072009e-308", 0x0.fffffffffffffp-1022); verify("2.2250738585072014e-308", 0x1p-1022); + verify("0.2225073858507201136e-307", 0x0.fffffffffffffp-1022); + verify("0.2225073858507201137e-307", 0x1p-1022); verify("1.7976931348623157e308", 0x1.fffffffffffffp+1023); verify("1.7976931348623158e308", 0x1.fffffffffffffp+1023); + verify("1.7976931348623158079e308", std::numeric_limits::max()); + verify("1.7976931348623158080e308", + std::numeric_limits::infinity(), + std::errc::result_out_of_range); verify("4503599627370496.5", 4503599627370496.5); verify("4503599627475352.5", 4503599627475352.5); verify("4503599627475353.5", 4503599627475353.5); @@ -1543,6 +1552,8 @@ TEST_CASE("float.general") { verify("0.7006492e-45", 0.f, std::errc::result_out_of_range); // FLT_TRUE_MIN / 2 + 0.0000001e-45 verify("0.7006493e-45", 0x1p-149f); + verify("0.7006492321624085354e-45", 0.f, std::errc::result_out_of_range); + verify("0.7006492321624085355e-45", 0x1p-149f); // max verify("340282346638528859811704183484516925440", 0x1.fffffep+127f); @@ -1553,6 +1564,10 @@ TEST_CASE("float.general") { // that rounds to FLT_MAX verify("340282356779733661637539395458142568447", std::numeric_limits::max()); + verify("0.3402823567797336616e39", std::numeric_limits::max()); + verify("0.3402823567797336617e39", + std::numeric_limits::infinity(), + std::errc::result_out_of_range); verify("-1e-999", -0.0f, std::errc::result_out_of_range); verify("1." @@ -1563,6 +1578,8 @@ TEST_CASE("float.general") { "175494140627517859246175898662808184331245864732796240031385942718174" "6759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f); + verify("1.1754942807573642917e-38", 0x1.fffff8p-127f); + verify("1.1754942807573642918e-38", std::numeric_limits::min()); verify_runtime( append_zeros("1." "17549414062751785924617589866280818433124586473279624003138" From 3e2b5d3dc39aed83f0492001f83e793ecfb71270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=AC=EC=9A=B1?= Date: Wed, 4 Feb 2026 15:36:31 +0900 Subject: [PATCH 21/37] refactor verification calls for double and float limits --- tests/basictest.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/basictest.cpp b/tests/basictest.cpp index 5f50ac5a..dba36e8a 100644 --- a/tests/basictest.cpp +++ b/tests/basictest.cpp @@ -1270,9 +1270,8 @@ TEST_CASE("double.general") { verify("1.7976931348623157e308", 0x1.fffffffffffffp+1023); verify("1.7976931348623158e308", 0x1.fffffffffffffp+1023); verify("1.7976931348623158079e308", std::numeric_limits::max()); - verify("1.7976931348623158080e308", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); + verify("1.7976931348623158080e308", std::numeric_limits::infinity(), + std::errc::result_out_of_range); verify("4503599627370496.5", 4503599627370496.5); verify("4503599627475352.5", 4503599627475352.5); verify("4503599627475353.5", 4503599627475353.5); @@ -1565,9 +1564,8 @@ TEST_CASE("float.general") { verify("340282356779733661637539395458142568447", std::numeric_limits::max()); verify("0.3402823567797336616e39", std::numeric_limits::max()); - verify("0.3402823567797336617e39", - std::numeric_limits::infinity(), - std::errc::result_out_of_range); + verify("0.3402823567797336617e39", std::numeric_limits::infinity(), + std::errc::result_out_of_range); verify("-1e-999", -0.0f, std::errc::result_out_of_range); verify("1." @@ -1578,7 +1576,7 @@ TEST_CASE("float.general") { "175494140627517859246175898662808184331245864732796240031385942718174" "6759860647699724722770042717456817626953125e-38", 0x1.fffff8p-127f); - verify("1.1754942807573642917e-38", 0x1.fffff8p-127f); + verify("1.1754942807573642917e-38", 0x1.fffffcp-127f); verify("1.1754942807573642918e-38", std::numeric_limits::min()); verify_runtime( append_zeros("1." From a110aa1392d37c90440a0bb2e213ea171ed81780 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 4 Feb 2026 12:13:25 -0500 Subject: [PATCH 22/37] adding bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..8a5ba71c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Ideally, you should provide a reproducible test case. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. + +**Note:** Bug reports should come with a test case or, at least, an analysis. + +**Automated tool policy**: If you use an automated tool (e.g., static analysis, +LLM, etc.), you need to demonstrate an understanding of the issue you are raising. Usually, a bug is demonstrated by a test case. Do not copy-paste what a tool is telling you. \ No newline at end of file From 3c6a64b87d3491659a7a31520d3c1f3733f350bf Mon Sep 17 00:00:00 2001 From: Xisco Fauli Date: Fri, 6 Feb 2026 11:28:34 +0100 Subject: [PATCH 23/37] fix warning C4702: unreachable code --- include/fast_float/float_common.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index f35920ba..6bb4c591 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -313,8 +313,6 @@ fastfloat_strncasecmp3(UC const *actual_mixedcase, return false; } } - - return true; } template @@ -369,8 +367,6 @@ fastfloat_strncasecmp5(UC const *actual_mixedcase, return false; } } - - return true; } // Compares two ASCII strings in a case insensitive manner. From 8514abe2e281eea16369981623f658f8f032fc5e Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 5 Mar 2026 21:59:09 -0500 Subject: [PATCH 24/37] Update README with note for C users Added a note for C users to consider ffc.h for high-performance parsing. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c2b2b386..e63db6be 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ [![Ubuntu 22.04 CI (GCC 11)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml/badge.svg)](https://github.com/fastfloat/fast_float/actions/workflows/ubuntu22.yml) +*Note: This library is for C++ users. C programmers should consider [ffc.h](https://github.com/kolemannix/ffc.h). It is a high-performance port of fast_float to C.* + + The fast_float library provides fast header-only implementations for the C++ from_chars functions for `float` and `double` types as well as integer types. These functions convert ASCII strings representing decimal values (e.g., @@ -10,6 +13,7 @@ These functions convert ASCII strings representing decimal values (e.g., even). In our experience, these `fast_float` functions many times faster than comparable number-parsing functions from existing C++ standard libraries. + Specifically, `fast_float` provides the following two functions to parse floating-point numbers with a C++17-like syntax (the library itself only requires C++11): From a18b614b0ec591e30d74d26e07162b737236fdce Mon Sep 17 00:00:00 2001 From: Koleman Nix Date: Sat, 7 Mar 2026 14:20:13 -0500 Subject: [PATCH 25/37] Mention C under other languages --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e63db6be..c90a632c 100644 --- a/README.md +++ b/README.md @@ -492,6 +492,8 @@ Packages [Jackson](https://github.com/FasterXML/jackson-core). * [There is a C# port of the fast_float library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`. +* There is a [plain C port](https://github.com/kolemannix/ffc.h) (c99) of the fast_float library +called ffc.h ## How fast is it? From b83fdd79cee7db392e54e9913918905bcbedb5f0 Mon Sep 17 00:00:00 2001 From: Koleman Nix Date: Sat, 7 Mar 2026 14:23:07 -0500 Subject: [PATCH 26/37] consistency --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index c90a632c..cc321622 100644 --- a/README.md +++ b/README.md @@ -492,8 +492,7 @@ Packages [Jackson](https://github.com/FasterXML/jackson-core). * [There is a C# port of the fast_float library](https://github.com/CarlVerret/csFastFloat) called `csFastFloat`. -* There is a [plain C port](https://github.com/kolemannix/ffc.h) (c99) of the fast_float library -called ffc.h +* [There is a plain C port of the fast_float library](https://github.com/kolemannix/ffc.h) called ffc.h ## How fast is it? From 2606bcdf2f0e69dba3c246ff94b32eb0f6f6077e Mon Sep 17 00:00:00 2001 From: Koleman Nix Date: Sat, 7 Mar 2026 15:36:09 -0500 Subject: [PATCH 27/37] A few inlines --- include/fast_float/parse_number.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index c01bb15a..008c2463 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -251,7 +251,7 @@ clinger_fast_path_impl(uint64_t mantissa, int64_t exponent, bool is_negative, * parsing options or other parsing custom function implemented by user. */ template -FASTFLOAT_CONSTEXPR20 from_chars_result_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { static_assert(is_supported_float_type::value, "only some floating-point types are supported"); @@ -290,7 +290,7 @@ from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { } template -FASTFLOAT_CONSTEXPR20 from_chars_result_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_float_advanced(UC const *first, UC const *last, T &value, parse_options_t options) noexcept { @@ -456,6 +456,7 @@ template struct from_chars_advanced_caller { template <> struct from_chars_advanced_caller<1> { template + fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, parse_options_t options) noexcept { @@ -465,7 +466,7 @@ template <> struct from_chars_advanced_caller<1> { template <> struct from_chars_advanced_caller<2> { template - FASTFLOAT_CONSTEXPR20 static from_chars_result_t + fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, parse_options_t options) noexcept { return from_chars_int_advanced(first, last, value, options); @@ -473,7 +474,7 @@ template <> struct from_chars_advanced_caller<2> { }; template -FASTFLOAT_CONSTEXPR20 from_chars_result_t +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t from_chars_advanced(UC const *first, UC const *last, T &value, parse_options_t options) noexcept { return from_chars_advanced_caller< From 50c19fad17ec559f8736813b8fa18545f3fb856f Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 10 Mar 2026 11:53:45 -0400 Subject: [PATCH 28/37] init --- tests/long_test.cpp | 2 +- tests/string_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/long_test.cpp b/tests/long_test.cpp index 40539ef0..feab4d02 100644 --- a/tests/long_test.cpp +++ b/tests/long_test.cpp @@ -22,7 +22,7 @@ template bool test() { char const *begin = input.data(); char const *end = input.data() + input.size(); for (size_t i = 0; i < answers.size(); i++) { - T result_value; + T result_value = 0; while ((begin < end) && (std::isspace(*begin))) { begin++; } diff --git a/tests/string_test.cpp b/tests/string_test.cpp index 68828ac3..69d2a31d 100644 --- a/tests/string_test.cpp +++ b/tests/string_test.cpp @@ -98,7 +98,7 @@ template bool test() { char const *begin = input.data(); char const *end = input.data() + input.size(); for (size_t i = 0; i < answers.size(); i++) { - T result_value; + T result_value = 0; while ((begin < end) && (std::isspace(*begin))) { begin++; } From eb9ab42c0aa86d3cc41871ba7306527d95077b3b Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 10 Mar 2026 12:10:12 -0400 Subject: [PATCH 29/37] 8.2.4 --- CMakeLists.txt | 2 +- README.md | 6 +++--- include/fast_float/float_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a75ad6dd..41951d3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) -project(fast_float VERSION 8.2.3 LANGUAGES CXX) +project(fast_float VERSION 8.2.4 LANGUAGES CXX) set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) option(FASTFLOAT_TEST "Enable tests" OFF) diff --git a/README.md b/README.md index cc321622..9484ade1 100644 --- a/README.md +++ b/README.md @@ -541,7 +541,7 @@ sufficiently recent version of CMake (3.11 or better at least): FetchContent_Declare( fast_float GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.2.3 + GIT_TAG tags/v8.2.4 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) @@ -557,7 +557,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: CPMAddPackage( NAME fast_float GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.2.3) + GIT_TAG v8.2.4) ``` ## Using as single header @@ -569,7 +569,7 @@ if desired as described in the command line help. You may directly download automatically generated single-header files: - + ## Benchmarking diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 6bb4c591..bed3efd9 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -18,7 +18,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 3 +#define FASTFLOAT_VERSION_PATCH 4 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) From 18e55e48a8d0c845c9262eaf1469d3443c228f57 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 10 Mar 2026 17:06:04 -0400 Subject: [PATCH 30/37] lint --- include/fast_float/parse_number.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 008c2463..ff9c53d0 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -155,7 +155,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; + float val = 0.0f; auto ret = from_chars_advanced(first, last, val, options); value = val; return ret; @@ -172,7 +172,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; + double val = 0.0; auto ret = from_chars_advanced(first, last, val, options); value = val; return ret; @@ -456,8 +456,7 @@ template struct from_chars_advanced_caller { template <> struct from_chars_advanced_caller<1> { template - fastfloat_really_inline - FASTFLOAT_CONSTEXPR20 static from_chars_result_t + fastfloat_really_inline FASTFLOAT_CONSTEXPR20 static from_chars_result_t call(UC const *first, UC const *last, T &value, parse_options_t options) noexcept { return from_chars_float_advanced(first, last, value, options); From 419695eba6f5280f0d25a3d7e52b8bb7583b78c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 00:08:44 +0000 Subject: [PATCH 31/37] Bump the github-actions group across 1 directory with 3 updates Bumps the github-actions group with 3 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/setup-node](https://github.com/actions/setup-node) and [jidicula/clang-format-action](https://github.com/jidicula/clang-format-action). Updates `actions/upload-artifact` from 6 to 7 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) Updates `actions/setup-node` from 6.2.0 to 6.3.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/6044e13b5dc448c55e2357c09f80417699197238...53b83947a5a98c8d113130e565377fae1a50d02f) Updates `jidicula/clang-format-action` from 4.16.0 to 4.17.0 - [Release notes](https://github.com/jidicula/clang-format-action/releases) - [Commits](https://github.com/jidicula/clang-format-action/compare/6cd220de46c89139a0365edae93eee8eb30ca8fe...3a18028048f01a66653b4e3bf8d968d2e7e2cb8b) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: jidicula/clang-format-action dependency-version: 4.17.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/cifuzz.yml | 2 +- .github/workflows/emscripten.yml | 2 +- .github/workflows/lint_and_format_check.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 2d0bdaa5..704d5f16 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -20,7 +20,7 @@ jobs: fuzz-seconds: 300 output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/emscripten.yml b/.github/workflows/emscripten.yml index 789aa66f..d991a2c6 100644 --- a/.github/workflows/emscripten.yml +++ b/.github/workflows/emscripten.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.2.2 - - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14 - name: Verify run: emcc -v diff --git a/.github/workflows/lint_and_format_check.yml b/.github/workflows/lint_and_format_check.yml index dd30d18e..df040cea 100644 --- a/.github/workflows/lint_and_format_check.yml +++ b/.github/workflows/lint_and_format_check.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4.1.7 - name: Run clang-format - uses: jidicula/clang-format-action@6cd220de46c89139a0365edae93eee8eb30ca8fe # v4.16.0 + uses: jidicula/clang-format-action@3a18028048f01a66653b4e3bf8d968d2e7e2cb8b # v4.17.0 with: clang-format-version: '17' From 9817d5ddaa924b380752e05ff0d78b65463983e3 Mon Sep 17 00:00:00 2001 From: Carbo Date: Fri, 27 Mar 2026 14:39:16 +0900 Subject: [PATCH 32/37] Fix Bazel build with bzlmod by loading cc_library rule With bzlmod, native rules like cc_library are no longer implicitly available and must be explicitly loaded from rules_cc. Add the rules_cc dependency to MODULE.bazel and the corresponding load statement to BUILD.bazel. Co-Authored-By: Claude Opus 4.6 (1M context) --- BUILD.bazel | 2 ++ MODULE.bazel | 2 ++ 2 files changed, 4 insertions(+) diff --git a/BUILD.bazel b/BUILD.bazel index fc784a3b..b08e9090 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,3 +1,5 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") + cc_library( name = "fast_float", hdrs = glob(["include/fast_float/*.h"]), diff --git a/MODULE.bazel b/MODULE.bazel index 6704680e..e34ea3b1 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -7,3 +7,5 @@ module( ) bazel_dep(name = "doctest", version = "2.4.11", dev_dependency = True) + +bazel_dep(name = "rules_cc", version = "0.2.17") From 2027a39ba0418d0c54dcbe29ae53a7e7f1b498ff Mon Sep 17 00:00:00 2001 From: Carbo Date: Fri, 27 Mar 2026 14:42:55 +0900 Subject: [PATCH 33/37] Update MODULE.bazel version to 8.2.4 Co-Authored-By: Claude Opus 4.6 (1M context) --- MODULE.bazel | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index e34ea3b1..9f63ac4e 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -2,8 +2,8 @@ module( name = "fast_float", - version = "6.1.6", - compatibility_level = 6, + version = "8.2.4", + compatibility_level = 8, ) bazel_dep(name = "doctest", version = "2.4.11", dev_dependency = True) From b063de82c739d2b93a209cc5fa3dceee8881b538 Mon Sep 17 00:00:00 2001 From: Michael Lippautz Date: Thu, 16 Apr 2026 09:51:58 +0200 Subject: [PATCH 34/37] Include in float_common.h `fastfloat_strncasecmp` relies on `std::min`. --- include/fast_float/float_common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index bed3efd9..f17b5e9b 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1,6 +1,7 @@ #ifndef FASTFLOAT_FLOAT_COMMON_H #define FASTFLOAT_FLOAT_COMMON_H +#include #include #include #include From 001c04cc8aea998bcbf380b35ca0369e0cd23e60 Mon Sep 17 00:00:00 2001 From: Michael Lippautz Date: Thu, 16 Apr 2026 17:17:19 +0000 Subject: [PATCH 35/37] Remove include and replace std::min with ternary operators Replaces uses of std::min with ternary operators in ascii_number.h, digit_comparison.h, and float_common.h to remove the dependency on the header in those files. --- include/fast_float/ascii_number.h | 2 +- include/fast_float/digit_comparison.h | 3 +-- include/fast_float/float_common.h | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 85435373..12c2fddc 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -594,7 +594,7 @@ parse_int_string(UC const *p, UC const *pend, T &value, ((digits + 0x46464646u) | (digits - 0x30303030u)) & 0x80808080u; uint32_t tz = (uint32_t)countr_zero_32(magic); // 7, 15, 23, 31, or 32 uint32_t nd = (tz == 32) ? 4 : (tz >> 3); - nd = (uint32_t)std::min((size_t)nd, len); + nd = (uint32_t)(nd < len ? nd : len); if (nd == 0) { if (has_leading_zeros) { value = 0; diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 03e70dcc..c2c83b0c 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -1,7 +1,6 @@ #ifndef FASTFLOAT_DIGIT_COMPARISON_H #define FASTFLOAT_DIGIT_COMPARISON_H -#include #include #include #include @@ -109,7 +108,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, if (-am.power2 >= mantissa_shift) { // have a denormal float int32_t shift = -am.power2 + 1; - cb(am, std::min(shift, 64)); + cb(am, (shift < 64 ? 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())) diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index f17b5e9b..69905882 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1,7 +1,6 @@ #ifndef FASTFLOAT_FLOAT_COMMON_H #define FASTFLOAT_FLOAT_COMMON_H -#include #include #include #include @@ -399,7 +398,7 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, size_t sz{8 / (sizeof(UC))}; for (size_t i = 0; i < length; i += sz) { val1 = val2 = 0; - sz = std::min(sz, length - i); + sz = sz < (length - i) ? sz : length - i; ::memcpy(&val1, actual_mixedcase + i, sz * sizeof(UC)); ::memcpy(&val2, expected_lowercase + i, sz * sizeof(UC)); val1 |= mask; From b2b1e203babf30b38b658d612aed63a2ecdbde92 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 16 Apr 2026 14:38:27 -0400 Subject: [PATCH 36/37] removing msys 32-bit --- .github/workflows/msys2-clang.yml | 3 --- .github/workflows/msys2.yml | 6 ------ 2 files changed, 9 deletions(-) diff --git a/.github/workflows/msys2-clang.yml b/.github/workflows/msys2-clang.yml index 68b36ea1..c6f8747d 100644 --- a/.github/workflows/msys2-clang.yml +++ b/.github/workflows/msys2-clang.yml @@ -16,9 +16,6 @@ jobs: - msystem: "MINGW64" install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang type: Release - - msystem: "MINGW32" - install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang - type: Release env: CMAKE_GENERATOR: Ninja diff --git a/.github/workflows/msys2.yml b/.github/workflows/msys2.yml index ae604c8b..62749135 100644 --- a/.github/workflows/msys2.yml +++ b/.github/workflows/msys2.yml @@ -16,15 +16,9 @@ jobs: - msystem: "MINGW64" install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc type: Release - - msystem: "MINGW32" - install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc - type: Release - msystem: "MINGW64" install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc type: Debug - - msystem: "MINGW32" - install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc - type: Debug env: CMAKE_GENERATOR: Ninja From 05087a303dad9c98768b33c829d398223a649bc6 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Thu, 16 Apr 2026 14:39:03 -0400 Subject: [PATCH 37/37] 8.2.5 --- CMakeLists.txt | 2 +- README.md | 6 +++--- include/fast_float/float_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41951d3c..e7cedc2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) -project(fast_float VERSION 8.2.4 LANGUAGES CXX) +project(fast_float VERSION 8.2.5 LANGUAGES CXX) set(FASTFLOAT_CXX_STANDARD 11 CACHE STRING "the C++ standard to use for fastfloat") set(CMAKE_CXX_STANDARD ${FASTFLOAT_CXX_STANDARD}) option(FASTFLOAT_TEST "Enable tests" OFF) diff --git a/README.md b/README.md index 9484ade1..be0f1f56 100644 --- a/README.md +++ b/README.md @@ -541,7 +541,7 @@ sufficiently recent version of CMake (3.11 or better at least): FetchContent_Declare( fast_float GIT_REPOSITORY https://github.com/fastfloat/fast_float.git - GIT_TAG tags/v8.2.4 + GIT_TAG tags/v8.2.5 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) @@ -557,7 +557,7 @@ You may also use [CPM](https://github.com/cpm-cmake/CPM.cmake), like so: CPMAddPackage( NAME fast_float GITHUB_REPOSITORY "fastfloat/fast_float" - GIT_TAG v8.2.4) + GIT_TAG v8.2.5) ``` ## Using as single header @@ -569,7 +569,7 @@ if desired as described in the command line help. You may directly download automatically generated single-header files: - + ## Benchmarking diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 69905882..403eea1f 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -18,7 +18,7 @@ #define FASTFLOAT_VERSION_MAJOR 8 #define FASTFLOAT_VERSION_MINOR 2 -#define FASTFLOAT_VERSION_PATCH 4 +#define FASTFLOAT_VERSION_PATCH 5 #define FASTFLOAT_STRINGIZE_IMPL(x) #x #define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x)