On 06/06/25 12:41 +0200, Tomasz Kamiński wrote:
In contrast to other calendar types if empty chron-spec is used for duration
"chron" -> "chrono"
we are required to format it (and it's representation type) via ostream.
"it's" -> "its"
Handling this case was now moved to be part of the format function for duration. To facilitate that __formatter_chrono::_M_format_to_ostream function was made public. However, for standard aritmetic types, we know the result of inserting them into ostream, and in consequence we can format them directly. This is handled by configuring default format spec to "%Q%q" for such types. As we no longer __formatter_chrono::_M_format with empty chrono-spec,
"no longer" -> "no longer use"
this functions now requires that _M_chrono_specs are not empty,
"functions" -> "function"
and onditional call to _M_format_to_ostream is removed. This allows
"onditional" -> "conditional"
_M_format_to_ostream to be reduced to accept only duration. libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (__formatter_chrono::_M_format): Remove handling of empty _M_chrono_specs. (__formatter_chrono::_M_format_to_ostream): Changed to accept only chrono::duration and made public. (std::formatter<chrono::duration<_Rep, _Period>, _CharT>): Configure __defSpec and handle empty chrono-spec locally.
This is OK for trunk, although I think you can't push it until the [PATCH 3/4] is in, so that _M_format_to_ostream isn't needed for the info types.
--- libstdc++-v3/include/bits/chrono_io.h | 88 ++++++++++++++------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index bbbae3d3064..d8744339094 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -614,14 +614,12 @@ namespace __format // that we instantiate fewer different specializations. Similar to // _Sink_iter for std::format. Replace each _S_year, _S_day etc. with // member functions of that type. + // pre: !_M_spec._M_chrono_specs.empty() template<typename _Tp, typename _FormatContext> typename _FormatContext::iterator _M_format(const _Tp& __t, _FormatContext& __fc, bool __is_neg = false) const { - 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 // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3565. Handling of encodings in localized formatting @@ -820,6 +818,24 @@ namespace __format return std::move(__out); } + // Format duration for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6). + template<typename _Rep, typename _Period, typename _FormatContext> + typename _FormatContext::iterator + _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d, + bool __is_neg, _FormatContext& __fc) const + { + basic_ostringstream<_CharT> __os; + __os.imbue(_M_locale(__fc)); + + if (__is_neg) [[unlikely]] + __os << _S_plus_minus[1]; + __os << __d; + + auto __str = std::move(__os).str(); + return __format::__write_padded_as_spec(__str, __str.size(), + __fc, _M_spec); + } + _ChronoSpec<_CharT> _M_spec; private: @@ -834,41 +850,6 @@ namespace __format return __fc.locale(); } - // Format for empty chrono-specs, e.g. "{}" (C++20 [time.format] p6). - // TODO: consider moving body of every operator<< into this function - // and use std::format("{}", t) to implement those operators. That - // would avoid std::format("{}", t) calling operator<< which calls - // std::format again. - template<typename _Tp, typename _FormatContext> - typename _FormatContext::iterator - _M_format_to_ostream(const _Tp& __t, _FormatContext& __fc, - bool __is_neg) const - { - using ::std::chrono::__detail::__utc_leap_second; - using ::std::chrono::__detail::__local_time_fmt; - - basic_ostringstream<_CharT> __os; - __os.imbue(_M_locale(__fc)); - - if constexpr (__is_specialization_of<_Tp, __local_time_fmt>) - __builtin_trap(); - else if constexpr (__is_specialization_of<_Tp, __utc_leap_second>) - __builtin_trap(); - else if constexpr (chrono::__is_time_point_v<_Tp>) - __builtin_trap(); - else - { - if constexpr (chrono::__is_duration_v<_Tp>) - if (__is_neg) [[unlikely]] - __os << _S_plus_minus[1]; - __os << __t; - } - - auto __str = std::move(__os).str(); - return __format::__write_padded_as_spec(__str, __str.size(), - __fc, _M_spec); - } - static constexpr const _CharT* _S_chars = _GLIBCXX_WIDEN("0123456789:/ +-{}"); static constexpr _CharT _S_colon = _S_chars[10]; @@ -2057,7 +2038,7 @@ namespace __format parse(basic_format_parse_context<_CharT>& __pc) { using namespace __format; - auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay); + auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay, __defSpec); if constexpr (!is_floating_point_v<_Rep>) if (_M_f._M_spec._M_prec_kind != __format::_WP_none) __throw_format_error("format error: invalid precision for duration"); @@ -2079,16 +2060,37 @@ namespace __format using _URep = make_unsigned_t<_Rep>; auto __ucnt = -static_cast<_URep>(__d.count()); auto __ud = chrono::duration<_URep, _Period>(__ucnt); - return _M_f._M_format(__ud, __fc, true); + return _M_format(__ud, true, __fc); } else - return _M_f._M_format(-__d, __fc, true); + return _M_format(-__d, true, __fc); } - return _M_f._M_format(__d, __fc, false); + return _M_format(__d, false, __fc); } private: - __format::__formatter_chrono<_CharT> _M_f; + static constexpr __format::_ChronoSpec<_CharT> __defSpec = [] + { + __format::_ChronoSpec<_CharT> __res{}; + __res._M_localized = !is_integral_v<_Rep>; + if constexpr (is_arithmetic_v<_Rep>) + __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q"); + return __res; + }(); + + template<typename _Rep2, typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + _M_format(const chrono::duration<_Rep2, _Period>& __d, + bool __is_neg, + basic_format_context<_Out, _CharT>& __fc) const + { + if constexpr (!is_arithmetic_v<_Rep>) + if (_M_f._M_spec._M_chrono_specs.empty()) + return _M_f._M_format_to_ostream(__d, __is_neg, __fc); + return _M_f._M_format(__d, __fc, __is_neg); + } + + __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; template<__format::__char _CharT> -- 2.49.0