Skip to content

Commit

Permalink
Parsing: use <charconv> from_chars on C++17
Browse files Browse the repository at this point in the history
When building for C++17 or later, NumberUtils can use standard
<charconv> 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.
  • Loading branch information
aras-p committed Oct 1, 2024
1 parent bcb7ce5 commit dab9471
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
3 changes: 3 additions & 0 deletions share/cmake/utils/CompilerFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
48 changes: 45 additions & 3 deletions src/utils/NumberUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
#ifndef INCLUDED_NUMBERUTILS_H
#define INCLUDED_NUMBERUTILS_H

// With C++17, we can use <charconv> 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 <charconv>
#endif

#if defined(_MSC_VER)
#define really_inline __forceinline
#else
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit dab9471

Please sign in to comment.