From: Patrick Palka <ppalka@redhat.com>
To: Jonathan Wakely <jwakely@redhat.com>
Cc: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org, ppalka@redhat.com
Subject: Re: [PATCH] libstdc++: Ensure that std::from_chars is declared when supported
Date: Mon, 14 Mar 2022 10:15:51 -0400 (EDT) [thread overview]
Message-ID: <d3a7cc04-b15a-0829-f2df-7935a2513818@idea> (raw)
In-Reply-To: <20220311183244.1861699-1-jwakely@redhat.com>
On Fri, 11 Mar 2022, Jonathan Wakely wrote:
> 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.
Don't we still depend on uselocale in GCC 12 for long double from_chars,
at least on targets where long double != binary64?
>
>
> -- >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
So ISTM we need to also check
_GLIBCXX_HAVE_USELOCALE || (__LDBL_MANT_DIG__ == __DBL_MANT_DIG__)
or something like that :/
> # 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);
I think __floating_from_chars_hex should work fine on 16 bit targets,
so I suppose we could use it in the !USE_LIB_FAST_FLOAT branch as well.
> #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 prev parent reply other threads:[~2022-03-14 14:15 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-11 18:32 Jonathan Wakely
2022-03-14 14:15 ` Patrick Palka [this message]
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=d3a7cc04-b15a-0829-f2df-7935a2513818@idea \
--to=ppalka@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jwakely@redhat.com \
--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).