On Thu, Jun 12, 2025 at 5:50 PM Jonathan Wakely <jwakely....@gmail.com> wrote:
> > > On Thu, 12 Jun 2025, 16:19 Tomasz Kamiński, <tkami...@redhat.com> wrote: > >> This patch change implementation of the formatters for sys_info and >> local_info, >> so they no longer delegate to operator<< for ostream in case of empty >> spec. >> As this types may be only formatted with chrono-spec containing only %%, >> %t, %n >> specifiers and fill characters, we use a separate __formatter_chrono_info >> formatter. >> >> For empty chron-spec __formatter_chrono_info formats sys_info using >> format_to call >> with format specifier extracted from corresponding operator<<, that now >> delegates >> to format with empty spec. For local_info we replicate functionality of >> the operator<<. >> The alignment and padding is handled using an _Padding_sink. >> >> For non-empty spec, we delegate to __formatter_chrono::_M_format. As >> non-of the >> format specifiers depends on the formatted object, we pass chrono::day to >> avoid >> triggering additional specializations. >> >> libstdc++-v3/ChangeLog: >> >> * include/bits/chrono_io.h (__format::__formatter_chrono_info): >> Define. >> (std::formatter<chrono::sys_info, _CharT>) >> (std::formatter<chrono::local_inf, _CharT>): Delegate to >> __format::__formatter_chrono_info. >> (std::operator<<(basic_ostream<_CharT, _Traits>& const >> sys_info&)): >> Use format on sys_info with empty format spec. >> --- >> Sending actual v2, with support for chrono-spec with whitespaces and >> non-value spec. Sorry for noise. >> > > OK, thanks > Formatter chrono needs to be guarded with if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI. Will fix that before committing. > > > >> >> libstdc++-v3/include/bits/chrono_io.h | 98 +++++++++++++++++++++++---- >> 1 file changed, 83 insertions(+), 15 deletions(-) >> >> diff --git a/libstdc++-v3/include/bits/chrono_io.h >> b/libstdc++-v3/include/bits/chrono_io.h >> index 247d40c82d7..5fa07364f64 100644 >> --- a/libstdc++-v3/include/bits/chrono_io.h >> +++ b/libstdc++-v3/include/bits/chrono_io.h >> @@ -1940,6 +1940,82 @@ namespace __format >> } >> }; >> >> + template<typename _CharT> >> + struct __formatter_chrono_info >> + { >> + constexpr typename basic_format_parse_context<_CharT>::iterator >> + parse(basic_format_parse_context<_CharT>& __pc) >> + { return _M_f._M_parse(__pc, _ChronoParts(), {}); } >> + >> + template<typename _Info, typename _Out> >> + typename basic_format_context<_Out, _CharT>::iterator >> + format(const _Info& __i, >> + basic_format_context<_Out, _CharT>& __fc) const >> + { >> + // n.b. only acceptable chrono-spec for info is one containing >> + // only whitespaces and %%, that do not depend on formatted >> object. >> + if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]] >> + return _M_f._M_format(chrono::day(1), __fc); >> + >> + const size_t __padwidth = _M_f._M_spec._M_get_width(__fc); >> + if (__padwidth == 0) >> + return _M_format_to(__fc.out(), __i); >> + >> + _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth); >> + _M_format_to(__sink.out(), __i); >> + return __sink._M_finish(_M_f._M_spec._M_align, >> _M_f._M_spec._M_fill); >> + } >> + >> + private: >> + template<typename _Out> >> + _Out >> + _M_format_to(_Out __out, const chrono::sys_info& __si) const >> + { >> + using _FmtStr = _Runtime_format_string<_CharT>; >> + // n.b. only decimal separator is locale dependent for >> specifiers >> + // used below, as sys_info uses seconds and minutes duration, >> the >> + // output is locale-independent. >> + constexpr auto* __fs >> + = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F >> %T},{2:%T},{3:%Q%q},{0:%Z}]"); >> + const chrono::local_seconds >> __lb(__si.begin.time_since_epoch()); >> + return std::format_to(std::move(__out), _FmtStr(__fs), >> + chrono::local_time_format(__lb, >> &__si.abbrev), >> + __si.end, __si.offset, __si.save); >> + } >> + >> + template<typename _Out> >> + _Out >> + _M_format_to(_Out __out, const chrono::local_info& __li) const >> + { >> + *__out = _Separators<_CharT>::_S_squares()[0]; >> + ++__out; >> + if (__li.result == chrono::local_info::unique) >> + __out = _M_format_to(std::move(__out), __li.first); >> + else >> + { >> + basic_string_view<_CharT> __sv; >> + if (__li.result == chrono::local_info::nonexistent) >> + __sv =_GLIBCXX_WIDEN("nonexistent"); >> + else >> + __sv = _GLIBCXX_WIDEN("ambiguous"); >> + __out = __format::__write(std::move(__out), __sv); >> + >> + __sv = _GLIBCXX_WIDEN(" local time between "); >> + __out = __format::__write(std::move(__out), __sv); >> + __out = _M_format_to(std::move(__out), __li.first); >> + >> + __sv = _GLIBCXX_WIDEN(" and "); >> + __out = __format::__write(std::move(__out), __sv); >> + __out = _M_format_to(std::move(__out), __li.second); >> + } >> + *__out = _Separators<_CharT>::_S_squares()[1]; >> + ++__out; >> + return std::move(__out); >> + } >> + >> + __formatter_chrono<_CharT> _M_f; >> + }; >> + >> } // namespace __format >> /// @endcond >> >> @@ -2430,16 +2506,16 @@ namespace __format >> { >> constexpr typename basic_format_parse_context<_CharT>::iterator >> parse(basic_format_parse_context<_CharT>& __pc) >> - { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } >> + { return _M_f.parse(__pc); } >> >> template<typename _Out> >> typename basic_format_context<_Out, _CharT>::iterator >> format(const chrono::sys_info& __i, >> basic_format_context<_Out, _CharT>& __fc) const >> - { return _M_f._M_format(__i, __fc); } >> + { return _M_f.format(__i, __fc); } >> >> private: >> - __format::__formatter_chrono<_CharT> _M_f; >> + __format::__formatter_chrono_info<_CharT> _M_f; >> }; >> >> template<__format::__char _CharT> >> @@ -2447,16 +2523,16 @@ namespace __format >> { >> constexpr typename basic_format_parse_context<_CharT>::iterator >> parse(basic_format_parse_context<_CharT>& __pc) >> - { return _M_f._M_parse(__pc, __format::_ChronoParts{}); } >> + { return _M_f.parse(__pc); } >> >> template<typename _Out> >> typename basic_format_context<_Out, _CharT>::iterator >> format(const chrono::local_info& __i, >> basic_format_context<_Out, _CharT>& __fc) const >> - { return _M_f._M_format(__i, __fc); } >> + { return _M_f.format(__i, __fc); } >> >> private: >> - __format::__formatter_chrono<_CharT> _M_f; >> + __format::__formatter_chrono_info<_CharT> _M_f; >> }; >> #endif >> >> @@ -3318,15 +3394,7 @@ namespace __detail >> basic_ostream<_CharT, _Traits>& >> operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __i) >> { >> - // n.b. only decimal separator is locale dependent for specifiers >> - // used below, as sys_info uses seconds and minutes duration, the >> - // output is locale-independent. >> - constexpr auto* __fs >> - = _GLIBCXX_WIDEN("[{0:%F %T},{1:%F %T},{2:%T},{3:%Q%q},{0:%Z}]"); >> - local_seconds __lb(__i.begin.time_since_epoch()); >> - __os << std::format(__fs, local_time_format(__lb, &__i.abbrev), >> - __i.end, __i.offset, __i.save); >> - return __os; >> + return __os << std::format(__os.getloc(), _GLIBCXX_WIDEN("{}"), >> __i); >> } >> >> /// Writes a local_info object to an ostream in an unspecified format. >> -- >> 2.49.0 >> >>