From dab9471806f6322f7d4ea4f0952f50518fedd81a Mon Sep 17 00:00:00 2001 From: Aras Pranckevicius Date: Tue, 1 Oct 2024 13:26:33 +0300 Subject: [PATCH] Parsing: use from_chars on C++17 When building for C++17 or later, NumberUtils can use standard from_chars functions (except on Apple platforms, where those are not implemented for floating point types as of Xcode 15). This has advantage of not having to deal with errno nor locales. Saves some thread local storage accesses and function calls (e.g. on Windows errno is actually a function call). With these changes, parsing Khronos PBR Neutral Iridas .cube file (5.4MB) on Ryzen 5950X / VS2022 Release build: 142ms -> 123ms There's a CMake setup change that adds "/Zc:__cplusplus" flag for MSVC; for backwards compat reasons it does not report proper C++ version detection defines otherwise. --- share/cmake/utils/CompilerFlags.cmake | 3 ++ src/utils/NumberUtils.h | 48 +++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/share/cmake/utils/CompilerFlags.cmake b/share/cmake/utils/CompilerFlags.cmake index 91e438f455..c1f6272480 100644 --- a/share/cmake/utils/CompilerFlags.cmake +++ b/share/cmake/utils/CompilerFlags.cmake @@ -62,6 +62,9 @@ if(USE_MSVC) ) endif() + # Make MSVC compiler report correct __cplusplus version (otherwise reports 199711L) + set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/Zc:__cplusplus") + # Explicitely specify the default warning level i.e. /W3. # Note: Do not use /Wall (i.e. /W4) which adds 'informational' warnings. set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/W3") diff --git a/src/utils/NumberUtils.h b/src/utils/NumberUtils.h index f6835a0a16..05231c4d2a 100644 --- a/src/utils/NumberUtils.h +++ b/src/utils/NumberUtils.h @@ -4,6 +4,18 @@ #ifndef INCLUDED_NUMBERUTILS_H #define INCLUDED_NUMBERUTILS_H +// With C++17, we can use from_chars. +// +// That has advantage of not dealing with locale / errno, +// which might involve locks or thread local storage accesses. +// +// Except on Apple platforms, where (as of Xcode 15 / Apple Clang 15) +// these are not implemented for float/double types. +#if __cpp_lib_to_chars >= 201611L && !defined(__APPLE__) +#define USE_CHARCONV_FROM_CHARS +#include +#endif + #if defined(_MSC_VER) #define really_inline __forceinline #else @@ -56,12 +68,21 @@ static const Locale loc; really_inline from_chars_result from_chars(const char *first, const char *last, double &value) noexcept { - errno = 0; if (!first || !last || first == last) { return {first, std::errc::invalid_argument}; } +#ifdef USE_CHARCONV_FROM_CHARS + if (first < last && first[0] == '+') + { + ++first; + } + std::from_chars_result res = std::from_chars(first, last, value); + return from_chars_result{ res.ptr, res.ec }; +#else + + errno = 0; char * endptr = nullptr; double @@ -88,16 +109,26 @@ really_inline from_chars_result from_chars(const char *first, const char *last, { return {first, std::errc::argument_out_of_domain}; } +#endif } really_inline from_chars_result from_chars(const char *first, const char *last, float &value) noexcept { - errno = 0; if (!first || !last || first == last) { return {first, std::errc::invalid_argument}; } +#ifdef USE_CHARCONV_FROM_CHARS + if (first < last && first[0] == '+') + { + ++first; + } + std::from_chars_result res = std::from_chars(first, last, value); + return from_chars_result{ res.ptr, res.ec }; +#else + + errno = 0; char *endptr = nullptr; float @@ -132,16 +163,26 @@ really_inline from_chars_result from_chars(const char *first, const char *last, { return {first, std::errc::argument_out_of_domain}; } +#endif } really_inline from_chars_result from_chars(const char *first, const char *last, long int &value) noexcept { - errno = 0; if (!first || !last || first == last) { return {first, std::errc::invalid_argument}; } +#ifdef USE_CHARCONV_FROM_CHARS + if (first < last && first[0] == '+') + { + ++first; + } + std::from_chars_result res = std::from_chars(first, last, value); + return from_chars_result{ res.ptr, res.ec }; +#else + + errno = 0; char *endptr = nullptr; long int @@ -170,6 +211,7 @@ really_inline from_chars_result from_chars(const char *first, const char *last, { return {first, std::errc::argument_out_of_domain}; } +#endif } } // namespace NumberUtils } // namespace OCIO_NAMESPACE