mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 21:20:30 +00:00
Under a locale whose decimal point is longer than one byte (e.g. U+066B in fa_IR.UTF-8 or ar_EG.UTF-8), every float that reached the strtod fallback was truncated at the decimal point: "3.14159265358979323846" became 3.0, and "1.5e400" became 1.0 instead of throwing. With libc++ and in C++11/14, that fallback was taken for most floats. The lexer now converts floats in this order: 1. std::from_chars, now also for float and double with libc++ 20 or later, which does not define __cpp_lib_to_chars (on Apple platforms only if the deployment target provides it); 2. Clinger's fast path (double only); 3. strtof_l/strtod_l/strtold_l with a "C" locale created once, on glibc, Apple platforms, and MSVC; 4. strtof/strtod/strtold with the decimal point of the current locale, which now puts a multi-byte decimal point into a copy of the token. If std::from_chars reports a value out of range, the result is derived from the token (+-infinity or +-0) instead of calling strtod, because implementations disagree on the stored value (P4168). Values that may be subnormal are left to the next step, because libstdc++ before GCC 13 reports some of them as out of range. The conversion helpers moved from the lexer to number_parse.hpp, so the last-resort path can be tested directly. Fixes #5660. Signed-off-by: Niels Lohmann <mail@nlohmann.me>