Re: [PATCH 3/4] libstdc++: Specialize _Iter_sink for ostreambuf_iterator
Tomasz Kaminski <[email protected]>
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.libstdc++.devel |
|---|---|
| Message-ID | <CAKvuMXAdXy=hwoD5y+Y6nMdrvNnReen1L43M1-qi_3uGuNqvdg@mail.gmail.com> |
On Thu, Jul 16, 2026 at 2:06 PM Anlai Lu <[email protected]> wrote: > Add partial specialization of _Iter_sink for ostreambuf_iterator > that inherits _Streambuf_sink, replacing per-character sputc with > bulk sputn and zero-copy put-area writes. > > All counting and truncation (_M_max) is handled in this > specialization so that _Streambuf_sink stays a pure I/O layer. > _M_overflow counts all characters and only writes up to the limit, > so format_to_n can compute the total output length. _M_discarding > returns false for the same reason. Stack writes go through > _M_out._M_put() which tracks failure on the iterator. sputn > exceptions are caught and the iterator is marked failed via > _M_set_failed(). > > The maximum count uses size_t with _S_no_limit sentinel, matching > the _Ptr_sink convention and avoiding signed comparisons. > > libstdc++-v3/ChangeLog: > > * include/std/format > (_Iter_sink<ostreambuf_iterator>): New partial specialization. > > Signed-off-by: Anlai Lu <[email protected]> > I will again posted updated patch addressing the comment below. > --- > libstdc++-v3/include/std/format | 67 +++++++++++++++++++++++++++++++++ > 1 file changed, 67 insertions(+) > > diff --git a/libstdc++-v3/include/std/format > b/libstdc++-v3/include/std/format > index b676629b1..63d12eff8 100644 > --- a/libstdc++-v3/include/std/format > +++ b/libstdc++-v3/include/std/format > @@ -3867,6 +3867,73 @@ namespace __format > } > }; > > + // Specialization replacing per-character sputc with bulk sputn > + // and zero-copy writes into the streambuf's put area. > + template<typename _CharT, typename _Traits> > + class _Iter_sink<_CharT, ostreambuf_iterator<_CharT, _Traits>> > + : public _Streambuf_sink<_CharT, _Traits> > + { > + using _Base = _Streambuf_sink<_CharT, _Traits>; > + using _OutIter = ostreambuf_iterator<_CharT, _Traits>; > + _OutIter _M_out; > + size_t _M_max; > + > + static constexpr size_t _S_no_limit = size_t(-1); > + > + protected: > + size_t _M_count = 0; > + > + _GLIBCXX_CONSTEXPR_FORMAT span<_CharT> > + _M_limit(span<_CharT> __s) > + { > + size_t __n = __s.size(); > + size_t __commit; > + if (_M_max == _S_no_limit) > + __commit = __n; > + else if (_M_count >= _M_max) > + __commit = 0; > + else > + __commit = min(__n, _M_max - _M_count); > + _M_count += __n; > + return __s.first(__commit); > + } > + > + _GLIBCXX_CONSTEXPR_FORMAT void > + _M_overflow() override > + { > + auto __s = this->_M_limit(this->_M_used()); > + this->_M_flush(__s); > + if (!this->_M_use_put_area()) > Here, if we we actuall use put_area we do not limit size of the buffer and thus may write into put_area more than n character, overriding existing ons. This leads to the failures in test_format_to_n_prefilled, once we configure put_area use on constructor (as mentioned in previous patch). A similar case may happen for reserve, where we provide a chunk of put_area that is larger then remaining characters we can write, thus overriding it. > + this->_M_use_stackbuf(); > + } > + > + _GLIBCXX_CONSTEXPR_FORMAT bool > + _M_discarding() const override > + { return false; } > + > + public: > + [[__gnu__::__always_inline__]] > + _GLIBCXX_CONSTEXPR_FORMAT explicit > + _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1) > + : _Base(__out._M_get_sbuf()), _M_out(__out), > + _M_max(__max < 0 ? _S_no_limit : size_t(__max)) > + { } > + > + using _Base::out; > + > + _GLIBCXX_CONSTEXPR_FORMAT format_to_n_result<_OutIter> > + _M_finish() && > + { > + auto __s = this->_M_limit(this->_M_used()); > + this->_M_flush(__s); > + > + if (this->_M_write_failed) > + _M_out._M_set_failed(); > + iter_difference_t<_OutIter> __count(_M_count); > + return { std::move(_M_out), __count }; > + } > + }; > + > // Used for contiguous iterators. > // No buffer is used, characters are written straight to the iterator. > // We do not know the size of the output range, so the span size just > grows > -- > 2.34.1 > >