On 06/06/25 12:41 +0200, Tomasz Kamiński wrote:
This patch change implementation of the formatters for time points and hh_mm_ss,
so they no longer delegate to operator<< for ostream in case of empty 
chrono-spec.
As in case of calendar types, the formatters for specific type now provide
__formatter_chrono with default _ChronoSpec that are used in case if empty
chron-spec.

chron -> chrono

The configuration of __defSpec is straight forward, expect for the sys_time,

expect -> except

and local_time that print time, if the duration is convertible to days,
which is equivalent to setting _M_chrono_specs "%F" instead of "%F %T".
Furthermore, certain sys_time<Dur> do not support ostream operator, and
should not be formattable with empty spec - in such case default _M_chron_spec,

chron -> chrono

allowing the issue to still be detected in _M_parse.

Finally, _ChronoFormats are extended to cover required format strings.

libstdc++-v3/ChangeLog:

        * include/bits/chrono_io.h (_ChronoFormats::_S_ftz)
        (_ChronoFormats::_S_ft, _ChronoFormats::_S_t): Define.
        (__formatter_chrono::_M_format_to_ostream): Remove handling for
        time_points.
        (std::formatter<chrono::hh_mm_ss<_Dur>, _CharT>)
        (std::formatter<chrono::sys_time<_Dur>, _CharT>)
        (std::formatter<chrono::utc_time<_Dur>, _CharT>)
        (std::formatter<chrono::tai_time<_Dur>, _CharT>)
        (std::formatter<chrono::gps_time<_Dur>, _CharT>)
        (std::formatter<chrono::file_time<_Dur>, _CharT>)
        (std::formatter<chrono::local_time<_Dur>, _CharT>)
        (std::formatter<chrono::__detail::__local_time_fmt<_Dur>, _CharT>)
        (std::formatter<chrono::zoned_time<_Dur>, _CharT>):
        Define __defSpec, and pass it as argument to _M_prase and
        constructor of __formatter_chrono.

OK for trunk


---
libstdc++-v3/include/bits/chrono_io.h | 220 ++++++++++++++++----------
1 file changed, 135 insertions(+), 85 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h 
b/libstdc++-v3/include/bits/chrono_io.h
index e36cf1ffd31..24c7dfb91c9 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -243,10 +243,25 @@ namespace __format
  {
    using _String_view = basic_string_view<_CharT>;

+    static consteval
+    _String_view
+    _S_ftz() noexcept
+    { return _GLIBCXX_WIDEN("%F %T %Z"); }
+
+    static consteval
+    _String_view
+    _S_ft() noexcept
+    { return _S_ftz().substr(0, 5); }
+
    static consteval
    _String_view
    _S_f() noexcept
-    { return _GLIBCXX_WIDEN("%F"); }
+    { return _S_ftz().substr(0, 2); }
+
+    static consteval
+    _String_view
+    _S_t() noexcept
+    { return _S_ftz().substr(3, 2); }

    static consteval
    _String_view
@@ -836,58 +851,17 @@ namespace __format
          __os.imbue(_M_locale(__fc));

          if constexpr (__is_specialization_of<_Tp, __local_time_fmt>)
-           {
-             // Format as "{:L%F %T}"
-             auto __days = chrono::floor<chrono::days>(__t._M_time);
-             __os << chrono::year_month_day(__days) << ' '
-                  << chrono::hh_mm_ss(__t._M_time - __days);
-
-             // For __local_time_fmt the __is_neg flags says whether to
-             // append " %Z" to the result.
-             if (__is_neg)
-               {
-                 if (!__t._M_abbrev) [[unlikely]]
-                   __format::__no_timezone_available();
-                 else if constexpr (is_same_v<_CharT, char>)
-                   __os << ' ' << *__t._M_abbrev;
-                 else
-                   {
-                     __os << L' ';
-                     for (char __c : *__t._M_abbrev)
-                       __os << __c;
-                   }
-               }
-           }
+           __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 (__is_specialization_of<_Tp, __utc_leap_second>)
-               __os << __t._M_date << ' ' << __t._M_time;
-             else if constexpr (chrono::__is_time_point_v<_Tp>)
-               {
-                 // Need to be careful here because not all specializations
-                 // of chrono::sys_time can be written to an ostream.
-                 // For the specializations of time_point that can be
-                 // formatted with an empty chrono-specs, either it's a
-                 // sys_time with period greater or equal to days:
-                 if constexpr (is_convertible_v<_Tp, chrono::sys_days>)
-                   __os << _S_date(__t);
-                 // Or a local_time with period greater or equal to days:
-                 else if constexpr (is_convertible_v<_Tp, chrono::local_days>)
-                   __os << _S_date(__t);
-                 else // Or it's formatted as "{:L%F %T}":
-                   {
-                     auto __days = chrono::floor<chrono::days>(__t);
-                     __os << chrono::year_month_day(__days) << ' '
-                        << chrono::hh_mm_ss(__t - __days);
-                   }
-               }
-             else
-               {
-                 if constexpr (chrono::__is_duration_v<_Tp>)
-                   if (__is_neg) [[unlikely]]
-                     __os << _S_plus_minus[1];
-                 __os << __t;
-               }
+             if constexpr (chrono::__is_duration_v<_Tp>)
+               if (__is_neg) [[unlikely]]
+                 __os << _S_plus_minus[1];
+             __os << __t;
            }

          auto __str = std::move(__os).str();
