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



>
>  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
>
>

Reply via email to