diff --git a/include/nlohmann/detail/conversions/from_chars.hpp b/include/nlohmann/detail/conversions/from_chars.hpp index 728c58908..46bd63a70 100644 --- a/include/nlohmann/detail/conversions/from_chars.hpp +++ b/include/nlohmann/detail/conversions/from_chars.hpp @@ -190,6 +190,58 @@ inline from_chars_result from_chars(const char* first, const char* last, T& valu #if defined(_WIN32) +/*! +@brief Extended locale functions on Windows + +A trait object which provides wrappers for isspace and the strto* family of +functions, based on the platform's support for extended locale APIs. + +This is the Windows implementation. The primary class template definition +falls back to the standard locale-dependent functions, which is used on +MinGW, whose C runtime only provides an incomplete subset of the +`__l` family (e.g., missing `_strtof_l`/`_strtold_l` depending on +the toolchain version). A specialization for genuine MSVC (including +clang-cl, which mimics the MSVC ABI and CRT) is used instead, as the full +`__l` family has reliably been available there since at least +Visual Studio 2005. +*/ +template +struct extended_locale_traits +{ + static constexpr bool is_locale_independent = false; + + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + static int isspace(int c) noexcept + { + return std::isspace(c); + } + + // NOLINTNEXTLINE(runtime/int) + static long long strtoll(const char* str, char** endptr) noexcept + { + return std::strtoll(str, endptr, 10); + } + + // NOLINTNEXTLINE(runtime/int) + static unsigned long long strtoull(const char* str, char** endptr) noexcept + { + return std::strtoull(str, endptr, 10); + } + + static constexpr float(&strtof)(const char*, char**) = std::strtof; + static constexpr double(&strtod)(const char*, char**) = std::strtod; + static constexpr long double(&strtold)(const char*, char**) = std::strtold; +}; + +#if defined(_MSC_VER) + /*! @brief Get a pointer to a globally shared instance of the "C" locale on Windows @@ -208,58 +260,51 @@ inline _locale_t get_c_locale_t() noexcept } }; using LocaleUPtr = std::unique_ptr::type, LocaleTDeleter>; - static const LocaleUPtr c_locale = LocaleUPtr{::_create_locale(LC_ALL_MASK, "C"), LocaleTDeleter{}}; + static const LocaleUPtr c_locale = LocaleUPtr{::_create_locale(LC_ALL, "C"), LocaleTDeleter{}}; return c_locale.get(); } -/*! -@brief Extended locale functions on Windows - -A trait object which provides wrappers for isspace and the strto* family of -functions, based on the platform's support for extended locale APIs. - -This is the Windows implementation where extended locale support is always -available through the `__l` variants. -*/ -template -struct extended_locale_traits +template +struct extended_locale_traits { static constexpr bool is_locale_independent = true; static constexpr char(&get_decimal_point)() = get_locale_independent_decimal_point; static int isspace(int c) noexcept { - return ::_isspace_l(c, get_c_locale_t()); + return _isspace_l(c, get_c_locale_t()); } // NOLINTNEXTLINE(runtime/int) static long long strtoll(const char* str, char** endptr) noexcept { - return ::_strtoll_l(str, endptr, 10, get_c_locale_t()); + return _strtoll_l(str, endptr, 10, get_c_locale_t()); } // NOLINTNEXTLINE(runtime/int) static unsigned long long strtoull(const char* str, char** endptr) noexcept { - return ::_strtoull_l(str, endptr, 10, get_c_locale_t()); + return _strtoull_l(str, endptr, 10, get_c_locale_t()); } - static float strtof(const char* str, char** str_end) noexcept + static float strtof(T str, char** str_end) { - return ::_strtof_l(str, str_end, get_c_locale_t()); + return _strtof_l(str, str_end, get_c_locale_t()); } - static double strtod(const char* str, char** str_end) noexcept + static double strtod(T str, char** str_end) { - return ::_strtod_l(str, str_end, get_c_locale_t()); + return _strtod_l(str, str_end, get_c_locale_t()); } - static long double strtold(const char* str, char** str_end) noexcept + static long double strtold(T str, char** str_end) { - return ::_strtold_l(str, str_end, get_c_locale_t()); + return _strtold_l(str, str_end, get_c_locale_t()); } }; +#endif + #else /*! @@ -360,7 +405,7 @@ struct extended_locale_traits_l` family (e.g., missing `_strtof_l`/`_strtold_l` depending on +the toolchain version). A specialization for genuine MSVC (including +clang-cl, which mimics the MSVC ABI and CRT) is used instead, as the full +`__l` family has reliably been available there since at least +Visual Studio 2005. +*/ +template +struct extended_locale_traits +{ + static constexpr bool is_locale_independent = false; + + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + static int isspace(int c) noexcept + { + return std::isspace(c); + } + + // NOLINTNEXTLINE(runtime/int) + static long long strtoll(const char* str, char** endptr) noexcept + { + return std::strtoll(str, endptr, 10); + } + + // NOLINTNEXTLINE(runtime/int) + static unsigned long long strtoull(const char* str, char** endptr) noexcept + { + return std::strtoull(str, endptr, 10); + } + + static constexpr float(&strtof)(const char*, char**) = std::strtof; + static constexpr double(&strtod)(const char*, char**) = std::strtod; + static constexpr long double(&strtold)(const char*, char**) = std::strtold; +}; + +#if defined(_MSC_VER) + /*! @brief Get a pointer to a globally shared instance of the "C" locale on Windows @@ -7924,58 +7976,51 @@ inline _locale_t get_c_locale_t() noexcept } }; using LocaleUPtr = std::unique_ptr::type, LocaleTDeleter>; - static const LocaleUPtr c_locale = LocaleUPtr{::_create_locale(LC_ALL_MASK, "C"), LocaleTDeleter{}}; + static const LocaleUPtr c_locale = LocaleUPtr{::_create_locale(LC_ALL, "C"), LocaleTDeleter{}}; return c_locale.get(); } -/*! -@brief Extended locale functions on Windows - -A trait object which provides wrappers for isspace and the strto* family of -functions, based on the platform's support for extended locale APIs. - -This is the Windows implementation where extended locale support is always -available through the `__l` variants. -*/ -template -struct extended_locale_traits +template +struct extended_locale_traits { static constexpr bool is_locale_independent = true; static constexpr char(&get_decimal_point)() = get_locale_independent_decimal_point; static int isspace(int c) noexcept { - return ::_isspace_l(c, get_c_locale_t()); + return _isspace_l(c, get_c_locale_t()); } // NOLINTNEXTLINE(runtime/int) static long long strtoll(const char* str, char** endptr) noexcept { - return ::_strtoll_l(str, endptr, 10, get_c_locale_t()); + return _strtoll_l(str, endptr, 10, get_c_locale_t()); } // NOLINTNEXTLINE(runtime/int) static unsigned long long strtoull(const char* str, char** endptr) noexcept { - return ::_strtoull_l(str, endptr, 10, get_c_locale_t()); + return _strtoull_l(str, endptr, 10, get_c_locale_t()); } - static float strtof(const char* str, char** str_end) noexcept + static float strtof(T str, char** str_end) { - return ::_strtof_l(str, str_end, get_c_locale_t()); + return _strtof_l(str, str_end, get_c_locale_t()); } - static double strtod(const char* str, char** str_end) noexcept + static double strtod(T str, char** str_end) { - return ::_strtod_l(str, str_end, get_c_locale_t()); + return _strtod_l(str, str_end, get_c_locale_t()); } - static long double strtold(const char* str, char** str_end) noexcept + static long double strtold(T str, char** str_end) { - return ::_strtold_l(str, str_end, get_c_locale_t()); + return _strtold_l(str, str_end, get_c_locale_t()); } }; +#endif + #else /*! @@ -8076,7 +8121,7 @@ struct extended_locale_traits typename std::enable_if::value, void>::type -check(std::string str, init_val_t, std::ptrdiff_t expected_ptr_offset, std::errc expected_ec) +check(std::string str, init_val_t /*unused*/, std::ptrdiff_t expected_ptr_offset, std::errc expected_ec) { T const init_value = 42; T value = init_value; @@ -89,7 +89,7 @@ check(std::string str, init_val_t, std::ptrdiff_t expected_ptr_offset, std::errc template typename std::enable_if::value, void>::type -check(std::string str, init_val_t, std::ptrdiff_t expected_ptr_offset, std::errc expected_ec) +check(std::string str, init_val_t /*unused*/, std::ptrdiff_t expected_ptr_offset, std::errc expected_ec) { { T const init_value = 42;