On Thu, Jul 16, 2026 at 2:05 PM Anlai Lu <[email protected]> wrote:

> Use _Streambuf_sink directly in vprint_nonunicode instead of
> formatting to an intermediate string (_Str_sink) and then writing
> it to the stream.  This avoids the temporary string allocation and
> extra copy, and allows zero-copy writes into the streambuf's put
> area.
>
> I/O errors are tracked internally by _Streambuf_sink and reported
> after formatting completes via setstate(badbit), so that exceptions
> from vformat (format_error, bad_alloc) propagate without setting
> badbit, meeting [ostream.formatted.print]/(4.2).
>
Unfortunately, I have  realized that this is non-conforming, as it's
leads to differences in observable behavior, for example in the following
two cases: print(os, "{} {}", t, u)
- if t is formatted successfully but formatting
   of u throws, then standard requires no changes (we haven't created a
  string to print), but _Stream_sink may write representation of t
- if formatter of t or u prints to os direclty, the standard is clear that
  we get the direct output from formatters and then the result of the
format,
  but we may interleave
I will post updated patch 1/4 that adds above example./

I think this optimization is worthwhile, and maybe we could reuse
existing enable_nonlocking_formatter_optimziation to print direclty to
ostream (we require opt-in). But that requires changes to the standard.

Would be interested in working on standard proposal on such effect?


>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/ostream_print.h (vprint_nonunicode): Use
>         _Streambuf_sink instead of _Str_sink + __ostream_write.
>
> Signed-off-by: Anlai Lu <[email protected]>
> ---
>  libstdc++-v3/include/bits/ostream_print.h | 12 +++++-------
>  1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/ostream_print.h
> b/libstdc++-v3/include/bits/ostream_print.h
> index 0adf16d4f..4542bfcbf 100644
> --- a/libstdc++-v3/include/bits/ostream_print.h
> +++ b/libstdc++-v3/include/bits/ostream_print.h
> @@ -61,21 +61,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      ostream::sentry __cerb(__os);
>      if (__cerb)
>        {
> -       __format::_Str_sink<char> __buf;
> -       std::vformat_to(__buf.out(), __os.getloc(), __fmt, __args);
> -       auto __out = __buf.view();
> -
> +       __format::_Streambuf_sink<char> __sink(__os.rdbuf());
>         __try
>           {
> -           std::__ostream_write(__os, __out.data(), __out.size());
> +           std::vformat_to(__sink.out(), __os.getloc(), __fmt, __args);
> +           std::move(__sink)._M_finish();
>           }
>         __catch(const __cxxabiv1::__forced_unwind&)
>           {
>             __os._M_setstate(ios_base::badbit);
>             __throw_exception_again;
>           }
> -       __catch(...)
> -         { __os._M_setstate(ios_base::badbit); }
> +       if (__sink._M_failed())
> +         __os.setstate(ios_base::badbit);
>        }
>    }
>
> --
> 2.34.1
>
>

Reply via email to