[PATCH] libstdc++: Format std::float16_t and std::bfloat16_t using respective std::to_chars overloads [PR126731]

Tomasz Kamiński <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel
Message-ID <[email protected]>
This patch removes the partial specialization for float16_t and bfloat16_t
that formatted the values by casting to float. In consequence an implicit
specialization of generic floating-point specialization is used, and
to_chars overloads for their types are used.
As explained in r13-3591-g0ae26533b3e268 (that adds corresponding to_chars
overload), the shortest string (produced when no precision is specified)
is shorter for above, than float.

As formatter specializations were defined under the same condition as
corresponding to_chars overloads, the __formattable_float constrain on
formatter floating-point specialization makes it enable in same cases.

This reverts parts of r14-3305-g6cf214b4fc97f5 (revereted partially
in r14-3329-g27d0cfcb2b33de), leading to (necessary for correctness)
increase of the number template specializations. It also depends on
preserving values of above types (instead of float) in basic_format_arg
introduced r16-616-g9c9a7316adb996.

The specializations for float32_t and float64_t are left unchanged,
as their to_chars overloads are also implemented in terms of casting
to float/double respectivelly.

libstdc++-v3/ChangeLog:

	PR libstdc++/126731
	* include/std/format (std::formatter<_Float16, _CharT>)
	(std::formatter<__format::__bflt16_t, _CharT>): Remove
	partial specializations.
	* testsuite/std/format/formatter/ext_float.cc: Test output
	for closest value to 1/10.
---
As far as I can tell this case will not be affected by P3505R4
"Fix the default floating-point representation in std::format",
as float(0.1f16) is 1.998p-4, while 0.1 f is 1.99999ap-4, so
only later could use 0.1 as shortest string.

Testing on x86_64-linux. *format* passed in all standard modes,
-m32, debug and assertions. OK for trunk and 16?
(We cannot backport it to eariel standards due dependency described
above).

 libstdc++-v3/include/std/format               | 44 -------------------
 .../std/format/formatter/ext_float.cc         | 22 ++++++----
 2 files changed, 13 insertions(+), 53 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 729cb89ec60..8d530e883c3 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -3003,28 +3003,6 @@ namespace __format
     };
 #endif
 
-#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
-  // Reuse __formatter_fp<C>::format<float, Out> for _Float16.
-  template<__format::__char _CharT>
-    struct formatter<_Float16, _CharT>
-    {
-      formatter() = default;
-
-      [[__gnu__::__always_inline__]]
-      constexpr typename basic_format_parse_context<_CharT>::iterator
-      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f.parse(__pc); }
-
-      template<typename _Out>
-	typename basic_format_context<_Out, _CharT>::iterator
-	format(_Float16 __u, basic_format_context<_Out, _CharT>& __fc) const
-	{ return _M_f.format((float)__u, __fc); }
-
-    private:
-      __format::__formatter_fp<_CharT> _M_f;
-    };
-#endif
-
 #if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
   // Reuse __formatter_fp<C>::format<float, Out> for _Float32.
   template<__format::__char _CharT>
@@ -3114,28 +3092,6 @@ namespace __format
     };
 #endif
 
-#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
-  // Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
-  template<__format::__char _CharT>
-    struct formatter<__format::__bflt16_t, _CharT>
-    {
-      formatter() = default;
-
-      [[__gnu__::__always_inline__]]
-      constexpr typename basic_format_parse_context<_CharT>::iterator
-      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f.parse(__pc); }
-
-      template<typename _Out>
-	typename basic_format_context<_Out, _CharT>::iterator
-	format(__gnu_cxx::__bfloat16_t __u,
-	       basic_format_context<_Out, _CharT>& __fc) const
-	{ return _M_f.format((float)__u, __fc); }
-
-    private:
-      __format::__formatter_fp<_CharT> _M_f;
-    };
-#endif
 #endif // __cpp_lib_to_chars
 
   /** Format a pointer.
diff --git a/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc b/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc
index 82e696fa797..7b231b07006 100644
--- a/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc
+++ b/libstdc++-v3/testsuite/std/format/formatter/ext_float.cc
@@ -4,10 +4,14 @@
 #include <testsuite_hooks.h>
 
 template<typename T>
-bool format_float()
+void
+verify_output()
 {
-    auto s = std::format("{:#} != {:<+7.3f}", (T)-0.0, (T)0.5);
-    return s == "-0. != +0.500 ";
+  auto s = std::format("{:#} != {:<+7.3f}", T(-0.0), T(0.5));
+  VERIFY( s == "-0. != +0.500 ");
+
+  s = std::format("{}", T(1)/T(10));
+  VERIFY( s == "0.1");
 }
 
 #if __cplusplus > 202002L
@@ -23,7 +27,7 @@ test_float16()
 {
 #if __FLT16_DIG__
   if constexpr (formattable<_Float16>)
-    VERIFY( format_float<_Float16>() );
+    verify_output<_Float16>();
   else
     std::puts("Cannot format _Float16 on this target");
 #endif
@@ -34,7 +38,7 @@ test_float32()
 {
 #if __FLT32_DIG__
   if constexpr (formattable<_Float32>)
-    VERIFY( format_float<_Float32>() );
+    verify_output<_Float32>();
   else
     std::puts("Cannot format _Float32 on this target");
 #endif
@@ -45,7 +49,7 @@ test_float64()
 {
 #if __FLT64_DIG__
   if constexpr (formattable<_Float64>)
-    VERIFY( format_float<_Float64>() );
+    verify_output<_Float64>();
   else
     std::puts("Cannot format _Float64 on this target");
 #endif
@@ -56,13 +60,13 @@ test_float128()
 {
 #ifdef __SIZEOF_FLOAT128__
   if constexpr (formattable<__float128>)
-    VERIFY( format_float<__float128>() );
+    verify_output<__float128>();
   else
     std::puts("Cannot format __float128 on this target");
 #endif
 #if __FLT128_DIG__
   if constexpr (formattable<_Float128>)
-    VERIFY( format_float<_Float128>() );
+    verify_output<_Float128>();
   else
     std::puts("Cannot format _Float128 on this target");
 #endif
@@ -75,7 +79,7 @@ test_bfloat16()
   using bfloat16_t = decltype(0.0bf16);
 
   if constexpr (formattable<bfloat16_t>)
-    VERIFY( format_float<bfloat16_t>() );
+    verify_output<bfloat16_t>();
   else
     std::puts("Cannot format bfloat16_t on this target");
 #endif
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.