Skip to content

Commit dab9471

Browse files
committed
Parsing: use <charconv> from_chars on C++17
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.
1 parent bcb7ce5 commit dab9471

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

share/cmake/utils/CompilerFlags.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ if(USE_MSVC)
6262
)
6363
endif()
6464

65+
# Make MSVC compiler report correct __cplusplus version (otherwise reports 199711L)
66+
set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/Zc:__cplusplus")
67+
6568
# Explicitely specify the default warning level i.e. /W3.
6669
# Note: Do not use /Wall (i.e. /W4) which adds 'informational' warnings.
6770
set(PLATFORM_COMPILE_OPTIONS "${PLATFORM_COMPILE_OPTIONS};/W3")

src/utils/NumberUtils.h

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44
#ifndef INCLUDED_NUMBERUTILS_H
55
#define INCLUDED_NUMBERUTILS_H
66

7+
// With C++17, we can use <charconv> from_chars.
8+
//
9+
// That has advantage of not dealing with locale / errno,
10+
// which might involve locks or thread local storage accesses.
11+
//
12+
// Except on Apple platforms, where (as of Xcode 15 / Apple Clang 15)
13+
// these are not implemented for float/double types.
14+
#if __cpp_lib_to_chars >= 201611L && !defined(__APPLE__)
15+
#define USE_CHARCONV_FROM_CHARS
16+
#include <charconv>
17+
#endif
18+
719
#if defined(_MSC_VER)
820
#define really_inline __forceinline
921
#else
@@ -56,12 +68,21 @@ static const Locale loc;
5668

5769
really_inline from_chars_result from_chars(const char *first, const char *last, double &value) noexcept
5870
{
59-
errno = 0;
6071
if (!first || !last || first == last)
6172
{
6273
return {first, std::errc::invalid_argument};
6374
}
6475

76+
#ifdef USE_CHARCONV_FROM_CHARS
77+
if (first < last && first[0] == '+')
78+
{
79+
++first;
80+
}
81+
std::from_chars_result res = std::from_chars(first, last, value);
82+
return from_chars_result{ res.ptr, res.ec };
83+
#else
84+
85+
errno = 0;
6586
char * endptr = nullptr;
6687

6788
double
@@ -88,16 +109,26 @@ really_inline from_chars_result from_chars(const char *first, const char *last,
88109
{
89110
return {first, std::errc::argument_out_of_domain};
90111
}
112+
#endif
91113
}
92114

93115
really_inline from_chars_result from_chars(const char *first, const char *last, float &value) noexcept
94116
{
95-
errno = 0;
96117
if (!first || !last || first == last)
97118
{
98119
return {first, std::errc::invalid_argument};
99120
}
100121

122+
#ifdef USE_CHARCONV_FROM_CHARS
123+
if (first < last && first[0] == '+')
124+
{
125+
++first;
126+
}
127+
std::from_chars_result res = std::from_chars(first, last, value);
128+
return from_chars_result{ res.ptr, res.ec };
129+
#else
130+
131+
errno = 0;
101132
char *endptr = nullptr;
102133

103134
float
@@ -132,16 +163,26 @@ really_inline from_chars_result from_chars(const char *first, const char *last,
132163
{
133164
return {first, std::errc::argument_out_of_domain};
134165
}
166+
#endif
135167
}
136168

137169
really_inline from_chars_result from_chars(const char *first, const char *last, long int &value) noexcept
138170
{
139-
errno = 0;
140171
if (!first || !last || first == last)
141172
{
142173
return {first, std::errc::invalid_argument};
143174
}
144175

176+
#ifdef USE_CHARCONV_FROM_CHARS
177+
if (first < last && first[0] == '+')
178+
{
179+
++first;
180+
}
181+
std::from_chars_result res = std::from_chars(first, last, value);
182+
return from_chars_result{ res.ptr, res.ec };
183+
#else
184+
185+
errno = 0;
145186
char *endptr = nullptr;
146187

147188
long int
@@ -170,6 +211,7 @@ really_inline from_chars_result from_chars(const char *first, const char *last,
170211
{
171212
return {first, std::errc::argument_out_of_domain};
172213
}
214+
#endif
173215
}
174216
} // namespace NumberUtils
175217
} // namespace OCIO_NAMESPACE

0 commit comments

Comments
 (0)