diff --git a/src/OpenColorIO/CMakeLists.txt b/src/OpenColorIO/CMakeLists.txt index 034185d8c6..65b68a98eb 100755 --- a/src/OpenColorIO/CMakeLists.txt +++ b/src/OpenColorIO/CMakeLists.txt @@ -227,7 +227,7 @@ target_link_libraries(OpenColorIO ${OCIO_HALF_LIB} pystring::pystring sampleicc::sampleicc - utils::from_chars + from_chars_helpers utils::strings yaml-cpp ) diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index c10ea658a4..0f789b96db 100755 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -18,13 +18,22 @@ set_property(TARGET ${OCIO_HALF_LIB} APPEND PROPERTY # from_chars shim (via fast_float or strtod_l) -add_library(utils::from_chars INTERFACE IMPORTED GLOBAL) +set(SOURCES + NumberUtils.cpp +) -set_target_properties(utils::from_chars PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/.." +add_library(from_chars_helpers STATIC ${SOURCES}) + +target_include_directories(from_chars_helpers + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/.." ) if (OCIO_USE_FAST_FLOAT) - target_compile_definitions(utils::from_chars INTERFACE USE_FAST_FLOAT) - target_link_libraries(utils::from_chars INTERFACE fast_float::fast_float) + target_compile_definitions(from_chars_helpers PUBLIC USE_FAST_FLOAT) + target_link_libraries(from_chars_helpers PUBLIC fast_float::fast_float) endif() + +set_target_properties(from_chars_helpers PROPERTIES + COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS}" +) diff --git a/src/utils/NumberUtils.cpp b/src/utils/NumberUtils.cpp new file mode 100644 index 0000000000..f79dc14cfc --- /dev/null +++ b/src/utils/NumberUtils.cpp @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright Contributors to the OpenColorIO Project. + +#include "NumberUtils.h" + +#ifdef USE_FAST_FLOAT +#include +#endif + +#include +#include + +namespace NumberUtils +{ + +struct Locale +{ +#ifdef _WIN32 + Locale() : local(_create_locale(LC_ALL, "C")) + { + } + ~Locale() + { + _free_locale(local); + } + _locale_t local; +#else + Locale() : local(newlocale(LC_ALL_MASK, "C", NULL)) + { + } + ~Locale() + { + freelocale(local); + } + locale_t local; +#endif +}; + +static const Locale loc; + +#ifdef USE_FAST_FLOAT +from_chars_result from_chars(const char *first, const char *last, float &value) noexcept +{ + // By design that's not supported by from_chars() so handle it here. + if (first && *first == '+') + ++first; + + const auto ret = fast_float::from_chars(first, last, value); + return {ret.ptr, ret.ec}; +} + +from_chars_result from_chars(const char *first, const char *last, double &value) noexcept +{ + // By design that's not supported by from_chars() so handle it here. + if (first && *first == '+') + ++first; + + const auto ret = fast_float::from_chars(first, last, value); + return {ret.ptr, ret.ec}; +} + +#else +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}; + } + + char *endptr = nullptr; + + double +#ifdef _WIN32 + tempval = _strtod_l(first, &endptr, loc.local); +#else + tempval = ::strtod_l(first, &endptr, loc.local); +#endif + + if (errno != 0) + { + return {first + (endptr - first), std::errc::result_out_of_range}; + } + else if (endptr == first) + { + return {first, std::errc::invalid_argument}; + } + else if (endptr <= last) + { + value = tempval; + return {first + (endptr - first), {}}; + } + else + { + return {first, std::errc::argument_out_of_domain}; + } +} + +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}; + } + + char *endptr = nullptr; + + float +#ifdef _WIN32 + tempval = _strtof_l(first, &endptr, loc.local); +#elif __APPLE__ + // On OSX, strtod_l is for some reason drastically faster than strtof_l. + tempval = static_cast(::strtod_l(first, &endptr, loc.local)); +#else + tempval = ::strtof_l(first, &endptr, loc.local); +#endif + + if (errno != 0) + { + return {first + (endptr - first), std::errc::result_out_of_range}; + } + else if (endptr == first) + { + return {first, std::errc::invalid_argument}; + } + else if (endptr <= last) + { + value = tempval; + return {first + (endptr - first), {}}; + } + else + { + return {first, std::errc::argument_out_of_domain}; + } +} +#endif // USE_FAST_FLOAT + +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}; + } + + char *endptr = nullptr; + + long int +#ifdef _WIN32 + tempval = _strtol_l(first, &endptr, 0, loc.local); +#else + tempval = ::strtol_l(first, &endptr, 0, loc.local); +#endif + + if (errno != 0) + { + return {first + (endptr - first), std::errc::result_out_of_range}; + } + else if (endptr == first) + { + return {first, std::errc::invalid_argument}; + } + else if (endptr <= last) + { + value = tempval; + return {first + (endptr - first), {}}; + } + else + { + return {first, std::errc::argument_out_of_domain}; + } +} +} // namespace NumberUtils diff --git a/src/utils/NumberUtils.h b/src/utils/NumberUtils.h index 34d1f2e7ee..9876d9f7e9 100644 --- a/src/utils/NumberUtils.h +++ b/src/utils/NumberUtils.h @@ -4,190 +4,21 @@ #ifndef INCLUDED_NUMBERUTILS_H #define INCLUDED_NUMBERUTILS_H -#if defined(_MSC_VER) -#define really_inline __forceinline -#else -#define really_inline inline __attribute__((always_inline)) -#endif - -#ifdef USE_FAST_FLOAT -#include -#endif - -#include -#include #include -#include -namespace OCIO_NAMESPACE -{ namespace NumberUtils { - -struct Locale -{ -#ifdef _WIN32 - Locale() : local(_create_locale(LC_ALL, "C")) - { - } - ~Locale() - { - _free_locale(local); - } - _locale_t local; -#else - Locale() : local(newlocale(LC_ALL_MASK, "C", NULL)) - { - } - ~Locale() - { - freelocale(local); - } - locale_t local; -#endif -}; - struct from_chars_result { const char *ptr; std::errc ec; }; -static const Locale loc; - -#ifdef USE_FAST_FLOAT -really_inline from_chars_result from_chars(const char *first, const char *last, float &value) noexcept -{ - // By design that's not supported by from_chars() so handle it here. - if (first && *first == '+') - ++first; - - const auto ret = fast_float::from_chars(first, last, value); - return {ret.ptr, ret.ec}; -} - -really_inline from_chars_result from_chars(const char *first, const char *last, double &value) noexcept -{ - // By design that's not supported by from_chars() so handle it here. - if (first && *first == '+') - ++first; - - const auto ret = fast_float::from_chars(first, last, value); - return {ret.ptr, ret.ec}; -} - -#else -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}; - } - - char * endptr = nullptr; - - double -#ifdef _WIN32 - tempval = _strtod_l(first, &endptr, loc.local); -#else - tempval = ::strtod_l(first, &endptr, loc.local); -#endif - - if (errno != 0) - { - return {first + (endptr - first), std::errc::result_out_of_range}; - } - else if (endptr == first) - { - return {first, std::errc::invalid_argument}; - } - else if (endptr <= last) - { - value = tempval; - return {first + (endptr - first), {}}; - } - else - { - return {first, std::errc::argument_out_of_domain}; - } -} - -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}; - } - - char *endptr = nullptr; - - float -#ifdef _WIN32 - tempval = _strtof_l(first, &endptr, loc.local); -#elif __APPLE__ - // On OSX, strtod_l is for some reason drastically faster than strtof_l. - tempval = static_cast(::strtod_l(first, &endptr, loc.local)); -#else - tempval = ::strtof_l(first, &endptr, loc.local); -#endif - - if (errno != 0) - { - return {first + (endptr - first), std::errc::result_out_of_range}; - } - else if (endptr == first) - { - return {first, std::errc::invalid_argument}; - } - else if (endptr <= last) - { - value = tempval; - return {first + (endptr - first), {}}; - } - else - { - return {first, std::errc::argument_out_of_domain}; - } -} -#endif // USE_FAST_FLOAT - -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}; - } +from_chars_result from_chars(const char *first, const char *last, float &value) noexcept; - char *endptr = nullptr; +from_chars_result from_chars(const char *first, const char *last, double &value) noexcept; - long int -#ifdef _WIN32 - tempval = _strtol_l(first, &endptr, 0, loc.local); -#else - tempval = ::strtol_l(first, &endptr, 0, loc.local); -#endif +from_chars_result from_chars(const char *first, const char *last, long int &value) noexcept; - if (errno != 0) - { - return {first + (endptr - first), std::errc::result_out_of_range}; - } - else if (endptr == first) - { - return {first, std::errc::invalid_argument}; - } - else if (endptr <= last) - { - value = tempval; - return {first + (endptr - first), {}}; - } - else - { - return {first, std::errc::argument_out_of_domain}; - } -} } // namespace NumberUtils -} // namespace OCIO_NAMESPACE #endif // INCLUDED_NUMBERUTILS_H diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 73e265f0eb..ff107ef632 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -19,7 +19,7 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) ${OCIO_HALF_LIB} pystring::pystring sampleicc::sampleicc - utils::from_chars + from_chars_helpers unittest_data utils::strings yaml-cpp