diff --git a/doc/decimal/charconv.adoc b/doc/decimal/charconv.adoc index 10c846ce3..2ae869620 100644 --- a/doc/decimal/charconv.adoc +++ b/doc/decimal/charconv.adoc @@ -88,6 +88,18 @@ namespace decimal { template constexpr boost::decimal::from_chars_result from_chars(const char* first, const char* last, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept +#ifdef BOOST_DECIMAL_HAS_STD_STRING_VIEW + +template +constexpr boost::decimal::from_chars_result from_chars(std::string_view str, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept + +#else + +template +constexpr boost::decimal::from_chars_result from_chars(const std::string& str, DecimalType& value, boost::decimal::chars_format fmt = boost::decimal::chars_format::general) noexcept + +#endif + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV template diff --git a/doc/decimal/config.adoc b/doc/decimal/config.adoc index f578f4897..268e91def 100644 --- a/doc/decimal/config.adoc +++ b/doc/decimal/config.adoc @@ -46,3 +46,5 @@ This flag increases the performance of the basis operations (e.g. add, sub, mul, - `BOOST_DECIMAL_HAS_STD_CHARCONV`: This macro is defined if header `` exists and the language standard used is >= C++17 * We only need the structs and enums out of the header so we are not concerned with being overly restrictive about the feature test macros. ** Known compilers that support this lighter requirement are: GCC >= 10, Clang >= 13, and MSVC >= 14.2 + +- `BOOST_DECIMAL_HAS_STD_STRING_VIEW`: This macro is defined if header `` exists and the langauge standard used is >= C++17 diff --git a/include/boost/decimal/charconv.hpp b/include/boost/decimal/charconv.hpp index 21a7a2ceb..5fe93836f 100644 --- a/include/boost/decimal/charconv.hpp +++ b/include/boost/decimal/charconv.hpp @@ -27,6 +27,10 @@ #if !defined(BOOST_DECIMAL_DISABLE_CLIB) +#ifndef BOOST_DECIMAL_BUILD_MODULE +#include +#endif + namespace boost { namespace decimal { @@ -94,31 +98,103 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal32& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal32& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal64& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal64& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal64& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal64_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal128& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal128& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal128& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept { return detail::from_chars_general_impl(first, last, value, fmt); } +#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW +BOOST_DECIMAL_EXPORT inline auto from_chars(const std::string& str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#else +BOOST_DECIMAL_EXPORT constexpr auto from_chars(std::string_view str, decimal128_fast& value, chars_format fmt = chars_format::general) noexcept +{ + return detail::from_chars_general_impl(str.data(), str.data() + str.size(), value, fmt); +} +#endif + #ifdef BOOST_DECIMAL_HAS_STD_CHARCONV BOOST_DECIMAL_EXPORT template constexpr auto from_chars(const char* first, const char* last, DecimalType& value, std::chars_format fmt) noexcept @@ -147,6 +223,13 @@ constexpr auto from_chars(const char* first, const char* last, DecimalType& valu return std::from_chars_result {boost_r.ptr, boost_r.ec}; } + +BOOST_DECIMAL_EXPORT template +constexpr auto from_chars(std::string_view str, DecimalType& value, std::chars_format fmt) noexcept + BOOST_DECIMAL_REQUIRES_RETURN(detail::is_decimal_floating_point_v, DecimalType, std::from_chars_result) +{ + return from_chars(str.data(), str.data() + str.size(), value, fmt); +} #endif // --------------------------------------------------------------------------------------------------------------------- diff --git a/include/boost/decimal/detail/config.hpp b/include/boost/decimal/detail/config.hpp index 3dec3b8c2..fe4f36dc9 100644 --- a/include/boost/decimal/detail/config.hpp +++ b/include/boost/decimal/detail/config.hpp @@ -323,6 +323,16 @@ typedef unsigned __int128 uint128_t; # define BOOST_DECIMAL_HAS_STD_CHARCONV # endif # endif + +# if __has_include() +# ifndef BOOST_DECIMAL_BUILD_MODULE +# include +# endif +# if __cpp_lib_string_view >= 201606L +# define BOOST_DECIMAL_HAS_STD_STRING_VIEW +# endif +# endif + #endif // Since we should not be able to pull these in from the STL in module mode define them ourselves diff --git a/modules/decimal.cxx b/modules/decimal.cxx index 0031838c2..033c745bb 100644 --- a/modules/decimal.cxx +++ b/modules/decimal.cxx @@ -30,6 +30,7 @@ module; #include #include #include +#include // is a C++23 feature that is not everywhere yet #if __has_include() diff --git a/test/test_from_chars.cpp b/test/test_from_chars.cpp index 4964a5de4..0500a29f7 100644 --- a/test/test_from_chars.cpp +++ b/test/test_from_chars.cpp @@ -162,6 +162,7 @@ void test_non_finite_values() const char* snan_str = "nan(snan)"; auto r = from_chars(snan_str, snan_str + std::strlen(snan_str), val); + BOOST_TEST(r); BOOST_TEST(isnan(val)); const char* qnan_str = "nan"; @@ -318,6 +319,17 @@ void test_from_chars_general_std() #endif +template +void test_string_interface() +{ + constexpr T correct_val {42}; + std::string str {"42"}; + T val; + const auto r = from_chars(str, val); + BOOST_TEST(r); + BOOST_TEST_EQ(val, correct_val); +} + int main() { test_from_chars_scientific(); @@ -362,12 +374,25 @@ int main() test_hex_values(); test_hex_values(); + test_string_interface(); + test_string_interface(); + test_string_interface(); + test_string_interface(); + #if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH) test_from_chars_scientific(); test_from_chars_fixed(); test_from_chars_general(); test_non_finite_values(); test_hex_values(); + test_string_interface(); + + test_from_chars_scientific(); + test_from_chars_fixed(); + test_from_chars_general(); + test_non_finite_values(); + test_hex_values(); + test_string_interface(); #endif return boost::report_errors();