libstdc++: Ensure that std::from_chars is declared when supported
This adjusts the declarations in <charconv> to match when the definition is present. This solves the issue that std::from_chars is present on Solaris 11.3 (using fast_float) but was not declared in the header (because the declarations were guarded by _GLIBCXX_HAVE_USELOCALE). Additionally, do not define __cpp_lib_to_chars unless both from_chars and to_chars are supported (which is only true for IEEE float and double). We might still provide from_chars (via strtold) but if to_chars isn't provided, we shouldn't define the feature test macro. Finally, this simplifies some of the preprocessor checks in the bodies of std::from_chars in src/c++17/floating_from_chars.cc and hoists the repeated code for the strtod version into a new function template. N.B. the long double overload of std::from_chars will always be defined if the float and double overloads are defined. We can always use one of strtold or fast_float's binary64 routines (although the latter might produce errors for some long double values if they are not representable as binary64). libstdc++-v3/ChangeLog: * include/std/charconv (__cpp_lib_to_chars): Only define when both from_chars and to_chars are supported for floating-point types. (from_chars, to_chars): Adjust preprocessor conditions guarding declarations. * include/std/version (__cpp_lib_to_chars): Adjust condition to match <charconv> definition. * src/c++17/floating_from_chars.cc (from_chars_strtod): New function template. (from_chars): Simplify preprocessor checks and use from_chars_strtod when appropriate.
This commit is contained in:
parent
beb12c62ea
commit
5a4e208022
@ -43,7 +43,8 @@
|
||||
#include <bits/error_constants.h> // for std::errc
|
||||
#include <ext/numeric_traits.h>
|
||||
|
||||
#if _GLIBCXX_HAVE_USELOCALE
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
|
||||
&& __SIZE_WIDTH__ >= 32
|
||||
# define __cpp_lib_to_chars 201611L
|
||||
#endif
|
||||
|
||||
@ -686,7 +687,7 @@ namespace __detail
|
||||
operator^=(chars_format& __lhs, chars_format __rhs) noexcept
|
||||
{ return __lhs = __lhs ^ __rhs; }
|
||||
|
||||
#if _GLIBCXX_HAVE_USELOCALE
|
||||
#if defined __cpp_lib_to_chars || _GLIBCXX_HAVE_USELOCALE
|
||||
from_chars_result
|
||||
from_chars(const char* __first, const char* __last, float& __value,
|
||||
chars_format __fmt = chars_format::general) noexcept;
|
||||
@ -700,8 +701,7 @@ namespace __detail
|
||||
chars_format __fmt = chars_format::general) noexcept;
|
||||
#endif
|
||||
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
|
||||
&& __SIZE_WIDTH__ >= 32
|
||||
#if defined __cpp_lib_to_chars
|
||||
// Floating-point std::to_chars
|
||||
|
||||
// Overloads for float.
|
||||
|
@ -171,7 +171,8 @@
|
||||
#endif
|
||||
#define __cpp_lib_shared_ptr_weak_type 201606L
|
||||
#define __cpp_lib_string_view 201803L
|
||||
#if _GLIBCXX_HAVE_USELOCALE
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
|
||||
&& __SIZE_WIDTH__ >= 32
|
||||
# define __cpp_lib_to_chars 201611L
|
||||
#endif
|
||||
#define __cpp_lib_unordered_map_try_emplace 201411L
|
||||
|
@ -65,6 +65,7 @@ extern "C" __ieee128 __strtoieee128(const char*, char**);
|
||||
&& __SIZE_WIDTH__ >= 32
|
||||
# define USE_LIB_FAST_FLOAT 1
|
||||
# if __LDBL_MANT_DIG__ == __DBL_MANT_DIG__
|
||||
// No need to use strtold.
|
||||
# undef USE_STRTOD_FOR_FROM_CHARS
|
||||
# endif
|
||||
#endif
|
||||
@ -420,6 +421,33 @@ namespace
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
from_chars_result
|
||||
from_chars_strtod(const char* first, const char* last, T& value,
|
||||
chars_format fmt) noexcept
|
||||
{
|
||||
errc ec = errc::invalid_argument;
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
buffer_resource mr;
|
||||
pmr::string buf(&mr);
|
||||
#else
|
||||
string buf;
|
||||
if (!reserve_string(buf))
|
||||
return make_result(first, 0, {}, ec);
|
||||
#endif
|
||||
size_t len = 0;
|
||||
__try
|
||||
{
|
||||
if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
|
||||
len = from_chars_impl(pat, value, ec);
|
||||
}
|
||||
__catch (const std::bad_alloc&)
|
||||
{
|
||||
fmt = chars_format{};
|
||||
}
|
||||
return make_result(first, len, fmt, ec);
|
||||
}
|
||||
#endif // USE_STRTOD_FOR_FROM_CHARS
|
||||
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
|
||||
@ -793,35 +821,15 @@ from_chars_result
|
||||
from_chars(const char* first, const char* last, float& value,
|
||||
chars_format fmt) noexcept
|
||||
{
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
|
||||
#if USE_LIB_FAST_FLOAT
|
||||
if (fmt == chars_format::hex)
|
||||
return __floating_from_chars_hex(first, last, value);
|
||||
else
|
||||
{
|
||||
static_assert(USE_LIB_FAST_FLOAT);
|
||||
return fast_float::from_chars(first, last, value, fmt);
|
||||
}
|
||||
#else
|
||||
errc ec = errc::invalid_argument;
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
buffer_resource mr;
|
||||
pmr::string buf(&mr);
|
||||
#else
|
||||
string buf;
|
||||
if (!reserve_string(buf))
|
||||
return make_result(first, 0, {}, ec);
|
||||
#endif
|
||||
size_t len = 0;
|
||||
__try
|
||||
{
|
||||
if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
|
||||
len = from_chars_impl(pat, value, ec);
|
||||
}
|
||||
__catch (const std::bad_alloc&)
|
||||
{
|
||||
fmt = chars_format{};
|
||||
}
|
||||
return make_result(first, len, fmt, ec);
|
||||
return from_chars_strtod(first, last, value, fmt);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -829,35 +837,15 @@ from_chars_result
|
||||
from_chars(const char* first, const char* last, double& value,
|
||||
chars_format fmt) noexcept
|
||||
{
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
|
||||
#if USE_LIB_FAST_FLOAT
|
||||
if (fmt == chars_format::hex)
|
||||
return __floating_from_chars_hex(first, last, value);
|
||||
else
|
||||
{
|
||||
static_assert(USE_LIB_FAST_FLOAT);
|
||||
return fast_float::from_chars(first, last, value, fmt);
|
||||
}
|
||||
#else
|
||||
errc ec = errc::invalid_argument;
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
buffer_resource mr;
|
||||
pmr::string buf(&mr);
|
||||
#else
|
||||
string buf;
|
||||
if (!reserve_string(buf))
|
||||
return make_result(first, 0, {}, ec);
|
||||
#endif
|
||||
size_t len = 0;
|
||||
__try
|
||||
{
|
||||
if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
|
||||
len = from_chars_impl(pat, value, ec);
|
||||
}
|
||||
__catch (const std::bad_alloc&)
|
||||
{
|
||||
fmt = chars_format{};
|
||||
}
|
||||
return make_result(first, len, fmt, ec);
|
||||
return from_chars_strtod(first, last, value, fmt);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -865,41 +853,23 @@ from_chars_result
|
||||
from_chars(const char* first, const char* last, long double& value,
|
||||
chars_format fmt) noexcept
|
||||
{
|
||||
#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
|
||||
&& ! USE_STRTOD_FOR_FROM_CHARS
|
||||
#if ! USE_STRTOD_FOR_FROM_CHARS
|
||||
// Either long double is the same as double, or we can't use strtold.
|
||||
// In the latter case, this might give an incorrect result (e.g. values
|
||||
// out of range of double give an error, even if they fit in long double).
|
||||
double dbl_value;
|
||||
from_chars_result result;
|
||||
if (fmt == chars_format::hex)
|
||||
result = __floating_from_chars_hex(first, last, dbl_value);
|
||||
else
|
||||
{
|
||||
static_assert(USE_LIB_FAST_FLOAT);
|
||||
result = fast_float::from_chars(first, last, dbl_value, fmt);
|
||||
}
|
||||
if (result.ec == errc{})
|
||||
value = dbl_value;
|
||||
return result;
|
||||
#else
|
||||
errc ec = errc::invalid_argument;
|
||||
#if _GLIBCXX_USE_CXX11_ABI
|
||||
buffer_resource mr;
|
||||
pmr::string buf(&mr);
|
||||
#else
|
||||
string buf;
|
||||
if (!reserve_string(buf))
|
||||
return make_result(first, 0, {}, ec);
|
||||
#endif
|
||||
size_t len = 0;
|
||||
__try
|
||||
{
|
||||
if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
|
||||
len = from_chars_impl(pat, value, ec);
|
||||
}
|
||||
__catch (const std::bad_alloc&)
|
||||
{
|
||||
fmt = chars_format{};
|
||||
}
|
||||
return make_result(first, len, fmt, ec);
|
||||
return from_chars_strtod(first, last, value, fmt);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -918,20 +888,8 @@ from_chars_result
|
||||
from_chars(const char* first, const char* last, __ieee128& value,
|
||||
chars_format fmt) noexcept
|
||||
{
|
||||
buffer_resource mr;
|
||||
pmr::string buf(&mr);
|
||||
size_t len = 0;
|
||||
errc ec = errc::invalid_argument;
|
||||
__try
|
||||
{
|
||||
if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
|
||||
len = from_chars_impl(pat, value, ec);
|
||||
}
|
||||
__catch (const std::bad_alloc&)
|
||||
{
|
||||
fmt = chars_format{};
|
||||
}
|
||||
return make_result(first, len, fmt, ec);
|
||||
// fast_float doesn't support IEEE binary128 format, but we can use strtold.
|
||||
return from_chars_strtod(first, last, value, fmt);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user