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

commit r13-8458-gde45abc4b2a0446f374254981b59a19e0c6eebae
Author: Jonathan Wakely <jwak...@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>)

Reply via email to