@@ -2438,7 +2412,7 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_TimeOfDay); }
+      { return _M_f._M_parse(__pc, __format::_TimeOfDay, __defSpec); }

      template<typename _Out>
        typename basic_format_context<_Out, _CharT>::iterator
@@ -2447,7 +2421,15 @@ namespace __format
        { return _M_f._M_format(__t, __fc); }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_t();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -2492,7 +2474,7 @@ namespace __format
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
      {
-       auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime);
+       auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec);
        if constexpr (!__stream_insertable)
          if (_M_f._M_spec._M_chrono_specs.empty())
            __format::__invalid_chrono_spec(); // chrono-specs can't be empty
@@ -2510,7 +2492,22 @@ namespace __format
        = requires (basic_ostream<_CharT>& __os,
                    chrono::sys_time<_Duration> __t) { __os << __t; };

-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         if constexpr (!__stream_insertable)
+           return __res;
+         else if constexpr (is_convertible_v<_Duration, chrono::days>)
+           __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_f();
+         else
+           {
+             __res._M_localized = true;
+             __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+           }
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

  template<typename _Duration, __format::__char _CharT>
@@ -2519,11 +2516,11 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+      { return _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::utc_time<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::utc_time<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        {
          // Adjust by removing leap seconds to get equivalent sys_time.
@@ -2544,7 +2541,15 @@ namespace __format
    private:
      friend formatter<chrono::__detail::__utc_leap_second<_Duration>, _CharT>;

-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

  template<typename _Duration, __format::__char _CharT>
@@ -2553,11 +2558,11 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+      { return _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::tai_time<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::tai_time<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        {
          // Convert to __local_time_fmt with abbrev "TAI" and offset 0s.
@@ -2575,7 +2580,15 @@ namespace __format
        }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

  template<typename _Duration, __format::__char _CharT>
@@ -2584,11 +2597,11 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+      { return _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::gps_time<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::gps_time<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        {
          // Convert to __local_time_fmt with abbrev "GPS" and offset 0s.
@@ -2606,7 +2619,15 @@ namespace __format
        }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

  template<typename _Duration, __format::__char _CharT>
@@ -2614,11 +2635,11 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+      { return _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::file_time<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::file_time<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        {
          using namespace chrono;
@@ -2626,24 +2647,45 @@ namespace __format
        }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
-    };
+       static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
+     };

  template<typename _Duration, __format::__char _CharT>
    struct formatter<chrono::local_time<_Duration>, _CharT>
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      {  return _M_f._M_parse(__pc, __format::_DateTime); }
+      {  return _M_f._M_parse(__pc, __format::_DateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::local_time<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::local_time<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        { return _M_f._M_format(__t, __fc); }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
+      static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         if constexpr (is_convertible_v<_Duration, chrono::days>)
+           __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_f();
+         else
+           {
+             __res._M_localized = true;
+             __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ft();
+           }
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

  template<typename _Duration, __format::__char _CharT>
@@ -2651,16 +2693,24 @@ namespace __format
    {
      constexpr typename basic_format_parse_context<_CharT>::iterator
      parse(basic_format_parse_context<_CharT>& __pc)
-      { return _M_f._M_parse(__pc, __format::_ZonedDateTime); }
+      { return _M_f._M_parse(__pc, __format::_ZonedDateTime, __defSpec); }

      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
-       { return _M_f._M_format(__t, __fc, /* use %Z for {} */ true); }
+       { return _M_f._M_format(__t, __fc); }

    private:
-      __format::__formatter_chrono<_CharT> _M_f;
+       static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
+       {
+         __format::_ChronoSpec<_CharT> __res{};
+         __res._M_localized = true;
+         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_ftz();
+         return __res;
+       }();
+
+      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
    };

#if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
@@ -2669,8 +2719,8 @@ namespace __format
    : formatter<chrono::__detail::__local_time_fmt_for<_Duration>, _CharT>
    {
      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::zoned_time<_Duration, _TimeZonePtr>& __tp,
               basic_format_context<_Out, _CharT>& __fc) const
        {
          using _Ltf = chrono::__detail::__local_time_fmt_for<_Duration>;
@@ -2690,8 +2740,8 @@ namespace __format
    : formatter<chrono::utc_time<_Duration>, _CharT>
    {
      template<typename _Out>
-        typename basic_format_context<_Out, _CharT>::iterator
-        format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
+       typename basic_format_context<_Out, _CharT>::iterator
+       format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
               basic_format_context<_Out, _CharT>& __fc) const
        { return this->_M_f._M_format(__t, __fc); }
    };
--
2.49.0



Reply via email to