On Mon, 29 Jun 2026 at 13:30, Anlai Lu <[email protected]> wrote:
>
> 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);

Why badbit and not failbit?

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

I think we want 'else' here ...

>        if (__i >= 1 && __i <= 5)
>         __os2 << __s.back();
>        else

And we probably want to set __os.setstate(failbit) on error, and not
try to write __os2.view() to __os. Just setting a failed state on
__os2 doesn't propagate any error to the caller.


> @@ -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