[PATCH v2 2/2] libstdc++: Lift chrono localized formatting to main chrono format loop [PR110739]
Jonathan Wakely
jwakely@redhat.com
Thu Jun 26 12:09:23 GMT 2025
On 26/06/25 11:39 +0200, Tomasz Kamiński wrote:
>This patch extract calls to _M_locale_fmt and construction of the struct tm,
>from the functions dedicated to each specifier, to main format loop in
>_M_format_to functions. This removes duplicated code repeated for specifiers.
Great, this is exactly what I wanted to do. Removing all the branches
to call _M_locale_fmt from each of the _M_xxx member functions makes
them smaller and potentially faster.
>To allow _M_locale_fmt to only be called if localized formatting is enabled
>('L' is present in chrono-format-spec), we provide a implementations for
>locale specific specifiers (%c, %r, %x, %X) that produces the same result
>as locale::classic():
> * %c is implemented as separate _M_c method
> * %r is implemented as separate _M_r method
> * %x is implemented together with %D, as they provide same behavior,
> * %X is implemented together with %R as _M_R_X, as both of them do not include
> subseconds.
Nice.
>The handling of subseconds was also extracted to _M_subsecs function that is
>used by _M_S and _M_T specifier. The _M_T is now implemented in terms of
>_M_R_X (printing time without subseconds) and _M_subs.
>
>The __mod responsible for triggering localized formatting was removed from
>method handling most of specifiers, except:
> * _M_S (for %S) for which it determines if subseconds should be included,
> * _M_z (for %z) for which it determines if ':' is used as separator.
>
> PR libstdc++/110739
>
>libstdc++-v3/ChangeLog:
>
> * include/bits/chrono_io.h (__formatter_chrono::_M_use_locale_fmt):
> Define.
> (__formatter_chrono::_M_locale_fmt): Moved to front of the class.
> (__formatter_chrono::_M_format_to): Construct and initialize
> struct tm and call _M_locale_fmt if needed.
> (__formatter_chrono::_M_c_r_x_X): Split into separate methods.
> (__formatter_chrono::_M_c, __formatter_chrono::_M_r): Define.
> (__formatter_chrono::_M_D): Renamed to _M_D_x.
> (__formatter_chrono::_M_D_x): Renamed from _M_D.
> (__formatter_chrono::_M_R_T): Split into _M_R_X and _M_T.
> (__formatter_chrono::_M_R_X): Extracted from _M_R_T.
> (__formatter_chrono::_M_T): Define in terms of _M_R_X and _M_subsecs.
> (__formatter_chrono::_M_subsecs): Extracted from _M_S.
> (__formatter_chrono::_M_S): Replaced __mod with __subs argument,
> removed _M_locale_fmt call, and delegate to _M_subsecs.
> (__formatter_chrono::_M_C_y_Y, __formatter_chrono::_M_d_e)
> (__formatter_chrono::_M_H_I, __formatter_chrono::_M_m)
> (__formatter_chrono::_M_u_w, __formatter_chrono::_M_U_V_W): Remove
> __mod argument and call to _M_locale_fmt.
>---
> libstdc++-v3/include/bits/chrono_io.h | 340 +++++++++++++-------------
> 1 file changed, 172 insertions(+), 168 deletions(-)
>
>diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
>index 35e95906e6a..d451bde722d 100644
>--- a/libstdc++-v3/include/bits/chrono_io.h
>+++ b/libstdc++-v3/include/bits/chrono_io.h
>@@ -906,6 +906,40 @@ namespace __format
> return __format::__write(std::move(__out), __s);
> }
>
>+ [[__gnu__::__always_inline__]]
>+ static bool
>+ _S_localized_spec(_CharT __conv, _CharT __mod)
>+ {
>+ switch (__conv)
>+ {
>+ case 'c':
>+ case 'r':
>+ case 'x':
>+ case 'X':
>+ return true;
>+ case 'z':
>+ return false;
>+ default:
>+ return (bool)__mod;
>+ };
>+ }
>+
>+ // Use the formatting locale's std::time_put facet to produce
>+ // a locale-specific representation.
>+ template<typename _Iter>
>+ _Iter
>+ _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
>+ char __fmt, char __mod) const
>+ {
>+ basic_ostringstream<_CharT> __os;
>+ __os.imbue(__loc);
>+ const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>+ __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>+ if (__os)
>+ __out = _M_write(std::move(__out), __loc, __os.view());
>+ return __out;
>+ }
>+
> template<typename _Out, typename _FormatContext>
> _Out
> _M_format_to(const _ChronoData<_CharT>& __t, _Out __out,
>@@ -923,6 +957,36 @@ namespace __format
> return std::move(__out);
> };
>
>+ struct tm __tm{};
>+ bool __use_locale_fmt = false;
>+ if (_M_spec._M_localized && _M_spec._M_locale_specific)
>+ if (__fc.locale() != locale::classic())
>+ {
>+ __use_locale_fmt = true;
>+
>+ __tm.tm_year = (int)__t._M_year - 1900;
>+ __tm.tm_yday = __t._M_day_of_year.count();
>+ __tm.tm_mon = (unsigned)__t._M_month - 1;
>+ __tm.tm_mday = (unsigned)__t._M_day;
>+ __tm.tm_wday = __t._M_weekday.c_encoding();
>+ __tm.tm_hour = __t._M_hours.count();
>+ __tm.tm_min = __t._M_minutes.count();
>+ __tm.tm_sec = __t._M_seconds.count();
>+
>+ // Some locales use %Z in their %c format but we don't want strftime
>+ // to use the system's local time zone (from /etc/localtime or $TZ)
>+ // as the output for %Z. Setting tm_isdst to -1 says there is no
>+ // time zone info available for the time in __tm.
>+ __tm.tm_isdst = -1;
>+
>+#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
>+ // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
>+ // BSD has had tm_zone since 1987 but as char* so cast away const.
>+ if (__t._M_zone_cstr)
>+ __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
>+#endif
>+ }
>+
> // Characters to output for "%n", "%t" and "%%" specifiers.
> constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
>
>@@ -932,7 +996,10 @@ namespace __format
> do
> {
> _CharT __c = *__first++;
>- switch (__c)
>+ if (__use_locale_fmt && _S_localized_spec(__c, __mod)) [[unlikely]]
>+ __out = _M_locale_fmt(std::move(__out), __fc.locale(),
>+ __tm, __c, __mod);
>+ else switch (__c)
> {
> // %\0 is extension for handling weekday index
> case '\0':
>@@ -948,22 +1015,20 @@ namespace __format
> __out = _M_b_B(__t._M_month, std::move(__out), __fc, __c == 'B');
> break;
> case 'c':
>- case 'r':
>- case 'x':
>- case 'X':
>- __out = _M_c_r_x_X(__t, std::move(__out), __fc, __c, __mod);
>+ __out = _M_c(__t, std::move(__out), __fc);
> break;
> case 'C':
> case 'y':
> case 'Y':
>- __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc, __c, __mod);
>+ __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc, __c);
> break;
> case 'd':
> case 'e':
>- __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c, __mod == 'O');
>+ __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c);
> break;
> case 'D':
>- __out = _M_D(__t, std::move(__out), __fc);
>+ case 'x':
>+ __out = _M_D_x(__t, std::move(__out), __fc);
> break;
> case 'F':
> __out = _M_F(__t, std::move(__out), __fc);
>@@ -974,16 +1039,16 @@ namespace __format
> break;
> case 'H':
> case 'I':
>- __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c, __mod == 'O');
>+ __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c);
> break;
> case 'j':
> __out = _M_j(__t, __print_sign(), __fc);
> break;
> case 'm':
>- __out = _M_m(__t._M_month, std::move(__out), __fc, __mod == 'O');
>+ __out = _M_m(__t._M_month, std::move(__out), __fc);
> break;
> case 'M':
>- __out = _M_M(__t._M_minutes, __print_sign(), __fc, __mod == 'O');
>+ __out = _M_M(__t._M_minutes, __print_sign(), __fc);
> break;
> case 'p':
> __out = _M_p(__t._M_hours, std::move(__out), __fc);
>@@ -994,22 +1059,28 @@ namespace __format
> case 'Q':
> __out = _M_Q(__t, __print_sign(), __fc);
> break;
>+ case 'r':
>+ __out = _M_r(__t, __print_sign(), __fc);
>+ break;
> case 'R':
>+ case 'X':
>+ __out = _M_R_X(__t, __print_sign(), __fc, __c != 'R');
>+ break;
> case 'T':
>- __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T');
>+ __out = _M_T(__t, __print_sign(), __fc);
> break;
>+
> case 'S':
>- __out = _M_S(__t, __print_sign(), __fc, __mod == 'O');
>+ __out = _M_S(__t, __print_sign(), __fc, __mod != 'O');
> break;
> case 'u':
> case 'w':
>- __out = _M_u_w(__t._M_weekday, std::move(__out), __fc, __c, __mod == 'O');
>+ __out = _M_u_w(__t._M_weekday, std::move(__out), __fc, __c);
> break;
> case 'U':
> case 'V':
> case 'W':
>- __out = _M_U_V_W(__t, std::move(__out), __fc, __c,
>- __mod == 'O');
>+ __out = _M_U_V_W(__t, std::move(__out), __fc, __c);
> break;
> case 'z':
> __out = _M_z(__t._M_zone_offset, std::move(__out), __fc, (bool)__mod);
>@@ -1132,50 +1203,27 @@ namespace __format
>
> template<typename _FormatContext>
> typename _FormatContext::iterator
>- _M_c_r_x_X(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, _CharT __mod) const
>+ _M_c(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>+ _FormatContext& __ctx) const
> {
>- // %c Locale's date and time representation.
>- // %Ec Locale's alternate date and time representation.
>- // %r Locale's 12-hour clock time.
>- // %x Locale's date rep
>- // %Ex Locale's alternative date representation.
>- // %X Locale's time rep
>- // %EX Locale's alternative time representation.
>-
>- using namespace chrono;
>- struct tm __tm{};
>-
>- // Some locales use %Z in their %c format but we don't want strftime
>- // to use the system's local time zone (from /etc/localtime or $TZ)
>- // as the output for %Z. Setting tm_isdst to -1 says there is no
>- // time zone info available for the time in __tm.
>- __tm.tm_isdst = -1;
>-
>-#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
>- // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
>- // BSD has had tm_zone since 1987 but as char* so cast away const.
>- if (__t._M_zone_cstr)
>- __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
>-#endif
>-
>- __tm.tm_year = (int)__t._M_year - 1900;
>- __tm.tm_yday = __t._M_day_of_year.count();
>- __tm.tm_mon = (unsigned)__t._M_month - 1;
>- __tm.tm_mday = (unsigned)__t._M_day;
>- __tm.tm_wday = __t._M_weekday.c_encoding();
>- __tm.tm_hour = __t._M_hours.count();
>- __tm.tm_min = __t._M_minutes.count();
>- __tm.tm_sec = __t._M_seconds.count();
>-
>- return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
>- __conv, __mod);
>+ // %c Locale's date and time representation, for C-locale: %a %b %e %T %Y
>+ // %Ec Locale's alternate date and time representation, for C-locale same as above
>+
>+ __out = _M_a_A(__t._M_weekday, std::move(__out), __ctx, false);
>+ *__out = _S_space;
>+ __out = _M_b_B(__t._M_month, std::move(++__out), __ctx, false);
>+ *__out = _S_space;
>+ __out = _M_d_e(__t._M_day, std::move(++__out), __ctx, 'e');
>+ *__out = _S_space;
>+ __out = _M_R_X(__t, std::move(++__out), __ctx, true);
>+ *__out = _S_space;
>+ return _M_C_y_Y(__t._M_year, std::move(__out), __ctx, 'Y');
> }
>
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_C_y_Y(chrono::year __y, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0) const
>+ _FormatContext& __ctx, _CharT __conv) const
> {
> // %C Year divided by 100 using floored division.
> // %EC Locale's alternative preresentation of the century (era name).
>@@ -1185,15 +1233,6 @@ namespace __format
> // %Y Year as a decimal number.
> // %EY Locale's alternative full year representation.
>
>- if (__mod && _M_spec._M_localized) [[unlikely]]
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_year = (int)__y - 1900;
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- __conv, __mod);
>- }
>-
> int __yi = (int)__y;
> const bool __is_neg = __yi < 0;
> __yi = __builtin_abs(__yi);
>@@ -1235,9 +1274,13 @@ namespace __format
>
> template<typename _FormatContext>
> typename _FormatContext::iterator
>- _M_D(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>- _FormatContext&) const
>+ _M_D_x(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>+ _FormatContext&) const
> {
>+ // %D Equivalent to %m/%d/%y
>+ // %x Locale's date rep, for C-locale: %m/%d/%y
>+ // %Ex Locale's alternative date representation, for C-locale same as above
>+
> auto __di = (unsigned)__t._M_day;
> auto __mi = (unsigned)__t._M_month;
> auto __yi = __builtin_abs((int)__t._M_year) % 100;
>@@ -1267,7 +1310,7 @@ namespace __format
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_d_e(chrono::day __d, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
>+ _FormatContext& __ctx, _CharT __conv) const
> {
> // %d The day of month as a decimal number.
> // %Od Locale's alternative representation.
>@@ -1276,15 +1319,6 @@ namespace __format
>
> unsigned __i = (unsigned)__d;
>
>- if (__mod && _M_spec._M_localized) [[unlikely]]
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_mday = __i;
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- (char)__conv, 'O');
>- }
>-
> _CharT __buf[3];
> auto __sv = _S_str_d2(__buf, __i);
> if (__conv == _CharT('e') && __i < 10)
>@@ -1360,7 +1394,7 @@ namespace __format
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_H_I(chrono::hours __h, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
>+ _FormatContext& __ctx, _CharT __conv) const
> {
> // %H The hour (24-hour clock) as a decimal number.
> // %OH Locale's alternative representation.
>@@ -1369,15 +1403,6 @@ namespace __format
>
> int __i = __h.count();
>
>- if (__mod && _M_spec._M_localized) [[unlikely]]
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_hour = __i;
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- (char)__conv, 'O');
>- }
>-
> if (__conv == _CharT('I'))
> {
> __i %= 12;
>@@ -1409,22 +1434,13 @@ namespace __format
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_m(chrono::month __m, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, bool __mod) const
>+ _FormatContext& __ctx) const
> {
> // %m month as a decimal number.
> // %Om Locale's alternative representation.
>
> auto __i = (unsigned)__m;
>
>- if (__mod && _M_spec._M_localized) [[unlikely]] // %Om
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_mon = __i - 1;
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- 'm', 'O');
>- }
>-
> _CharT __buf[3];
> return __format::__write(std::move(__out), _S_str_d2(__buf, __i));
> }
>@@ -1432,22 +1448,12 @@ namespace __format
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_M(chrono::minutes __m, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, bool __mod) const
>+ _FormatContext& __ctx) const
> {
> // %M The minute as a decimal number.
> // %OM Locale's alternative representation.
>
> auto __i = __m.count();
>-
>- if (__mod && _M_spec._M_localized) [[unlikely]] // %OM
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_min = __i;
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- 'M', 'O');
>- }
>-
> return __format::__write(std::move(__out), _S_two_digits(__i));
> }
>
>@@ -1488,17 +1494,42 @@ namespace __format
>
> template<typename _FormatContext>
> typename _FormatContext::iterator
>- _M_R_T(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>+ _M_r(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>+ _FormatContext& __ctx) const
>+ {
>+ // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p
>+ auto __hi = __t._M_hours.count() % 12;
>+ if (__hi == 0)
>+ __hi = 12;
>+
>+ _CharT __buf[9];
>+ __buf[2] = _S_colon;
>+ __buf[5] = _S_colon;
>+ __buf[8] = _S_space;
>+ _S_fill_two_digits(__buf, __hi);
>+ _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
>+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
>+
>+ __string_view __sv(__buf, 9);
>+ __out = __format::__write(std::move(__out), __sv);
>+ return _M_p(__t._M_hours, std::move(__out), __ctx);
>+ }
>+
>+ template<typename _FormatContext>
>+ typename _FormatContext::iterator
>+ _M_R_X(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
> _FormatContext& __ctx, bool __secs) const
> {
>- // %R Equivalent to %H:%M
>- // %T Equivalent to %H:%M:%S
>+ // %R Equivalent to %H:%M
>+ // %X Locale's time rep, for C-locale: %H:%M:%S (without subseconds)
>+ // %EX Locale's alternative time representation, for C-locale same as above
>+
> auto __hi = __t._M_hours.count();
>
>- _CharT __buf[6];
>+ _CharT __buf[8];
> __buf[2] = _S_colon;
> __buf[5] = _S_colon;
>- __string_view __sv(__buf, 5 + __secs);
>+ __string_view __sv(__buf, 8);
>
> if (__hi >= 100) [[unlikely]]
> {
>@@ -1509,39 +1540,39 @@ namespace __format
> _S_fill_two_digits(__buf, __hi);
>
> _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
>- __out = __format::__write(std::move(__out), __sv);
> if (__secs)
>- __out = _M_S(__t, std::move(__out), __ctx);
>- return __out;
>+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
>+ else
>+ __sv.remove_suffix(3);
>+
>+ return __format::__write(std::move(__out), __sv);
> }
>
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_S(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, bool __mod = false) const
>+ _FormatContext& __ctx, bool __subs = true) const
> {
>- // %S Seconds as a decimal number.
Doesn't this function still handle %S formats? Should this comment be kept?
Apart from that, this patch looks great - OK for trunk (after the
_ChronoData one, obviously).
> // %OS The locale's alternative representation.
> auto __s = __t._M_seconds;
>
>- if (__mod && _M_spec._M_localized) [[unlikely]] // %OS
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_sec = (int)__s.count();
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- 'S', 'O');
>- }
>-
> __out = __format::__write(std::move(__out),
>- _S_two_digits(__s.count()));
>+ _S_two_digits(__s.count()));
>+ if (__subs)
>+ __out = _M_subsecs(__t, std::move(__out), __ctx);
>+ return __out;
>+ }
>
>+ template<typename _FormatContext>
>+ typename _FormatContext::iterator
>+ _M_subsecs(const _ChronoData<_CharT>& __t,
>+ typename _FormatContext::iterator __out,
>+ _FormatContext& __ctx) const
>+ {
> unsigned __prec = _M_spec._M_prec_kind != _WP_none
> ? _M_spec._M_get_precision(__ctx)
> : _M_spec._M_prec;
>-
>- // %OS formats don't include subseconds
>- if (__prec == 0 || __mod)
>+ if (__prec == 0)
> return __out;
>
> _CharT __dot = _S_dot;
>@@ -1595,25 +1626,25 @@ namespace __format
>
> // %t handled in _M_format
>
>+ template<typename _FormatContext>
>+ typename _FormatContext::iterator
>+ _M_T(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>+ _FormatContext& __ctx) const
>+ {
>+ // %T Equivalent to %H:%M:%S, with subseconds
>+ __out = _M_R_X(__t, std::move(__out), __ctx, true);
>+ return _M_subsecs(__t, std::move(__out), __ctx);
>+ }
>+
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_u_w(chrono::weekday __wd, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
>+ _FormatContext& __ctx, _CharT __conv) const
> {
> // %u ISO weekday as a decimal number (1-7), where Monday is 1.
> // %Ou Locale's alternative numeric rep.
> // %w Weekday as a decimal number (0-6), where Sunday is 0.
> // %Ow Locale's alternative numeric rep.
>-
>- if (__mod && _M_spec._M_localized) [[unlikely]]
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_wday = __wd.c_encoding();
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- (char)__conv, 'O');
>- }
>-
> unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
> : __wd.c_encoding();
> _CharT __buf[3];
>@@ -1623,7 +1654,7 @@ namespace __format
> template<typename _FormatContext>
> typename _FormatContext::iterator
> _M_U_V_W(const _ChronoData<_CharT>& __t, typename _FormatContext::iterator __out,
>- _FormatContext& __ctx, _CharT __conv, bool __mod = false) const
>+ _FormatContext& __ctx, _CharT __conv) const
> {
> // %U Week number of the year as a decimal number, from first Sunday.
> // %OU Locale's alternative numeric rep.
>@@ -1633,17 +1664,6 @@ namespace __format
> // %OW Locale's alternative numeric rep.
> using namespace chrono;
>
>- if (__mod && _M_spec._M_localized) [[unlikely]]
>- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>- {
>- struct tm __tm{};
>- __tm.tm_year = (int)__t._M_year - 1900;
>- __tm.tm_yday = __t._M_day_of_year.count();
>- __tm.tm_wday = __t._M_weekday.c_encoding();
>- return _M_locale_fmt(std::move(__out), __loc, __tm,
>- (char)__conv, 'O');
>- }
>-
> auto __d = __t._M_ldays;
> local_days __first; // First day of week 1.
> if (__conv == 'V') // W01 begins on Monday before first Thursday.
>@@ -1755,22 +1775,6 @@ namespace __format
> __buf[2] = _S_chars[__n % 10];
> return __string_view(__buf.data(), 3);
> }
>-
>- // Use the formatting locale's std::time_put facet to produce
>- // a locale-specific representation.
>- template<typename _Iter>
>- _Iter
>- _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm& __tm,
>- char __fmt, char __mod) const
>- {
>- basic_ostringstream<_CharT> __os;
>- __os.imbue(__loc);
>- const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>- __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>- if (__os)
>- __out = _M_write(std::move(__out), __loc, __os.view());
>- return __out;
>- }
> };
>
> template<typename _CharT>
>--
>2.49.0
>
>
More information about the Libstdc++
mailing list