[gcc r13-8458] libstdc++: Simplify chrono::__units_suffix using std::format

Jonathan Wakely redi@gcc.gnu.org
Sat Mar 16 10:19:40 GMT 2024


https://gcc.gnu.org/g:de45abc4b2a0446f374254981b59a19e0c6eebae

commit r13-8458-gde45abc4b2a0446f374254981b59a19e0c6eebae
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Aug 15 16:35:22 2023 +0100

    libstdc++: Simplify chrono::__units_suffix using std::format
    
    For std::chrono formatting we can simplify __units_suffix by using
    std::format_to to generate the "[n/m]s" suffix with the correct
    character type and write directly to the output iterator, so it doesn't
    need to be widened using ctype. We can't remove the use of ctype::widen
    for formatting a time zone abbreviation as a wide string, because that
    can contain arbitrary characters that can't be widened by
    __to_wstring_numeric.
    
    This also fixes a bug in the chrono formatter for %Z which created a
    dangling wstring_view.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/chrono_io.h (__units_suffix_misc): Remove.
            (__units_suffix): Return a known suffix as string view, do not
            write unknown suffixes to a buffer.
            (__fmt_units_suffix): New function that formats the suffix using
            std::format_to.
            (operator<<, __chrono_formatter::_M_q): Use __fmt_units_suffix.
            (__chrono_formatter::_M_Z): Correct lifetime of wstring.
    
    (cherry picked from commit c992acdc6774ef3d566fab5f324d254bed1b9d4b)

Diff:
---
 libstdc++-v3/include/bits/chrono_io.h | 84 ++++++++++++-----------------------
 1 file changed, 29 insertions(+), 55 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index 1c08130bf65..1838ad1a8c6 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -38,7 +38,7 @@
 #include <iomanip> // setw, setfill
 #include <format>
 
-#include <bits/charconv.h>
+#include <bits/streambuf_iterator.h>
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -69,34 +69,9 @@ namespace __detail
 #define _GLIBCXX_WIDEN_(C, S) ::std::chrono::__detail::_Widen<C>(S, L##S)
 #define _GLIBCXX_WIDEN(S) _GLIBCXX_WIDEN_(_CharT, S)
 
-
-  // Write an arbitrary duration suffix into the buffer.
-  template<typename _Period>
-    constexpr const char*
-    __units_suffix_misc(char* __buf, size_t /* TODO check length? */) noexcept
-    {
-      namespace __tc = std::__detail;
-      char* __p = __buf;
-      __p[0] = '[';
-      unsigned __nlen = __tc::__to_chars_len((uintmax_t)_Period::num);
-      __tc::__to_chars_10_impl(__p + 1, __nlen, (uintmax_t)_Period::num);
-      __p += 1 + __nlen;
-      if constexpr (_Period::den != 1)
-	{
-	  __p[0] = '/';
-	  unsigned __dlen = __tc::__to_chars_len((uintmax_t)_Period::den);
-	  __tc::__to_chars_10_impl(__p + 1, __dlen, (uintmax_t)_Period::den);
-	  __p += 1 + __dlen;
-	}
-      __p[0] = ']';
-      __p[1] = 's';
-      __p[2] = '\0';
-      return __buf;
-    }
-
   template<typename _Period, typename _CharT>
-    constexpr auto
-    __units_suffix(char* __buf, size_t __n) noexcept
+    constexpr basic_string_view<_CharT>
+    __units_suffix() noexcept
     {
       // The standard say these are all narrow strings, which would need to
       // be widened at run-time when inserted into a wide stream. We use
@@ -134,7 +109,22 @@ namespace __detail
       _GLIBCXX_UNITS_SUFFIX(ratio<3600>,  "h")
       _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d")
 #undef _GLIBCXX_UNITS_SUFFIX
-      return __detail::__units_suffix_misc<_Period>(__buf, __n);
+	return {};
+    }
+
+  template<typename _Period, typename _CharT, typename _Out>
+    inline _Out
+    __fmt_units_suffix(_Out __out) noexcept
+    {
+      if (auto __s = __detail::__units_suffix<_Period, _CharT>(); __s.size())
+	return __format::__write(std::move(__out), __s);
+      else if constexpr (_Period::den == 1)
+	return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}]s"),
+			      (uintmax_t)_Period::num);
+      else
+	return std::format_to(std::move(__out), _GLIBCXX_WIDEN("[{}/{}]s"),
+			      (uintmax_t)_Period::num,
+			      (uintmax_t)_Period::den);
     }
 } // namespace __detail
 /// @endcond
