[PATCH 1/4] libstdc++: Format empty chrono-spec for the calendar types directly.

Jonathan Wakely jwakely@redhat.com
Thu Jun 12 11:37:55 GMT 2025


On 09/06/25 13:14 +0200, Tomasz Kaminski wrote:
>On Fri, Jun 6, 2025 at 1:02 PM Tomasz Kamiński <tkaminsk@redhat.com> wrote:
>
>> This patch change implementation of the formatters for the calendar types,
>> so they no longer delegate to operator<< for ostream in case of empty
>> chrono-spec.
>> Instead of that, we define the behavior of the in terms of format
>> specifiers,
>> that format specifiers are supplied by each formatter as argument to
>> _M_parse
>> Similary is formatter constructor it's __formatter_chrono from revalant
>> default
>> spec, so we preserve functionality of calling format on default cosntructed
>> formatters.
>>
>> Expressing  the existing functionality of the operaetor ostream, requires
>> providing two additional features:
>>  * printing "is not a valid sth" for !ok objects,
>>  * printing a weekday index in the month.
>>
>> The formatter functionality is enabled by setting spec _M_debug
>> (corresponding
>> to '?') that is currently unused. This is currently supported only for
>> subset of format specifiers used by the ostream operators. In future, we
>> could
>> make this user configurable (by adding '?' after 'L') and cover all flags.
>>
>> For the handling of the weekday index (for weekday_indexed, month_weekday,
>> year_month_weekday), we need to introduce an new format specifier. To not
>> conflict with future extension we use '%\0' (embedded null) as this
>> character
>> cannot be placed in valid format spec.
>>
>> Finally, the format strings for calendar types subsets each other, e.g.
>> year_month_weekday_last ("%Y/%b/%a[last])" contains month_weekday_last,
>> weekday_last, weekday, e.t.c.. We introduce a _ChronoFormats class that
>> provide
>> consteval accessors to format specs, internally sharing they
>> representations.
>>
>> libstdc++-v3/ChangeLog:
>>
>>         * include/bits/chrono_io.h (__format::_ChronoFormats): Define.
>>         (__formatter_chrono::__formatter_chrono())
>>         (__formatter_chrono::__formatter_chrono(_ChronoSpec<_CharT>)):
>> Define.
>>         (__formatter_chrono::_M_parse): Add parameter with default spec,
>>         namd merge it with new values. Handle '%\0' as weekday index
>>         specifier.
>>         (__formatter_chrono::_M_a_A, __formatter_chrono::_M_b_B)
>>         (__formatter_chrono::_M_C_y_Y, __formatter_chrono::_M_d_e)
>>         (__formatter_chrono::_M_F): Support _M_debug flag.
>>         (__formatter_chrono::_M_wi, __formatter_chrono::_S_weekday_index):
>>         Define.
>>         (std::formatter<chrono::day, _CharT>)
>>         (std::formatter<chrono::month, _CharT>)
>>         (std::formatter<chrono::year, _CharT>)
>>         (std::formatter<chrono::weekday, _CharT>)
>>         (std::formatter<chrono::weekday_indexed, _CharT>)
>>         (std::formatter<chrono::weekday_last, _CharT>)
>>         (std::formatter<chrono::month_day, _CharT>)
>>         (std::formatter<chrono::month_day_last, _CharT>)
>>         (std::formatter<chrono::month_weekday, _CharT>)
>>         (std::formatter<chrono::month_weekday_last, _CharT>)
>>         (std::formatter<chrono::year_month, _CharT>)
>>         (std::formatter<chrono::year_month_day, _CharT>)
>>         (std::formatter<chrono::year_month_day_last, _CharT>)
>>         (std::formatter<chrono::year_month_weekday, _CharT>)
>>         (std::formatter<chrono::year_month_weekday_last, _CharT>):
>>         Define __defSpec, and pass it as argument to _M_prase and
>>         constructor of __formatter_chrono.
>> ---
>>  libstdc++-v3/include/bits/chrono_io.h | 430 +++++++++++++++++++++++---
>>  1 file changed, 381 insertions(+), 49 deletions(-)
>>
>> diff --git a/libstdc++-v3/include/bits/chrono_io.h
>> b/libstdc++-v3/include/bits/chrono_io.h
>> index c5c5e4bae53..e36cf1ffd31 100644
>> --- a/libstdc++-v3/include/bits/chrono_io.h
>> +++ b/libstdc++-v3/include/bits/chrono_io.h
>> @@ -238,6 +238,93 @@ namespace __format
>>    operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept
>>    { return __x = __x | __y; }
>>
>> +  template<typename _CharT>
>> +  struct _ChronoFormats
>> +  {
>> +    using _String_view = basic_string_view<_CharT>;
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_f() noexcept
>> +    { return _GLIBCXX_WIDEN("%F"); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_ymd() noexcept
>> +    { return _GLIBCXX_WIDEN("%Y/%b/%d"); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_ym() noexcept
>> +    { return _S_ymd().substr(0, 5); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_md() noexcept
>> +    { return _S_ymd().substr(3); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_y() noexcept
>> +    { return _S_ymd().substr(0, 2); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_m() noexcept
>> +    { return _S_ymd().substr(3, 2); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_d() noexcept
>> +    { return _S_ymd().substr(6, 2); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_ymwi() noexcept
>> +    // %\0 is extension for handling weekday index
>> +    { return _String_view(_GLIBCXX_WIDEN("%Y/%b/%a[%\0]"), 12); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_mwi() noexcept
>> +    { return _S_ymwi().substr(3); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_wi() noexcept
>> +    { return _S_ymwi().substr(6); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_w() noexcept
>> +    { return _S_ymwi().substr(6, 2); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_ymwl() noexcept
>> +    { return _GLIBCXX_WIDEN("%Y/%b/%a[last]"); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_mwl() noexcept
>> +    { return _S_ymwl().substr(3); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_wl() noexcept
>> +    { return _S_ymwl().substr(6); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_yml() noexcept
>> +    { return _GLIBCXX_WIDEN("%Y/%b/last"); }
>> +
>> +    static consteval
>> +    _String_view
>> +    _S_ml() noexcept
>> +    { return _S_yml().substr(3); }
>> +  };
>> +
>>    // TODO rename this to chrono::__formatter? or
>> chrono::__detail::__formatter?
>>    template<typename _CharT>
>>      struct __formatter_chrono
>> @@ -245,49 +332,69 @@ namespace __format
>>        using __string_view = basic_string_view<_CharT>;
>>        using __string = basic_string<_CharT>;
>>
>> +      __formatter_chrono() = default;
>> +
>> +      constexpr explicit
>> +      __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept
>> +      : _M_spec(__spec)
>> +      { }
>> +
>>        template<typename _ParseContext>
>>         constexpr typename _ParseContext::iterator
>> -       _M_parse(_ParseContext& __pc, _ChronoParts __parts)
>> +       _M_parse(_ParseContext& __pc, _ChronoParts __parts,
>> +                const _ChronoSpec<_CharT>& __def = {})
>>         {
>>           auto __first = __pc.begin();
>>           auto __last = __pc.end();
>>
>>           _ChronoSpec<_CharT> __spec{};
>>
>This part could also be implemented as, let me know which version do you
>prefer:

I think I prefer this version, doing __spec = __def;


Rest of the review coming soon ...


>      using __string_view = basic_string_view<_CharT>;
>       using __string = basic_string<_CharT>;
>
>+      __formatter_chrono() = default;
>+
>+      constexpr explicit
>+      __formatter_chrono(_ChronoSpec<_CharT> __spec) noexcept
>+      : _M_spec(__spec)
>+      { }
>+
>       template<typename _ParseContext>
>        constexpr typename _ParseContext::iterator
>-       _M_parse(_ParseContext& __pc, _ChronoParts __parts)
>+       _M_parse(_ParseContext& __pc, _ChronoParts __parts,
>+                const _ChronoSpec<_CharT>& __def = {})
>        {
>          auto __first = __pc.begin();
>          auto __last = __pc.end();
>
>-         _ChronoSpec<_CharT> __spec{};
>+         _ChronoSpec<_CharT> __spec = __def;
>
>          auto __finalize = [this, &__spec] {
>            _M_spec = __spec;
>@@ -285,6 +380,7 @@ namespace __format
>                return __first;
>            }
>
>+         __spec._M_localized = false;
>          __first = __spec._M_parse_locale(__first, __last);
>          if (__finished())
>            return __first;
>@@ -307,6 +403,7 @@ namespace __format
>          // against __parts (so fail for %Y if no year in parts).
>          // Save range in __spec._M_chrono_specs.
>
>+         __spec._M_debug = false;
>          const auto __chrono_specs = __first++; // Skip leading '%'
>          if (*__chrono_specs != '%')
>            __throw_format_error("chrono format error: no '%' at
>
>>
>> -         auto __finalize = [this, &__spec] {
>> -           _M_spec = __spec;
>> +         auto __apply_default = [&] {
>> +           _M_spec = __def;
>> +           if (__spec._M_align != _Align_default)
>> +             {
>> +               _M_spec._M_align = __spec._M_align;
>> +               _M_spec._M_fill = __spec._M_fill;
>> +             }
>> +           if (__spec._M_width_kind != _WP_none)
>> +             {
>> +               _M_spec._M_width_kind = __spec._M_width_kind;
>> +               _M_spec._M_width = __spec._M_width;
>> +             }
>> +           if (__spec._M_prec_kind != _WP_none)
>> +             {
>> +               _M_spec._M_prec_kind = __spec._M_prec_kind;
>> +               _M_spec._M_prec = __spec._M_prec;
>> +             }
>> +           _M_spec._M_localized |= __spec._M_localized;
>> +           return __first;
>>           };
>>
>>           auto __finished = [&] {
>> -           if (__first == __last || *__first == '}')
>> -             {
>> -               __finalize();
>> -               return true;
>> -             }
>> -           return false;
>> +           return __first == __last || *__first == '}';
>>           };
>>
>>           if (__finished())
>> -           return __first;
>> +           return __apply_default();
>>
>>           __first = __spec._M_parse_fill_and_align(__first, __last);
>>           if (__finished())
>> -           return __first;
>> +           return __apply_default();
>>
>>           __first = __spec._M_parse_width(__first, __last, __pc);
>>           if (__finished())
>> -           return __first;
>> +           return __apply_default();
>>
>>           if (__parts & _ChronoParts::_Duration)
>>             {
>>               __first = __spec._M_parse_precision(__first, __last, __pc);
>>               if (__finished())
>> -               return __first;
>> +               return __apply_default();
>>             }
>>
>>           __first = __spec._M_parse_locale(__first, __last);
>>           if (__finished())
>> -           return __first;
>> +           return __apply_default();
>>
>>           // Everything up to the end of the string or the first '}' is a
>>           // chrono-specs string. Check it is valid.
>> @@ -562,6 +669,10 @@ namespace __format
>>               _CharT __c = *__first++;
>>               switch (__c)
>>                 {
>> +               // %\0 is extension for handling weekday index
>> +               case '\0':
>> +                 __out = _M_wi(__t, std::move(__out), __fc);
>> +                 break;
>>                 case 'a':
>>                 case 'A':
>>                   __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A');
>> @@ -816,6 +927,22 @@ namespace __format
>>           return __format::__write(std::move(__out), __s);
>>         }
>>
>> +      template<typename _Tp, typename _FormatContext>
>> +       typename _FormatContext::iterator
>> +       _M_wi(const _Tp& __t, typename _FormatContext::iterator __out,
>> +              _FormatContext& __ctx) const
>> +       {
>> +         // %\0 Extension to format weekday index, used only by empty
>> format spec
>> +         unsigned __wi = _S_weekday_index(__t);
>> +
>> +         _CharT __buf[3];
>> +         __out = __format::__write(std::move(__out), _S_str_d1(__buf,
>> __wi));
>> +         if (_M_spec._M_debug && (__wi < 1 || __wi > 5))
>> +           __out = __format::__write(std::move(__out),
>> +                     __string_view(_GLIBCXX_WIDEN(" is not a valid
>> index")));
>> +         return std::move(__out);
>> +       }
>> +
>>        template<typename _Tp, typename _FormatContext>
>>         typename _FormatContext::iterator
>>         _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
>> @@ -825,7 +952,16 @@ namespace __format
>>           // %A Locale's full weekday name.
>>           chrono::weekday __wd = _S_weekday(__t);
>>           if (!__wd.ok())
>> -           __throw_format_error("format error: invalid weekday");
>> +           {
>> +             if (!_M_spec._M_debug)
>> +               __throw_format_error("format error: invalid weekday");
>> +
>> +             _CharT __buf[3];
>> +             __out = __format::__write(std::move(__out),
>> +                                       _S_str_d1(__buf,
>> __wd.c_encoding()));
>> +             return __format::__write(std::move(__out),
>> +                       __string_view(_GLIBCXX_WIDEN(" is not a valid
>> weekday")));
>> +           }
>>
>>           locale __loc = _M_locale(__ctx);
>>           const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
>> @@ -847,7 +983,17 @@ namespace __format
>>           // %B Locale's full month name.
>>           chrono::month __m = _S_month(__t);
>>           if (!__m.ok())
>> -           __throw_format_error("format error: invalid month");
>> +           {
>> +             if (!_M_spec._M_debug)
>> +               __throw_format_error("format error: invalid month");
>> +
>> +             _CharT __buf[3];
>> +             __out = __format::__write(std::move(__out),
>> +                                       _S_str_d1(__buf, (unsigned)__m));
>> +             return __format::__write(std::move(__out),
>> +                       __string_view(_GLIBCXX_WIDEN(" is not a valid
>> month")));
>> +           }
>> +
>>           locale __loc = _M_locale(__ctx);
>>           const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
>>           const _CharT* __months[12];
>> @@ -974,7 +1120,11 @@ namespace __format
>>                 }
>>               __out = __format::__write(std::move(__out), __sv);
>>             }
>> -        return std::move(__out);
>> +
>> +         if (_M_spec._M_debug && __conv == 'Y' && !__y.ok()) [[unlikely]]
>> +           __out = __format::__write(std::move(__out),
>> +                     __string_view(_GLIBCXX_WIDEN(" is not a valid
>> year")));
>> +         return __out;
>>         }
>>
>>        template<typename _Tp, typename _FormatContext>
>> @@ -1039,7 +1189,12 @@ namespace __format
>>               __buf[0] = _S_space;
>>               __sv = {__buf, 2};
>>             }
>> -         return __format::__write(std::move(__out), __sv);
>> +
>> +         __out = __format::__write(std::move(__out), __sv);
>> +         if (_M_spec._M_debug && !__d.ok()) [[unlikely]]
>> +           __out = __format::__write(std::move(__out),
>> +                     __string_view(_GLIBCXX_WIDEN(" is not a valid
>> day")));
>> +         return std::move(__out);
>>         }
>>
>>        template<typename _Tp, typename _FormatContext>
>> @@ -1076,6 +1231,10 @@ namespace __format
>>               _S_fill_two_digits(__buf + 9, __di);
>>               __out = __format::__write(std::move(__out), __sv);
>>             }
>> +
>> +         if (_M_spec._M_debug && !__ymd.ok())
>> +           __out = __format::__write(std::move(__out),
>> +                     __string_view(_GLIBCXX_WIDEN(" is not a valid
>> date")));
>>           return std::move(__out);
>>         }
>>
>> @@ -1757,6 +1916,20 @@ namespace __format
>>             return weekday(_S_days(__t));
>>         }
>>
>> +      template<typename _Tp>
>> +       static unsigned
>> +       _S_weekday_index(const _Tp& __t)
>> +       {
>> +         using namespace ::std::chrono;
>> +
>> +         if constexpr (is_same_v<_Tp, weekday_indexed>)
>> +           return __t.index();
>> +         else if constexpr (requires { __t.weekday_indexed(); })
>> +           return __t.weekday_indexed().index();
>> +         else
>> +           return ((unsigned)_S_day(__t) + 6) / 7;
>> +       }
>> +
>>        // Remove subsecond precision from a time_point.
>>        template<typename _Tp>
>>         static auto
>> @@ -1851,7 +2024,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::_Day); }
>> +      { return _M_f._M_parse(__pc, __format::_Day, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1860,7 +2033,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_debug = true;
>> +         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_d();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1868,7 +2049,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::_Month); }
>> +      { return _M_f._M_parse(__pc, __format::_Month, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1877,7 +2058,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_m();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1885,7 +2076,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::_Year); }
>> +      { return _M_f._M_parse(__pc, __format::_Year, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1894,7 +2085,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_debug = true;
>> +         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_y();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1902,7 +2101,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::_Weekday); }
>> +      { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1911,7 +2110,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_w();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1919,7 +2128,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::_Weekday); }
>> +      { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1928,7 +2137,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_wi();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1936,7 +2155,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::_Weekday); }
>> +      { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1945,7 +2164,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_wl();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1953,7 +2182,10 @@ namespace __format
>>      {
>>        constexpr typename basic_format_parse_context<_CharT>::iterator
>>        parse(basic_format_parse_context<_CharT>& __pc)
>> -      { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
>> +      {
>> +       return _M_f._M_parse(__pc, __format::_Month|__format::_Day,
>> +                            __defSpec);
>> +      }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1962,7 +2194,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_md();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1970,7 +2212,10 @@ namespace __format
>>      {
>>        constexpr typename basic_format_parse_context<_CharT>::iterator
>>        parse(basic_format_parse_context<_CharT>& __pc)
>> -      { return _M_f._M_parse(__pc, __format::_Month|__format::_Day); }
>> +      {
>> +       return _M_f._M_parse(__pc, __format::_Month|__format::_Day,
>> +                            __defSpec);
>> +      }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1979,7 +2224,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ml();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -1987,7 +2242,10 @@ namespace __format
>>      {
>>        constexpr typename basic_format_parse_context<_CharT>::iterator
>>        parse(basic_format_parse_context<_CharT>& __pc)
>> -      { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
>> +      {
>> +       return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday,
>> +                            __defSpec);
>> +      }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -1996,7 +2254,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_mwi();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2004,7 +2272,10 @@ namespace __format
>>      {
>>        constexpr typename basic_format_parse_context<_CharT>::iterator
>>        parse(basic_format_parse_context<_CharT>& __pc)
>> -      { return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday); }
>> +      {
>> +       return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday,
>> +                            __defSpec);
>> +      }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2013,7 +2284,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_mwl();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2021,7 +2302,10 @@ namespace __format
>>      {
>>        constexpr typename basic_format_parse_context<_CharT>::iterator
>>        parse(basic_format_parse_context<_CharT>& __pc)
>> -      { return _M_f._M_parse(__pc, __format::_Year|__format::_Month); }
>> +      {
>> +       return _M_f._M_parse(__pc, __format::_Year|__format::_Month,
>> +                            __defSpec);
>> +      }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2030,7 +2314,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ym();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2038,7 +2332,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::_Date); }
>> +      { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2047,7 +2341,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_debug = true;
>> +         __res._M_chrono_specs = __format::_ChronoFormats<_CharT>::_S_f();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2055,7 +2357,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::_Date); }
>> +      { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2064,7 +2366,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_yml();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2072,7 +2384,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::_Date); }
>> +      { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2081,7 +2393,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ymwi();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<__format::__char _CharT>
>> @@ -2089,7 +2411,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::_Date); }
>> +      { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>>
>>        template<typename _Out>
>>         typename basic_format_context<_Out, _CharT>::iterator
>> @@ -2098,7 +2420,17 @@ 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_debug = true;
>> +         __res._M_localized = true;
>> +         __res._M_locale_specific = true;
>> +         __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ymwl();
>> +         return __res;
>> +       }();
>> +
>> +      __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>>      };
>>
>>    template<typename _Rep, typename _Period, __format::__char _CharT>
>> @@ -2947,7 +3279,7 @@ namespace __detail
>>        // 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
>> +      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),
>> --
>> 2.49.0
>>
>>



More information about the Libstdc++ mailing list