public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-3300] libstdc++: Rework std::format support for wchar_t
@ 2023-08-17 20:30 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2023-08-17 20:30 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:023a62b77f999b002d4c56a94475684a4d209788

commit r14-3300-g023a62b77f999b002d4c56a94475684a4d209788
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Aug 15 16:35:22 2023 +0100

    libstdc++: Rework std::format support for wchar_t
    
    This changes how std::format creates wide strings, by replacing uses of
    std::ctype<wchar_t>::widen with the recently-added __to_wstring_numeric
    helper function. This removes the dependency on the locale, which should
    only be used for locale-specific formats such as {:Ld}.
    
    Also disable all the wide string formatting support if the
    _GLIBCXX_USE_WCHAR_T macro is not defined. This is consistent with other
    wchar_t support being disabled if the library is built without that
    macro defined.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/format [_GLIBCXX_USE_WCHAR_T]: Guard all wide
            string formatters with this macro.
            (__formatter_int::_M_format_int, __formatter_fp::format)
            (formatter<const void*, C>::format): Use __to_wstring_numeric
            instead of std::ctype::widen.
            (__formatter_fp::_M_localize): Use hardcoded wchar_t values
            instead of std::ctype::widen.
            * testsuite/std/format/functions/format.cc: Add more checks for
            wstring formatting of arithmetic types.

Diff:
---
 libstdc++-v3/include/std/format                    | 108 ++++++++++++++-------
 .../testsuite/std/format/functions/format.cc       |  10 ++
 2 files changed, 82 insertions(+), 36 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 0d7d3d164202..79f810acce36 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -79,8 +79,10 @@ namespace __format
 
   using format_context
     = basic_format_context<__format::_Sink_iter<char>, char>;
+#ifdef _GLIBCXX_USE_WCHAR_T
   using wformat_context
     = basic_format_context<__format::_Sink_iter<wchar_t>, wchar_t>;
+#endif
 
   // [format.args], class template basic_format_args
   template<typename _Context> class basic_format_args;
@@ -118,9 +120,11 @@ namespace __format
   template<typename... _Args>
     using format_string = basic_format_string<char, type_identity_t<_Args>...>;
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename... _Args>
     using wformat_string
       = basic_format_string<wchar_t, type_identity_t<_Args>...>;
+#endif
 
   // [format.formatter], formatter
 
@@ -181,7 +185,9 @@ namespace __format
   // [format.parse.ctx], class template basic_format_parse_context
   template<typename _CharT> class basic_format_parse_context;
   using format_parse_context = basic_format_parse_context<char>;
+#ifdef _GLIBCXX_USE_WCHAR_T
   using wformat_parse_context = basic_format_parse_context<wchar_t>;
+#endif
 
   template<typename _CharT>
     class basic_format_parse_context
@@ -745,8 +751,13 @@ namespace __format
     bool _M_hasval = false;
   };
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _CharT>
     concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>;
+#else
+  template<typename _CharT>
+    concept __char = same_as<_CharT, char>;
+#endif
 
   template<__char _CharT>
     struct __formatter_str
@@ -1125,26 +1136,20 @@ namespace __format
 	{
 	  size_t __width = _M_spec._M_get_width(__fc);
 
-	  _Optional_locale __loc;
-
 	  basic_string_view<_CharT> __str;
 	  if constexpr (is_same_v<char, _CharT>)
 	    __str = __narrow_str;
 	  else
 	    {
-	      __loc = __fc.locale();
-	      auto& __ct = use_facet<ctype<_CharT>>(__loc.value());
 	      size_t __n = __narrow_str.size();
 	      auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
-	      __ct.widen(__narrow_str.data(), __narrow_str.data() + __n, __p);
+	      __to_wstring_numeric(__narrow_str.data(), __n, __p);
 	      __str = {__p, __n};
 	    }
 
 	  if (_M_spec._M_localized)
 	    {
-	      if constexpr (is_same_v<char, _CharT>)
-		__loc = __fc.locale();
-	      const auto& __l = __loc.value();
+	      const auto& __l = __fc.locale();
 	      if (__l.name() != "C")
 		{
 		  auto& __np = use_facet<numpunct<_CharT>>(__l);
@@ -1612,35 +1617,19 @@ namespace __format
 		}
 	    }
 
-	  // TODO move everything below to a new member function that
-	  // doesn't depend on _Fp type.
-
-
-	  _Optional_locale __loc;
 	  basic_string<_CharT> __wstr;
 	  basic_string_view<_CharT> __str;
 	  if constexpr (is_same_v<_CharT, char>)
 	    __str = __narrow_str;
 	  else
 	    {
-	      __loc = __fc.locale();
-	      auto& __ct = use_facet<ctype<_CharT>>(__loc.value());
-	      const char* __data = __narrow_str.data();
-	      auto __overwrite = [&__data, &__ct](_CharT* __p, size_t __n)
-	      {
-		__ct.widen(__data, __data + __n, __p);
-		return __n;
-	      };
-	      _S_resize_and_overwrite(__wstr, __narrow_str.size(), __overwrite);
+	      __wstr = std::__to_wstring_numeric(__narrow_str);
 	      __str = __wstr;
 	    }
 
 	  if (_M_spec._M_localized)
 	    {
-	      if constexpr (is_same_v<char, _CharT>)
-		__wstr = _M_localize(__str, __expc, __fc.locale());
-	      else
-		__wstr = _M_localize(__str, __expc, __loc.value());
+	      __wstr = _M_localize(__str, __expc, __fc.locale());
 	      if (!__wstr.empty())
 		__str = __wstr;
 	    }
@@ -1697,9 +1686,24 @@ namespace __format
 	  }
 	else
 	  {
-	    const auto& __ct = use_facet<ctype<_CharT>>(__loc);
-	    __dot = __ct.widen('.');
-	    __exp = __ct.widen(__expc);
+	    __dot = L'.';
+	    switch (__expc)
+	    {
+	      case 'e':
+		__exp = L'e';
+		break;
+	      case 'E':
+		__exp = L'E';
+		break;
+	      case 'p':
+		__exp = L'p';
+		break;
+	      case 'P':
+		__exp = L'P';
+		break;
+	      default:
+		__builtin_unreachable();
+	    }
 	  }
 
 	if (__grp.empty() && __point == __dot)
