From df5db2cfbf8765029e5728fa8ca68317723e20a1 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 24 Feb 2026 10:55:53 -0500 Subject: [PATCH 1/5] adding C interface without dep to C++ standard lib --- CMakeLists.txt | 4 +++- include/fast_float/fast_float_strtod.h | 32 ++++++++++++++++++++++++++ src/CMakeLists.txt | 14 +++++++++++ src/fast_float_strtod.cpp | 24 +++++++++++++++++++ tests/CMakeLists.txt | 7 ++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 include/fast_float/fast_float_strtod.h create mode 100644 src/CMakeLists.txt create mode 100644 src/fast_float_strtod.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a75ad6dd..fa5f2a81 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.3 LANGUAGES CXX C) 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) @@ -32,6 +32,8 @@ endif() add_library(fast_float INTERFACE) +add_subdirectory(src) + option(FASTFLOAT_BENCHMARKS "Enable benchmarks" OFF) if(FASTFLOAT_BENCHMARKS) diff --git a/include/fast_float/fast_float_strtod.h b/include/fast_float/fast_float_strtod.h new file mode 100644 index 00000000..6411f768 --- /dev/null +++ b/include/fast_float/fast_float_strtod.h @@ -0,0 +1,32 @@ +#ifndef __FAST_FLOAT_STRTOD_H__ +#define __FAST_FLOAT_STRTOD_H__ + +#if defined(__cplusplus) +extern "C" +{ +#endif +/** + * @brief Convert a string to a double using the fast_float library. This is + * a C-compatible wrapper around the fast_float parsing functionality, designed to + * mimic the behavior of the standard strtod function. + * + * This function parses the initial portion of the null-terminated string `nptr` + * and converts it to a `double`, similar to the standard `strtod` function but + * utilizing the high-performance fast_float library for parsing. + * + * On successful conversion, the result is returned. If parsing fails, errno is + * set to EINVAL and 0.0 is returned. + * + * @param nptr Pointer to the null-terminated string to be parsed. + * @param endptr If not NULL, a pointer to store the address of the first + * character after the parsed number. If parsing fails, it points + * to the beginning of the string. + * @return The converted double value on success, or 0.0 on failure. + */ + double fast_float_strtod(const char *in, char **out); + +#if defined(__cplusplus) +} +#endif + +#endif /* __FAST_FLOAT_STRTOD_H__ */ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..0d1360b9 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(fast_float_strtod STATIC fast_float_strtod.cpp) +target_link_libraries(fast_float_strtod PRIVATE fast_float) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_link_options(fast_float_strtod PRIVATE -nostdlib++) +endif() + +add_library(FastFloat::fast_float_strtod ALIAS fast_float_strtod) +target_include_directories( + fast_float_strtod + INTERFACE + $ + $ +) \ No newline at end of file diff --git a/src/fast_float_strtod.cpp b/src/fast_float_strtod.cpp new file mode 100644 index 00000000..cce11769 --- /dev/null +++ b/src/fast_float_strtod.cpp @@ -0,0 +1,24 @@ +#include "fast_float/fast_float_strtod.h" +#include "fast_float/fast_float.h" +#include +#include +#include + +extern "C" double fast_float_strtod(const char *nptr, char **endptr) { + double result = 0.0; + + // Parse the string using fast_float's from_chars function + auto parse_result = fast_float::from_chars(nptr, nptr + strlen(nptr), result); + + // Check if parsing encountered an error + if (parse_result.ec != std::errc{}) { + errno = EINVAL; + } + + // Update endptr if provided + if (endptr != nullptr) { + *endptr = const_cast(parse_result.ptr); + } + + return result; +} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a053581c..1c86c5d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -108,3 +108,10 @@ endif(FASTFLOAT_EXHAUSTIVE) add_subdirectory(build_tests) add_subdirectory(bloat_analysis) + +add_executable(strtod_test strtod_test.c) +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_link_options(strtod_test PUBLIC -nostdlib++) +endif() +target_link_libraries(strtod_test PUBLIC fast_float_strtod) +add_test(NAME strtod_test COMMAND strtod_test) From 6eb3dcdcd3391ecefdc0d6a7c8570ee123ecb831 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 24 Feb 2026 10:56:35 -0500 Subject: [PATCH 2/5] lint --- include/fast_float/fast_float_strtod.h | 9 ++++----- src/fast_float_strtod.cpp | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/fast_float/fast_float_strtod.h b/include/fast_float/fast_float_strtod.h index 6411f768..bba5c811 100644 --- a/include/fast_float/fast_float_strtod.h +++ b/include/fast_float/fast_float_strtod.h @@ -2,13 +2,12 @@ #define __FAST_FLOAT_STRTOD_H__ #if defined(__cplusplus) -extern "C" -{ +extern "C" { #endif /** * @brief Convert a string to a double using the fast_float library. This is - * a C-compatible wrapper around the fast_float parsing functionality, designed to - * mimic the behavior of the standard strtod function. + * a C-compatible wrapper around the fast_float parsing functionality, designed + * to mimic the behavior of the standard strtod function. * * This function parses the initial portion of the null-terminated string `nptr` * and converts it to a `double`, similar to the standard `strtod` function but @@ -23,7 +22,7 @@ extern "C" * to the beginning of the string. * @return The converted double value on success, or 0.0 on failure. */ - double fast_float_strtod(const char *in, char **out); +double fast_float_strtod(const char *in, char **out); #if defined(__cplusplus) } diff --git a/src/fast_float_strtod.cpp b/src/fast_float_strtod.cpp index cce11769..c8dbb65b 100644 --- a/src/fast_float_strtod.cpp +++ b/src/fast_float_strtod.cpp @@ -5,20 +5,20 @@ #include extern "C" double fast_float_strtod(const char *nptr, char **endptr) { - double result = 0.0; + double result = 0.0; - // Parse the string using fast_float's from_chars function - auto parse_result = fast_float::from_chars(nptr, nptr + strlen(nptr), result); + // Parse the string using fast_float's from_chars function + auto parse_result = fast_float::from_chars(nptr, nptr + strlen(nptr), result); - // Check if parsing encountered an error - if (parse_result.ec != std::errc{}) { - errno = EINVAL; - } + // Check if parsing encountered an error + if (parse_result.ec != std::errc{}) { + errno = EINVAL; + } - // Update endptr if provided - if (endptr != nullptr) { - *endptr = const_cast(parse_result.ptr); - } + // Update endptr if provided + if (endptr != nullptr) { + *endptr = const_cast(parse_result.ptr); + } - return result; + return result; } \ No newline at end of file From ec664092ebd4b49437ef6c53957819a1150c0730 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 24 Feb 2026 10:57:59 -0500 Subject: [PATCH 3/5] adding tests/strtod_test.c --- tests/strtod_test.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/strtod_test.c diff --git a/tests/strtod_test.c b/tests/strtod_test.c new file mode 100644 index 00000000..bcb00041 --- /dev/null +++ b/tests/strtod_test.c @@ -0,0 +1,28 @@ +#include "fast_float/fast_float_strtod.h" +#include +#include +#include + +int main() { + // Test successful conversion + const char *str1 = "3.14159"; + char *end1; + errno = 0; + double d1 = fast_float_strtod(str1, &end1); + printf("Input: %s\n", str1); + printf("Converted: %f\n", d1); + printf("End pointer: %s\n", end1); + printf("errno: %d\n", errno); + + // Test invalid input + const char *str2 = "invalid"; + char *end2; + errno = 0; + double d2 = fast_float_strtod(str2, &end2); + printf("\nInput: %s\n", str2); + printf("Converted: %f\n", d2); + printf("End pointer: %s\n", end2); + printf("errno: %d\n", errno); + + return 0; +} \ No newline at end of file From c99403b8af0e38de70a9da690ef5e2c73c5657b7 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 24 Feb 2026 11:56:10 -0500 Subject: [PATCH 4/5] lint --- include/fast_float/fast_float_strtod.h | 6 ++-- src/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 2 +- tests/strtod_test.c | 38 +++++++++++++------------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/fast_float/fast_float_strtod.h b/include/fast_float/fast_float_strtod.h index bba5c811..066a5013 100644 --- a/include/fast_float/fast_float_strtod.h +++ b/include/fast_float/fast_float_strtod.h @@ -1,5 +1,5 @@ -#ifndef __FAST_FLOAT_STRTOD_H__ -#define __FAST_FLOAT_STRTOD_H__ +#ifndef FAST_FLOAT_STRTOD_H__ +#define FAST_FLOAT_STRTOD_H__ #if defined(__cplusplus) extern "C" { @@ -28,4 +28,4 @@ double fast_float_strtod(const char *in, char **out); } #endif -#endif /* __FAST_FLOAT_STRTOD_H__ */ \ No newline at end of file +#endif /* FAST_FLOAT_STRTOD_H__ */ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0d1360b9..5b491183 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(fast_float_strtod STATIC fast_float_strtod.cpp) target_link_libraries(fast_float_strtod PRIVATE fast_float) -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU" AND NOT WIN32) target_link_options(fast_float_strtod PRIVATE -nostdlib++) endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1c86c5d2..eea2b2d0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -110,7 +110,7 @@ add_subdirectory(build_tests) add_subdirectory(bloat_analysis) add_executable(strtod_test strtod_test.c) -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU" AND NOT WIN32) target_link_options(strtod_test PUBLIC -nostdlib++) endif() target_link_libraries(strtod_test PUBLIC fast_float_strtod) diff --git a/tests/strtod_test.c b/tests/strtod_test.c index bcb00041..e552c691 100644 --- a/tests/strtod_test.c +++ b/tests/strtod_test.c @@ -4,25 +4,25 @@ #include int main() { - // Test successful conversion - const char *str1 = "3.14159"; - char *end1; - errno = 0; - double d1 = fast_float_strtod(str1, &end1); - printf("Input: %s\n", str1); - printf("Converted: %f\n", d1); - printf("End pointer: %s\n", end1); - printf("errno: %d\n", errno); + // Test successful conversion + const char *str1 = "3.14159"; + char *end1; + errno = 0; + double d1 = fast_float_strtod(str1, &end1); + printf("Input: %s\n", str1); + printf("Converted: %f\n", d1); + printf("End pointer: %s\n", end1); + printf("errno: %d\n", errno); - // Test invalid input - const char *str2 = "invalid"; - char *end2; - errno = 0; - double d2 = fast_float_strtod(str2, &end2); - printf("\nInput: %s\n", str2); - printf("Converted: %f\n", d2); - printf("End pointer: %s\n", end2); - printf("errno: %d\n", errno); + // Test invalid input + const char *str2 = "invalid"; + char *end2; + errno = 0; + double d2 = fast_float_strtod(str2, &end2); + printf("\nInput: %s\n", str2); + printf("Converted: %f\n", d2); + printf("End pointer: %s\n", end2); + printf("errno: %d\n", errno); - return 0; + return 0; } \ No newline at end of file From e22894002d1d5038b6a86087e4cdfcf99f6d6e4c Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 24 Feb 2026 16:24:18 -0500 Subject: [PATCH 5/5] saving. --- src/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b491183..dcb7ddf8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(fast_float_strtod STATIC fast_float_strtod.cpp) target_link_libraries(fast_float_strtod PRIVATE fast_float) -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU" AND NOT WIN32) +if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT WIN32) OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "13" AND NOT WIN32)) target_link_options(fast_float_strtod PRIVATE -nostdlib++) endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eea2b2d0..4d6dfdf7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -110,7 +110,7 @@ add_subdirectory(build_tests) add_subdirectory(bloat_analysis) add_executable(strtod_test strtod_test.c) -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU" AND NOT WIN32) +if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT WIN32) OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "13" AND NOT WIN32)) target_link_options(strtod_test PUBLIC -nostdlib++) endif() target_link_libraries(strtod_test PUBLIC fast_float_strtod)