On Fri, Jun 27, 2025 at 10:31 AM Tomasz Kamiński <tkami...@redhat.com> wrote:
> This patch adjust all internal std::format call inside of > __formatter_chrono, > to use runtime format stirng and thus avoid compile time checking of > validity > of the format string. Majority of cases are covered by calling newly > introduced > _S_empty_fs() function that returns __Runtime_format_string containing > _S_empty_spec, instead of passing later directly. > > In case of _M_j we use _S_str_d3 function (extracted from _S_str_d2), > eliminating > call to std::format outside of unlikely scenario in which day of year is > greater > than 1000 (this may happen for year_month_day with month greater than 12). > In > consequence, outside of handling subseconds, we no longer delegate to > std::format > or construct temporary strings, when formatting chrono types with ok() > values. > > PR libstdc++/110739 > > libstdc++-v3/ChangeLog: > > * include/bits/chrono_io.h (__formatter_chrono::_S_empty_fs): > Define. > (__formatter_chrono::_S_str_d2): Use _S_str_d3 for 3+ digits. > (__formatter_chrono::_S_str_d3): Extracted from _S_str_d2. > (__formatter_chrono::_M_H_I, __formatter_chrono::_M_R_X): Replace > _S_empty_spec with _S_empty_fs(). > (__formatter_chrono::_M_j): Likewise and use _S_str_d3 in common > case. > --- I do not think this buys us much, but I think it is worth doing anyway. It also finishes my side goal, of getting rid of temporary strings, and using local buffers, that I applied to other specifiers in previous commits. Tested on x86_64-linux locally. The std/time* test passed with -D_GLIBCXX_USE_CXX11_ABI=0 and -D_GLIBCXX_DEBUG. OK for trunk? > libstdc++-v3/include/bits/chrono_io.h | 27 ++++++++++++++++++++++----- > 1 file changed, 22 insertions(+), 5 deletions(-) > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index bcfd51b9866..d6bc6c7cf2a 100644 > --- a/libstdc++-v3/include/bits/chrono_io.h > +++ b/libstdc++-v3/include/bits/chrono_io.h > @@ -873,6 +873,11 @@ namespace __format > static constexpr const _CharT* _S_minus_empty_spec = _S_chars + 17; > static constexpr const _CharT* _S_empty_spec = _S_chars + 18; > > + [[__gnu__::__always_inline__]] > + static _Runtime_format_string<_CharT> > + _S_empty_fs() > + { return _Runtime_format_string<_CharT>(_S_empty_spec); } > + > // Return the formatting locale. > template<typename _FormatContext> > std::locale > @@ -1411,7 +1416,7 @@ namespace __format > __i = 12; > } > else if (__i >= 100) [[unlikely]] > - return std::format_to(std::move(__out), _S_empty_spec, __i); > + return std::format_to(std::move(__out), _S_empty_fs(), __i); > > return __format::__write(std::move(__out), _S_two_digits(__i)); > } > @@ -1425,11 +1430,15 @@ namespace __format > { > // Decimal number of days, without padding. > auto __d = chrono::floor<chrono::days>(__t._M_hours).count(); > - return std::format_to(std::move(__out), _S_empty_spec, __d); > + return std::format_to(std::move(__out), _S_empty_fs(), __d); > } > > - return std::format_to(std::move(__out), _GLIBCXX_WIDEN("{:03d}"), > - __t._M_day_of_year.count()); > + auto __d = __t._M_day_of_year.count(); > + if (__d >= 1000) [[unlikely]] > + return std::format_to(std::move(__out), _S_empty_fs(), __d); > + > + _CharT __buf[3]; > + return __format::__write(std::move(__out), _S_str_d3(__buf, > __d)); > } > > template<typename _FormatContext> > @@ -1534,7 +1543,7 @@ namespace __format > > if (__hi >= 100) [[unlikely]] > { > - __out = std::format_to(std::move(__out), _S_empty_spec, > __hi); > + __out = std::format_to(std::move(__out), _S_empty_fs(), > __hi); > __sv.remove_prefix(2); > } > else > @@ -1772,7 +1781,15 @@ namespace __format > { > if (__n < 100) [[likely]] > return _S_two_digits(__n); > + return _S_str_d3(__buf, __n); > + } > > + [[__gnu__::__always_inline__]] > + // Returns decimal representation of __n, padded to 3 digits. > + // Returned string_view points to __buf. > + static basic_string_view<_CharT> > + _S_str_d3(span<_CharT, 3> __buf, unsigned __n) > + { > _S_fill_two_digits(__buf.data(), __n / 10); > __buf[2] = _S_chars[__n % 10]; > return __string_view(__buf.data(), 3); > -- > 2.49.0 > >