@@ -1737,7 +1741,7 @@ namespace __format
 } // namespace __format
 /// @endcond
 
-  // Format a character.
+  /// Format a character.
   template<__format::__char _CharT>
     struct formatter<_CharT, _CharT>
     {
@@ -1774,7 +1778,8 @@ namespace __format
       __format::__formatter_int<_CharT> _M_f;
     };
 
-  // Format a char value for wide character output.
+#ifdef _GLIBCXX_USE_WCHAR_T
+  /// Format a char value for wide character output.
   template<>
     struct formatter<char, wchar_t>
     {
@@ -1808,6 +1813,7 @@ namespace __format
     private:
       __format::__formatter_int<wchar_t> _M_f;
     };
+#endif // USE_WCHAR_T
 
   /** Format a string.
    * @{
@@ -1903,6 +1909,7 @@ namespace __format
       __format::__formatter_str<char> _M_f;
     };
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Traits, typename _Alloc>
     struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t>
     {
@@ -1926,6 +1933,7 @@ namespace __format
     private:
       __format::__formatter_str<wchar_t> _M_f;
     };
+#endif // USE_WCHAR_T
 
   template<typename _Traits>
     struct formatter<basic_string_view<char, _Traits>, char>
@@ -1951,6 +1959,7 @@ namespace __format
       __format::__formatter_str<char> _M_f;
     };
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Traits>
     struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t>
     {
@@ -1974,6 +1983,7 @@ namespace __format
     private:
       __format::__formatter_str<wchar_t> _M_f;
     };
+#endif // USE_WCHAR_T
   /// @}
 
   /// Format an integer.
@@ -2144,10 +2154,8 @@ namespace __format
 	    __str = string_view(__buf, __n);
 	  else
 	    {
-	      const std::locale& __loc = __fc.locale();
-	      auto& __ct = use_facet<ctype<_CharT>>(__loc);
 	      auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
-	      __ct.widen(__buf, __buf + __n, __p);
+	      __to_wstring_numeric(__buf, __n, __p);
 	      __str = wstring_view(__p, __n);
 	    }
 
@@ -3698,25 +3706,33 @@ namespace __format
     vformat_to(_Out __out, string_view __fmt, format_args __args)
     { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out> requires output_iterator<_Out, const wchar_t&>
     [[__gnu__::__always_inline__]]
     inline _Out
     vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
     { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
+#endif
 
   template<typename _Out> requires output_iterator<_Out, const char&>
     [[__gnu__::__always_inline__]]
     inline _Out
     vformat_to(_Out __out, const locale& __loc, string_view __fmt,
 	       format_args __args)
-    { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); }
+    {
+      return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
+    }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out> requires output_iterator<_Out, const wchar_t&>
     [[__gnu__::__always_inline__]]
     inline _Out
     vformat_to(_Out __out, const locale& __loc, wstring_view __fmt,
 	       wformat_args __args)
-    { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); }
+    {
+      return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc);
+    }
+#endif
 
   [[nodiscard]]
   inline string
@@ -3727,6 +3743,7 @@ namespace __format
     return std::move(__buf).get();
   }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   [[nodiscard]]
   inline wstring
   vformat(wstring_view __fmt, wformat_args __args)
@@ -3735,6 +3752,7 @@ namespace __format
     std::vformat_to(__buf.out(), __fmt, __args);
     return std::move(__buf).get();
   }
+#endif
 
   [[nodiscard]]
   inline string
@@ -3745,6 +3763,7 @@ namespace __format
     return std::move(__buf).get();
   }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   [[nodiscard]]
   inline wstring
   vformat(const locale& __loc, wstring_view __fmt, wformat_args __args)
@@ -3753,6 +3772,7 @@ namespace __format
     std::vformat_to(__buf.out(), __loc, __fmt, __args);
     return std::move(__buf).get();
   }
+#endif
 
   template<typename... _Args>
     [[nodiscard]]
@@ -3760,11 +3780,13 @@ namespace __format
     format(format_string<_Args...> __fmt, _Args&&... __args)
     { return std::vformat(__fmt.get(), std::make_format_args(__args...)); }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename... _Args>
     [[nodiscard]]
     inline wstring
     format(wformat_string<_Args...> __fmt, _Args&&... __args)
     { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); }
+#endif
 
   template<typename... _Args>
     [[nodiscard]]
@@ -3776,6 +3798,7 @@ namespace __format
 			  std::make_format_args(__args...));
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename... _Args>
     [[nodiscard]]
     inline wstring
@@ -3785,6 +3808,7 @@ namespace __format
       return std::vformat(__loc, __fmt.get(),
 			  std::make_wformat_args(__args...));
     }
+#endif
 
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const char&>
@@ -3795,6 +3819,7 @@ namespace __format
 			     std::make_format_args(std::forward<_Args>(__args)...));
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const wchar_t&>
     inline _Out
@@ -3803,6 +3828,7 @@ namespace __format
       return std::vformat_to(std::move(__out), __fmt.get(),
 			     std::make_wformat_args(std::forward<_Args>(__args)...));
     }
+#endif
 
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const char&>
@@ -3814,6 +3840,7 @@ namespace __format
 			     std::make_format_args(std::forward<_Args>(__args)...));
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const wchar_t&>
     inline _Out
@@ -3823,6 +3850,7 @@ namespace __format
       return std::vformat_to(std::move(__out), __loc, __fmt.get(),
 			     std::make_wformat_args(std::forward<_Args>(__args)...));
     }
+#endif
 
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const char&>
@@ -3836,6 +3864,7 @@ namespace __format
       return std::move(__sink)._M_finish();
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const wchar_t&>
     inline format_to_n_result<_Out>
@@ -3847,6 +3876,7 @@ namespace __format
 		      std::make_wformat_args(__args...));
       return std::move(__sink)._M_finish();
     }
+#endif
 
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const char&>
@@ -3860,6 +3890,7 @@ namespace __format
       return std::move(__sink)._M_finish();
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename _Out, typename... _Args>
     requires output_iterator<_Out, const wchar_t&>
     inline format_to_n_result<_Out>
@@ -3871,6 +3902,7 @@ namespace __format
 		      std::make_wformat_args(__args...));
       return std::move(__sink)._M_finish();
     }
+#endif
 
 /// @cond undocumented
 namespace __format
@@ -3927,6 +3959,7 @@ namespace __format
       return __buf.count();
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename... _Args>
     [[nodiscard]]
     inline size_t
@@ -3937,6 +3970,7 @@ namespace __format
 		      std::make_wformat_args(std::forward<_Args>(__args)...));
       return __buf.count();
     }
+#endif
 
   template<typename... _Args>
     [[nodiscard]]
@@ -3950,6 +3984,7 @@ namespace __format
       return __buf.count();
     }
 
+#ifdef _GLIBCXX_USE_WCHAR_T
   template<typename... _Args>
     [[nodiscard]]
     inline size_t
@@ -3961,6 +3996,7 @@ namespace __format
 		      std::make_wformat_args(std::forward<_Args>(__args)...));
       return __buf.count();
     }
+#endif
 
 #if __cpp_lib_format_ranges
   // [format.range], formatting of ranges
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 59ed3be8baa3..59d327fccee1 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -274,6 +274,16 @@ test_wchar()
   VERIFY( s == L"0.0625" );
   s = std::format(L"{}", 0.25);
   VERIFY( s == L"0.25" );
+  s = std::format(L"{:+a} {:A}", 0x1.23p45, -0x1.abcdefp-15);
+  VERIFY( s == L"+1.23p+45 -1.ABCDEFP-15" );
+
+  double inf = std::numeric_limits<double>::infinity();
+  double nan = std::numeric_limits<double>::quiet_NaN();
+  s = std::format(L"{0} {0:F} {1} {1:E}", -inf, -nan);
+  VERIFY( s == L"-inf -INF -nan -NAN" );
+
+  s = std::format(L"{0:#b} {0:#B} {0:#x} {0:#X}", 99);
+  VERIFY( s == L"0b1100011 0B1100011 0x63 0X63" );
 }
 
 void

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-08-17 20:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17 20:30 [gcc r14-3300] libstdc++: Rework std::format support for wchar_t Jonathan Wakely

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).