Prefer strtod_l over libc++'s std::from_chars

libc++'s std::from_chars for float and double is 1.3x to 2.8x slower
per number than Apple's strtod_l, and it was tried before Clinger's
fast path. With Apple clang in C++17 mode, parsing random doubles took
1.75x as long as on develop, short numbers such as 123.45 1.3x, and
mesh.json 1.2x.

Use libc++'s std::from_chars only where the C library has no strtod_l.
On Apple platforms, floats are now converted by Clinger's fast path and
strtod_l, which is 0.90x to 1.01x the time of develop.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-30 10:12:50 +02:00
parent 436bfb1358
commit 42e3489abd
3 changed files with 87 additions and 83 deletions
@@ -77,11 +77,11 @@ otherwise, it uses unsigned integer storage.
[`std::strtod`](https://en.cppreference.com/w/cpp/string/byte/strtof), respectively.
- The result of converting floating-point numbers does not depend on the C locale (`LC_NUMERIC`). They are
converted with [`std::from_chars`](https://en.cppreference.com/w/cpp/utility/from_chars) where the standard
library implements it for the number type (including libc++ 20 or later for `#!c float` and `#!c double`),
otherwise with `strtod_l` and the "C" locale where the C library provides it (glibc, macOS, MSVC), and otherwise
with `std::strtod` and the decimal point of the current locale. Before version 3.13.0, the last way was used much
more often, and a locale whose decimal point is longer than one byte (e.g., `fa_IR.UTF-8`) truncated numbers at
the decimal point.
library implements it for the number type (with libc++ 20 or later, only for `#!c float` and `#!c double`, and
only where `strtod_l` is unavailable, because that is faster), otherwise with `strtod_l` and the "C" locale where
the C library provides it (glibc, macOS, MSVC), and otherwise with `std::strtod` and the decimal point of the
current locale. Before version 3.13.0, the last way was used much more often, and a locale whose decimal point
is longer than one byte (e.g., `fa_IR.UTF-8`) truncated numbers at the decimal point.
!!! example "Examples"