[PATCH v2 3/4] libstdc++: Format empty chrono-spec for the sys_info and local_info directly.
Tomasz Kaminski
tkaminsk@redhat.com
Fri Jun 13 02:21:35 GMT 2025
On Thu, Jun 12, 2025 at 5:50 PM Jonathan Wakely <jwakely.gcc@gmail.com>
wrote:
>
>
> On Thu, 12 Jun 2025, 16:19 Tomasz Kamiński, <tkaminsk@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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250613/b17419bd/attachment.htm>
More information about the Libstdc++
mailing list