@@ -149,14 +139,14 @@ namespace __detail
     operator<<(std::basic_ostream<_CharT, _Traits>& __os,
 	       const duration<_Rep, _Period>& __d)
     {
+      using _Out = ostreambuf_iterator<_CharT, _Traits>;
       using period = typename _Period::type;
-      char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
       std::basic_ostringstream<_CharT, _Traits> __s;
       __s.flags(__os.flags());
       __s.imbue(__os.getloc());
       __s.precision(__os.precision());
       __s << __d.count();
-      __s << __detail::__units_suffix<period, _CharT>(__buf, sizeof(__buf));
+      __detail::__fmt_units_suffix<period, _CharT>(_Out(__s));
       __os << std::move(__s).str();
       return __os;
     }
@@ -1074,32 +1064,16 @@ namespace __format
       template<typename _Tp, typename _FormatContext>
 	typename _FormatContext::iterator
 	_M_q(const _Tp&, typename _FormatContext::iterator __out,
-	     _FormatContext& __ctx) const
+	     _FormatContext&) const
 	{
 	  // %q The duration's unit suffix
 	  if constexpr (!chrono::__is_duration_v<_Tp>)
 	    __throw_format_error("format error: argument is not a duration");
 	  else
 	    {
+	      namespace __d = chrono::__detail;
 	      using period = typename _Tp::period;
-	      char __buf[sizeof("[/]s") + 2 * numeric_limits<intmax_t>::digits10];
-	      constexpr size_t __n = sizeof(__buf);
-	      auto __s = chrono::__detail::__units_suffix<period, _CharT>(__buf,
-									  __n);
-	      if constexpr (is_same_v<decltype(__s), const _CharT*>)
-		return std::format_to(std::move(__out), _S_empty_spec, __s);
-	      else
-		{
-		  // Suffix was written to __buf as narrow string.
-		  _CharT __wbuf[__n];
-		  size_t __len = __builtin_strlen(__buf);
-		  locale __loc = _M_locale(__ctx);
-		  auto& __ct = use_facet<ctype<_CharT>>(__loc);
-		  __ct.widen(__buf, __len, __wbuf);
-		  __wbuf[__len] = 0;
-		  return std::format_to(std::move(__out), _S_empty_spec,
-					__wbuf);
-		}
+	      return __d::__fmt_units_suffix<period, _CharT>(std::move(__out));
 	    }
 	}
 
@@ -1394,18 +1368,18 @@ namespace __format
 	    {
 	      if (__t._M_abbrev)
 		{
-		  __string_view __wsv;
+		  string_view __sv = *__t._M_abbrev;
 		  if constexpr (is_same_v<_CharT, char>)
-		    __wsv = *__t._M_abbrev;
+		    return __format::__write(std::move(__out), __sv);
 		  else
 		    {
-		      string_view __sv = *__t._M_abbrev;
+		      // TODO use resize_and_overwrite
 		      basic_string<_CharT> __ws(__sv.size(), _CharT());
 		      auto& __ct = use_facet<ctype<_CharT>>(_M_locale(__ctx));
 		      __ct.widen(__sv.begin(), __sv.end(), __ws.data());
-		      __wsv = __ws;
+		      __string_view __wsv = __ws;
+		      return __format::__write(std::move(__out), __wsv);
 		    }
-		  return __format::__write(std::move(__out), __wsv);
 		}
 	    }
 	  else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>)


More information about the Libstdc++-cvs mailing list