From: Jonathan Wakely <jwakely@redhat.com>
To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
Subject: [PATCH] libstdc++: Ensure that std::from_chars is declared when supported
Date: Fri, 11 Mar 2022 18:32:44 +0000 [thread overview]
Message-ID: <20220311183244.1861699-1-jwakely@redhat.com> (raw)
Patrick, I think this is right, but please take a look to double check.
I think we should fix the feature-test macro conditions for gcc-11 too,
although it's a bit more complicated there. It should depend on IEEE
float and double *and* uselocale. We don't need the other changes on the
branch.
-- >8 --
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.
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.
---
libstdc++-v3/include/std/charconv | 8 +-
libstdc++-v3/include/std/version | 3 +-
libstdc++-v3/src/c++17/floating_from_chars.cc | 120 ++++++------------
3 files changed, 45 insertions(+), 86 deletions(-)
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index a3f8c7718b2..2ce9c7d4cb9 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -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.
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 461e65b5fab..d730a7ea3c7 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -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
diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc b/libstdc++-v3/src/c++17/floating_from_chars.cc
index ba0426b3344..4aa2483bc28 100644
--- a/libstdc++-v3/src/c++17/floating_from_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
@@ -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
--
2.34.1
next reply other threads:[~2022-03-11 18:32 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-11 18:32 Jonathan Wakely [this message]
2022-03-14 14:15 ` Patrick Palka
2022-03-14 21:15 ` Jonathan Wakely
2022-03-15 14:12 ` Patrick Palka
2022-03-16 16:26 ` Jonathan Wakely
2022-03-16 16:54 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220311183244.1861699-1-jwakely@redhat.com \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).