Formatting code is extracted to _M_format_to function, that produced output to specified iterator. This function is now invoked either with __fc.out() directly (if width is not specified) or _Padding_sink::out().
This avoid formatting to temporary string if no padding is requested, and minimize allocations otherwise. For more details see commit message of r16-142-g01e5ef3e8b91288f5d387a27708f9f8979a50edf. This should not increase number of instantiations, as implementation only produce basis_format_context with _Sink_iter as iterator, which is also _Padding_sink iterator. libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (__formatter_chrono::_M_format_to): Extracted from _M_format. (__formatter_chrono::_M_format): Use _Padding_sink and delegate to _M_format_to. --- I have checked that there are no other calls to out() in this file, so _M_format_to uses only __out, and not iterator from __fc. Testing on x86_64-linux. OK for trunk? libstdc++-v3/include/bits/chrono_io.h | 55 ++++++++++----------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 620227a9f35..ace8b9f2629 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -503,9 +503,7 @@ namespace __format _M_format(const _Tp& __t, _FormatContext& __fc, bool __is_neg = false) const { - auto __first = _M_spec._M_chrono_specs.begin(); - const auto __last = _M_spec._M_chrono_specs.end(); - if (__first == __last) + if (_M_spec._M_chrono_specs.empty()) return _M_format_to_ostream(__t, __fc, __is_neg); #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8 @@ -525,29 +523,29 @@ namespace __format __fc._M_loc = __with_encoding_conversion(__loc); } #endif - - _Sink_iter<_CharT> __out; - __format::_Str_sink<_CharT> __sink; - bool __write_direct = false; - if constexpr (is_same_v<typename _FormatContext::iterator, - _Sink_iter<_CharT>>) - { - if (_M_spec._M_width_kind == __format::_WP_none) - { - __out = __fc.out(); - __write_direct = true; - } - else - __out = __sink.out(); - } - else - __out = __sink.out(); - // formatter<duration> passes the correct value of __is_neg // for durations but for hh_mm_ss we decide it here. if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>) __is_neg = __t.is_negative(); + const size_t __padwidth = _M_spec._M_get_width(__fc); + if (__padwidth == 0) + return _M_format_to(__t, __fc.out(), __fc, __is_neg); + + using _Out = typename _FormatContext::iterator; + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth); + _M_format_to(__t, __sink.out(), __fc, __is_neg); + return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill); + } + + template<typename _Tp, typename _Out, typename _FormatContext> + _Out + _M_format_to(const _Tp& __t, _Out __out, _FormatContext& __fc, + bool __is_neg) const + { + auto __first = _M_spec._M_chrono_specs.begin(); + const auto __last = _M_spec._M_chrono_specs.end(); + auto __print_sign = [&__is_neg, &__out] { if constexpr (chrono::__is_duration_v<_Tp> || __is_specialization_of<_Tp, chrono::hh_mm_ss>) @@ -699,20 +697,7 @@ namespace __format } } while (__first != __last); - - if constexpr (is_same_v<typename _FormatContext::iterator, - _Sink_iter<_CharT>>) - if (__write_direct) - return __out; - - auto __str = __sink.view(); - size_t __width; - if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>()) - __width = __unicode::__field_width(__str); - else - __width = __str.size(); - return __format::__write_padded_as_spec(__str, __width, - __fc, _M_spec); + return std::move(__out); } _ChronoSpec<_CharT> _M_spec; -- 2.49.0