This patch provides an equality operator between _Sink_iter and default_sentinel, that returns true, if any further writes to the _Sink_iter and underlying _Sink, will be discared, and thus can be omitted. This operator is implemented in terms new of _M_discarding virtual function in _Sink.
Currently only the _Padding_sink reports discarding mode of if width of sequence characters is greater than _M_maxwidth (precision), or underlying _Sink is discarding characters. The _M_discarding override, is separate function from _M_ignoring, that remain annotated with [[__gnu__::__always_inline__]]. Despite having notion of maximum characters to be written (_M_max), _Iter_sink nevers discard characters, as the total number of characters that would be written needs to be returned by format_to_n. This is documented in-source by providing an _Iter_sink::_M_discarding override, that always returns false. The function is currently queried only by the _Padding_sinks, that may be stacked for example a range is formatted, with padding with being specified both for range itself and it's elements. The state of underlying sink is checked during construction and after each write (_M_sync_discarding). libstdc++-v3/ChangeLog: * include/std/format (__Sink_iter<_CharT>::operator==) (__Sink<_CharT>::_M_discarding, _Iter_sink<_CharT, _OutIter>::_M_discarding) (_Padding_sinl<_CharT, _Out>::_M_padwidth) (_Padding_sink<_CharT, _Out>::_M_maxwidth): Remove const. (_Padding_sink<_CharT, _Out>::_M_sync_discarding) (_Padding_sink<_CharT, _Out>::_M_discarding): Define. (_Padding_sink<_CharT, _Out>::_Padding_sink(_Out, size_t, size_tt)) (_Padding_sink<_CharT, _Out>::_M_force_update): (_Padding_sink<_CharT, _Out>::_M_flush): Call _M_sync_discarding. (_Padding_sink<_CharT, _Out>::_Padding_sink(_Out, size_t)): Delegate. --- libstdc++-v3/include/std/format | 66 +++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 054ce350440..08a28fc92da 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -3144,6 +3144,10 @@ namespace __format auto _M_reserve(size_t __n) const { return _M_sink->_M_reserve(__n); } + + friend bool + operator==(_Sink_iter __it, default_sentinel_t) + { return __it._M_sink->_M_discarding(); } }; // Abstract base class for type-erased character sinks. @@ -3263,6 +3267,11 @@ namespace __format _M_bump(size_t __n) { _M_next += __n; } + // Returns true if the _Sink is discarding incoming characters. + virtual bool + _M_discarding() const + { return false; } + public: _Sink(const _Sink&) = delete; _Sink& operator=(const _Sink&) = delete; @@ -3488,6 +3497,15 @@ namespace __format _M_count += __s.size(); } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // thus we need to see and all characters. + // see https://eel.is/c%2B%2Bdraft/format#functions-22 + return false; + } + public: [[__gnu__::__always_inline__]] explicit @@ -3550,6 +3568,15 @@ namespace __format } } + bool + _M_discarding() const override + { + // format_to_n return total number of characters, that would be written, + // thus we need to see and all characters. + // see https://eel.is/c%2B%2Bdraft/format#functions-22 + return false; + } + typename _Sink<_CharT>::_Reservation _M_reserve(size_t __n) final { @@ -3636,17 +3663,15 @@ namespace __format template<typename _Out, typename _CharT> class _Padding_sink : public _Str_sink<_CharT> { - const size_t _M_padwidth; - const size_t _M_maxwidth; + size_t _M_padwidth; + size_t _M_maxwidth; _Out _M_out; size_t _M_printwidth; [[__gnu__::__always_inline__]] bool _M_ignoring() const - { - return _M_printwidth >= _M_maxwidth; - } + { return _M_printwidth >= _M_maxwidth; } [[__gnu__::__always_inline__]] bool @@ -3659,12 +3684,21 @@ namespace __format return false; } + void + _M_sync_discarding() + { + if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>) + if (_M_out == default_sentinel) + _M_maxwidth = _M_printwidth; + } + void _M_flush() { span<_CharT> __new = this->_M_used(); basic_string_view<_CharT> __str(__new.data(), __new.size()); _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); this->_M_rewind(); } @@ -3682,7 +3716,10 @@ namespace __format // We have more characters than padidng, no padding is needed, // write direclty to _M_out. if (_M_printwidth >= _M_padwidth) - _M_out = __format::__write(std::move(_M_out), __str); + { + _M_out = __format::__write(std::move(_M_out), __str); + _M_sync_discarding(); + } // We reached _M_maxwidth that is smaller than _M_padwidth. // Store the prefix sequence in _M_seq, and free _M_buf. else @@ -3718,6 +3755,10 @@ namespace __format _Str_sink<_CharT>::_M_overflow(); } + bool + _M_discarding() const override + { return _M_ignoring(); } + typename _Sink<_CharT>::_Reservation _M_reserve(size_t __n) override { @@ -3752,15 +3793,16 @@ namespace __format public: [[__gnu__::__always_inline__]] - explicit _Padding_sink(_Out __out, size_t __padwidth) - : _M_padwidth(__padwidth), _M_maxwidth(-1), + explicit + _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth) + : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth), _M_out(std::move(__out)), _M_printwidth(0) - { } + { _M_sync_discarding(); } [[__gnu__::__always_inline__]] - explicit _Padding_sink(_Out __out, size_t __padwidth, size_t __maxwidth) - : _M_padwidth(__padwidth), _M_maxwidth(__maxwidth), - _M_out(std::move(__out)), _M_printwidth(0) + explicit + _Padding_sink(_Out __out, size_t __padwidth) + : _Padding_sink(std::move(__out), __padwidth, (size_t)-1) { } _Out -- 2.49.0