Replace `os << std::format(...)` with `std::format_to(ostreambuf_iterator, ...)`
in chrono operator<< overloads.  This avoids creating a temporary std::string
for the formatted output, instead writing directly to the stream buffer.

This addresses the TODO in the chrono formatter about using format_to
instead of format for ostream insertion (PR libstdc++/111052).  When
combined with a subsequent _Iter_sink<ostreambuf_iterator> specialization,
this also benefits from zero-copy writing directly to the streambuf's
put area.

libstdc++-v3/ChangeLog:

        * include/bits/chrono_io.h (operator<<): Use format_to with
        ostreambuf_iterator instead of os << format.  Check for write
        failure and set badbit on the stream.

Signed-off-by: Anlai Lu <[email protected]>
---
 libstdc++-v3/include/bits/chrono_io.h | 102 +++++++++++++++++++++-----
 1 file changed, 83 insertions(+), 19 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h 
b/libstdc++-v3/include/bits/chrono_io.h
index f8bb485d1..2656bd9c4 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -3635,7 +3635,10 @@ namespace __detail
       if (__d.ok())
        __s = __s.substr(0, 6);
       auto __u = (unsigned)__d;
-      __os << std::vformat(__s, make_format_args<_Ctx>(__u));
+      auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                 __s, make_format_args<_Ctx>(__u));
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -3661,12 +3664,21 @@ namespace __detail
       using _Str = basic_string_view<_CharT>;
       _Str __s = _GLIBCXX_WIDEN("{:L%b}{} is not a valid month");
       if (__m.ok())
-       __os << std::vformat(__os.getloc(), __s.substr(0, 6),
-                            make_format_args<_Ctx>(__m));
+       {
+         auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                     __os.getloc(), __s.substr(0, 6),
+                                     make_format_args<_Ctx>(__m));
+         if (__it.failed())
+           __os.setstate(ios_base::badbit);
+       }
       else
        {
          auto __u = (unsigned)__m;
-         __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__u));
+         auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                     __s.substr(6),
+                                     make_format_args<_Ctx>(__u));
+         if (__it.failed())
+           __os.setstate(ios_base::badbit);
        }
       return __os;
     }
@@ -3699,7 +3711,11 @@ namespace __detail
        __s.remove_prefix(1);
       else
        __i = -__i;
-      __os << std::vformat(__s, make_format_args<_Ctx>(__i));
+      auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                 __s,
+                                 make_format_args<_Ctx>(__i));
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -3725,12 +3741,21 @@ namespace __detail
       using _Str = basic_string_view<_CharT>;
       _Str __s = _GLIBCXX_WIDEN("{:L%a}{} is not a valid weekday");
       if (__wd.ok())
-       __os << std::vformat(__os.getloc(), __s.substr(0, 6),
-                            make_format_args<_Ctx>(__wd));
+       {
+         auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                     __os.getloc(), __s.substr(0, 6),
+                                     make_format_args<_Ctx>(__wd));
+         if (__it.failed())
+           __os.setstate(ios_base::badbit);
+       }
       else
        {
          auto __c = __wd.c_encoding();
-         __os << std::vformat(__s.substr(6), make_format_args<_Ctx>(__c));
+         auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                     __s.substr(6),
+                                     make_format_args<_Ctx>(__c));
+         if (__it.failed())
+           __os.setstate(ios_base::badbit);
        }
       return __os;
     }
@@ -3764,7 +3789,10 @@ namespace __detail
       basic_string_view<_CharT> __s
        = _GLIBCXX_WIDEN("[ is not a valid index]");
       __os2 << __s[0];
-      __os2 << std::format(_GLIBCXX_WIDEN("{}"), __i);
+      auto __it_idx = std::format_to(std::ostreambuf_iterator<_CharT>(__os2),
+                                    _GLIBCXX_WIDEN("{}"), __i);
+      if (__it_idx.failed())
+       __os2.setstate(ios_base::badbit);
       if (__i >= 1 && __i <= 5)
        __os2 << __s.back();
       else
@@ -3909,8 +3937,11 @@ namespace __detail
       using _Ctx = __format::__format_context<_CharT>;
       using _Str = basic_string_view<_CharT>;
       _Str __s = _GLIBCXX_WIDEN("{:%F} is not a valid date");
-      __os << std::vformat(__ymd.ok() ? __s.substr(0, 5) : __s,
-                          make_format_args<_Ctx>(__ymd));
+      auto __it = std::vformat_to(std::ostreambuf_iterator<_CharT>(__os),
+                                 __ymd.ok() ? __s.substr(0, 5) : __s,
+                                 make_format_args<_Ctx>(__ymd));
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -3994,7 +4025,12 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const hh_mm_ss<_Duration>& __hms)
     {
-      return __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%T}"), __hms);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%T}"), __hms);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
+      return __os;
     }
 
 #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -4003,7 +4039,11 @@ namespace __detail
     basic_ostream<_CharT, _Traits>&
     operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i)
     {
-      return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(), _GLIBCXX_WIDEN("{}"), __i);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
+      return __os;
     }
 
   /// Writes a local_info object to an ostream in an unspecified format.
@@ -4033,7 +4073,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const zoned_time<_Duration, _TimeZonePtr>& __t)
     {
-      __os << format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T %Z}"), __t);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 #endif
@@ -4045,7 +4089,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const sys_time<_Duration>& __tp)
     {
-      __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T}"), __tp);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -4090,7 +4138,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const utc_time<_Duration>& __t)
     {
-      __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -4125,7 +4177,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const tai_time<_Duration>& __t)
     {
-      __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -4164,7 +4220,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const gps_time<_Duration>& __t)
     {
-      __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
@@ -4202,7 +4262,11 @@ namespace __detail
     operator<<(basic_ostream<_CharT, _Traits>& __os,
               const file_time<_Duration>& __t)
     {
-      __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      auto __it = std::format_to(std::ostreambuf_iterator<_CharT>(__os),
+                                __os.getloc(),
+                                _GLIBCXX_WIDEN("{:L%F %T}"), __t);
+      if (__it.failed())
+       __os.setstate(ios_base::badbit);
       return __os;
     }
 
-- 
2.34.1

Reply via email to