On Wed, 4 Jun 2025, 10:27 Tomasz Kamiński, <tkami...@redhat.com> wrote:

> This patches fixes an obvious error, where the output iterator argument was
> missing for call to format_to, when duration with custom representation
> types
> are used.
>
> It's also adding the test for behavior of ostream operator and the
> formatting
> with empty chron-spec for the chrono types. Current coverage is:
>  * duration and hh_mm_ss in this commit,
>  * calendar types in r16-1016-g28a17985dd34b7.
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/chrono_io.h (__formatter_chrono:_M_s): Add missing
>         __out argument to format_to call.
>         * testsuite/std/time/format/empty_spec.cc: New test.
> ---
> Tested on x86_64-linux. OK for trunk?
>

OK, thanks.

The fix for the missing argument should be backported too.



>  libstdc++-v3/include/bits/chrono_io.h         |   3 +-
>  .../testsuite/std/time/format/empty_spec.cc   | 271 ++++++++++++++++++
>  2 files changed, 273 insertions(+), 1 deletion(-)
>
> diff --git a/libstdc++-v3/include/bits/chrono_io.h
> b/libstdc++-v3/include/bits/chrono_io.h
> index 346eb8b3c33..239f9c78009 100644
> --- a/libstdc++-v3/include/bits/chrono_io.h
> +++ b/libstdc++-v3/include/bits/chrono_io.h
> @@ -1296,7 +1296,8 @@ namespace __format
>                   else
>                     {
>                       auto __str = std::format(_S_empty_spec,
> __ss.count());
> -                     __out = std::format_to(_GLIBCXX_WIDEN("{:0>{}s}"),
> +                     __out = std::format_to(std::move(__out),
> +                                            _GLIBCXX_WIDEN("{:0>{}s}"),
>                                              __str,
>                                              __hms.fractional_width);
>                     }
> diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
> b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
> index 322faa1939d..46942dc30fc 100644
> --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
> +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
> @@ -1,7 +1,9 @@
>  // { dg-do run { target c++20 } }
> +// { dg-require-effective-target hosted }
>  // { dg-timeout-factor 2 }
>
>  #include <chrono>
> +#include <ranges>
>  #include <sstream>
>  #include <testsuite_hooks.h>
>
> @@ -49,6 +51,274 @@ void verify(const T& t, const _CharT* str)
>    VERIFY( res == str );
>  }
>
> +template<typename Ret = void>
> +struct Rep
> +{
> +  using Return
> +    = std::conditional_t<std::is_void_v<Ret>, Rep, Ret>;
> +
> +  Rep(long v = 0) : val(v) {}
> +
> +  operator long() const
> +  { return val; }
> +
> +  Return
> +  operator+() const
> +  { return val; }
> +
> +  Rep
> +  operator-() const
> +  { return -val; }
> +
> +  friend Rep
> +  operator+(Rep lhs, Rep rhs)
> +  { return lhs.val + rhs.val; }
> +
> +  friend Rep
> +  operator-(Rep lhs, Rep rhs)
> +  { return lhs.val - rhs.val; }
> +
> +  friend Rep
> +  operator*(Rep lhs, Rep rhs)
> +  { return lhs.val * rhs.val; }
> +
> +  friend Rep
> +  operator/(Rep lhs, Rep rhs)
> +  { return lhs.val / rhs.val; }
> +
> +  friend auto operator<=>(Rep, Rep) = default;
> +
> +  template<typename _CharT>
> +  friend std::basic_ostream<_CharT>&
> +  operator<<(std::basic_ostream<_CharT>& os, const Rep& t)
> +  { return os << t.val << WIDEN("[via <<]"); }
> +
> +  long val;
> +};
> +
> +template<typename Ret, typename Other>
> +  requires std::is_integral_v<Other>
> +struct std::common_type<Rep<Ret>, Other>
> +{
> +  using type = Rep<Ret>;
> +};
> +
> +template<typename Ret, typename Other>
> +  requires std::is_integral_v<Other>
> +struct std::common_type<Other, Rep<Ret>>
> +  : std::common_type<Rep<Ret>, Other>
> +{ };
> +
> +template<typename Ret>
> +struct std::numeric_limits<Rep<Ret>>
> +  : std::numeric_limits<long>
> +{ };
> +
> +template<typename Ret, typename _CharT>
> +struct std::formatter<Rep<Ret>, _CharT>
> +  : std::formatter<long, _CharT>
> +{
> +  template<typename Out>
> +  typename std::basic_format_context<Out, _CharT>::iterator
> +  format(const Rep<Ret>& t, std::basic_format_context<Out, _CharT>& ctx)
> const
> +  {
> +    constexpr std::basic_string_view<_CharT> suffix = WIDEN("[via
> format]");
> +    auto out = std::formatter<long, _CharT>::format(t.val, ctx);
> +    return std::ranges::copy(suffix, out).out;
> +  }
> +};
> +
> +using deciseconds = duration<seconds::rep, std::deci>;
> +
> +template<typename _CharT>
> +void
> +test_duration()
> +{
> +  std::basic_string<_CharT> res;
> +
> +  const milliseconds di(40);
> +  verify( di, WIDEN("40ms") );
> +  res = std::format(WIDEN("{:>6}"), di);
> +  VERIFY( res == WIDEN("  40ms") );
> +
> +  verify( -di, WIDEN("-40ms") );
> +  res = std::format(WIDEN("{:>6}"), -di);
> +  VERIFY( res == WIDEN(" -40ms") );
> +
> +  const duration<double> df(11.22);
> +  verify( df, WIDEN("11.22s") );
> +  res = std::format(WIDEN("{:=^12}"), df);
> +  VERIFY( res == WIDEN("===11.22s===") );
> +
> +  verify( -df, WIDEN("-11.22s") );
> +  res = std::format(WIDEN("{:=^12}"), -df);
> +  VERIFY( res == WIDEN("==-11.22s===") );
> +}
> +
> +template<typename _CharT>
> +void
> +test_duration_cust()
> +{
> +  std::basic_string<_CharT> res;
> +  const duration<char, std::ratio<1, 10>> charRep(123);
> +  verify( charRep, WIDEN("123ds") );
> +
> +  // +asLong returns long, so formatted as long
> +  const duration<Rep<long>> asLong(20);
> +  verify( asLong, WIDEN("20s") );
> +  res = std::format(WIDEN("{:>6}"), asLong);
> +  VERIFY( res == WIDEN("   20s") );
> +
> +  verify( -asLong, WIDEN("-20s") );
> +  res = std::format(WIDEN("{:>6}"), -asLong);
> +  VERIFY( res == WIDEN("  -20s") );
> +
> +  res = std::format(WIDEN("{:%Q}"), asLong);
> +  VERIFY( res == WIDEN("20") );
> +  res = std::format(WIDEN("{:+<7%Q}"), asLong);
> +  VERIFY( res == WIDEN("20+++++") );
> +
> +  // +asRep returns Rep<>, so formatted as Rep<>
> +  const duration<Rep<>> asRep(10);
> +  verify( asRep, WIDEN("10[via <<]s") );
> +  res = std::format(WIDEN("{:=^15}"), asRep);
> +  VERIFY( res == WIDEN("==10[via <<]s==") );
> +
> +  verify( -asRep, WIDEN("-10[via <<]s") );
> +  res = std::format(WIDEN("{:=^15}"), -asRep);
> +  VERIFY( res == WIDEN("=-10[via <<]s==") );
> +
> +  res = std::format(WIDEN("{:%Q}"), asRep);
> +  VERIFY( res == WIDEN("10[via format]") );
> +  res = std::format(WIDEN("{:=^18%Q}"), asRep);
> +  VERIFY( res == WIDEN("==10[via format]==") );
> +
> +  const duration<Rep<>, std::milli> milliRep(10);
> +  verify( milliRep, WIDEN("10[via <<]ms") );
> +  res = std::format(WIDEN("{:=^15}"), milliRep);
> +  VERIFY( res == WIDEN("=10[via <<]ms==") );
> +
> +  verify( -milliRep, WIDEN("-10[via <<]ms") );
> +  res = std::format(WIDEN("{:=^15}"), -milliRep);
> +  VERIFY( res == WIDEN("=-10[via <<]ms=") );
> +
> +  res = std::format(WIDEN("{:%Q}"), milliRep);
> +  VERIFY( res == WIDEN("10[via format]") );
> +  res = std::format(WIDEN("{:=^18%Q}"), milliRep);
> +  VERIFY( res == WIDEN("==10[via format]==") );
> +}
> +
> +template<typename Ratio, typename Rep, typename Period>
> +constexpr auto
> +hms(const duration<Rep, Period>& d)
> +{
> +  using Dur = duration<Rep, typename Ratio::period>;
> +  return hh_mm_ss<Dur>(duration_cast<Dur>(d));
> +}
> +
> +template<typename _CharT>
> +void
> +test_hh_mm_ss()
> +{
> +  auto dt = 22h + 24min + 54s + 111222333ns;
> +  verify( hms<nanoseconds>(dt),
> +         WIDEN("22:24:54.111222333") );
> +  verify( hms<microseconds>(dt),
> +         WIDEN("22:24:54.111222") );
> +  verify( hms<milliseconds>(dt),
> +         WIDEN("22:24:54.111") );
> +  verify( hms<deciseconds>(dt),
> +         WIDEN("22:24:54.1") );
> +  verify( hms<seconds>(dt),
> +         WIDEN("22:24:54") );
> +  verify( hms<minutes>(dt),
> +         WIDEN("22:24:00") );
> +  verify( hms<hours>(dt),
> +         WIDEN("22:00:00") );
> +  verify( hms<nanoseconds>(-dt),
> +         WIDEN("-22:24:54.111222333") );
> +  verify( hms<microseconds>(-dt),
> +         WIDEN("-22:24:54.111222") );
> +  verify( hms<milliseconds>(-dt),
> +         WIDEN("-22:24:54.111") );
> +  verify( hms<deciseconds>(-dt),
> +         WIDEN("-22:24:54.1") );
> +  verify( hms<seconds>(-dt),
> +         WIDEN("-22:24:54") );
> +  verify( hms<minutes>(-dt),
> +         WIDEN("-22:24:00") );
> +  verify( hms<hours>(-dt),
> +         WIDEN("-22:00:00") );
> +
> +  verify( hms<nanoseconds>(-dt),
> +         WIDEN("-22:24:54.111222333") );
> +
> +  dt += 300h;
> +  verify( hms<nanoseconds>(dt),
> +         WIDEN("322:24:54.111222333") );
> +  verify( hms<nanoseconds>(-dt),
> +         WIDEN("-322:24:54.111222333") );
> +
> +  dt += 14000h;
> +  verify( hms<nanoseconds>(dt),
> +         WIDEN("14322:24:54.111222333") );
> +  verify( hms<nanoseconds>(-dt),
> +         WIDEN("-14322:24:54.111222333") );
> +}
> +
> +template<typename _CharT>
> +void
> +test_hh_mm_ss_cust()
> +{
> +  const duration<char, deciseconds::period> charRep(123);
> +  verify( hms<deciseconds>(charRep),
> +         WIDEN("00:00:12.3") );
> +  verify( hms<seconds>(charRep),
> +         WIDEN("00:00:12") );
> +
> +  auto dt = 22h + 24min + 54s + 123ms;
> +  // +plus returns long, so formatted as long
> +  const duration<Rep<long>, std::milli> asLong(dt.count());
> +  verify( hms<milliseconds>(asLong),
> +         WIDEN("22:24:54.123[via format]") );
> +  verify( hms<deciseconds>(asLong),
> +         WIDEN("22:24:54.1[via format]") );
> +  verify( hms<seconds>(asLong),
> +         WIDEN("22:24:54") );
> +  verify( hms<milliseconds>(-asLong),
> +         WIDEN("-22:24:54.123[via format]") );
> +  verify( hms<deciseconds>(-asLong),
> +         WIDEN("-22:24:54.1[via format]") );
> +  verify( hms<seconds>(-asLong),
> +         WIDEN("-22:24:54") );
> +
> +  // +asRep returns Rep<>, so formatted as Rep<>
> +  const duration<Rep<>, std::milli> asRep(dt.count());
> +  verify( hms<milliseconds>(asRep),
> +         WIDEN("22:24:54.123[via format]") );
> +  verify( hms<deciseconds>(asRep),
> +         WIDEN("22:24:54.1[via format]") );
> +  verify( hms<seconds>(asLong),
> +         WIDEN("22:24:54") );
> +  verify( hms<milliseconds>(-asLong),
> +         WIDEN("-22:24:54.123[via format]") );
> +  verify( hms<deciseconds>(-asLong),
> +         WIDEN("-22:24:54.1[via format]") );
> +  verify( hms<seconds>(-asLong),
> +         WIDEN("-22:24:54") );
> +}
> +
> +template<typename CharT>
> +void
> +test_durations()
> +{
> +  test_duration<CharT>();
> +  test_duration_cust<CharT>();
> +
> +  test_hh_mm_ss<CharT>();
> +  test_hh_mm_ss_cust<CharT>();
> +}
> +
>  template<typename _CharT>
>  void
>  test_day()
> @@ -288,6 +558,7 @@ void
>  test_all()
>  {
>    test_padding<CharT>();
> +  test_durations<CharT>();
>    test_calendar<CharT>();
>  }
>
> --
> 2.49.0
>
>

Reply via email to