On Thu, 26 Jun 2025 at 14:19, Tomasz Kamiński <tkami...@redhat.com> 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. > > 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. > > 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. > > Reviewed-by: Jonathan Wakely <jwak...@redhat.com> > Signed-off-by: Tomasz Kamiński <tkami...@redhat.com> > --- > Changes in v3: > - restored missing comment in _M_S > - increment __out before calling _M_C_y_Y in _M_c
OK for trunk, thanks > > libstdc++-v3/include/bits/chrono_io.h | 338 +++++++++++++------------- > 1 file changed, 171 insertions(+), 167 deletions(-) > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index 8811eaa5b3b..9e21152e398 100644 > --- a/libstdc++-v3/include/bits/chrono_io.h > +++ b/libstdc++-v3/include/bits/chrono_io.h > @@ -908,6 +908,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, > @@ -925,6 +959,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%"); > > @@ -934,7 +998,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': > @@ -950,22 +1017,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); > @@ -976,16 +1041,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); > @@ -996,22 +1061,27 @@ 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); > @@ -1134,50 +1204,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). > @@ -1187,15 +1234,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); > @@ -1237,9 +1275,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; > @@ -1269,7 +1311,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. > @@ -1278,15 +1320,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) > @@ -1362,7 +1395,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. > @@ -1371,15 +1404,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; > @@ -1411,22 +1435,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)); > } > @@ -1434,22 +1449,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)); > } > > @@ -1490,17 +1495,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]] > { > @@ -1511,39 +1541,40 @@ 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. > // %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; > @@ -1597,25 +1628,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]; > @@ -1625,7 +1656,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. > @@ -1635,17 +1666,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. > @@ -1757,22 +1777,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 >