From: Tomasz KamiƄski Date: Thu, 2 Oct 2025 14:17:05 +0000 (+0200) Subject: libstdc++: Implement P3235R3 optimizations for std::print [PR121790] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8b388a94890b06d58a290dd39b9023cc4383c80;p=thirdparty%2Fgcc.git libstdc++: Implement P3235R3 optimizations for std::print [PR121790] This patch implements additional enable_nonlocking_formatter_optimization specializations listed in P3235R3. PR libstdc++/121790 libstdc++-v3/ChangeLog: * include/bits/chrono_io.h (enable_nonlocking_formatter_optimization): Define specializations for chrono types. * include/bits/version.def (print): Bump. * include/bits/version.h: Regenerate. * include/std/format (enable_nonlocking_formatter_optimization): Define specializations for pair, tuple and ranges. * include/std/queue (enable_nonlocking_formatter_optimization): Define specializations for queue and priority_queue. * include/std/stack (enable_nonlocking_formatter_optimization): Define specialization for stack. * include/std/stacktrace (enable_nonlocking_formatter_optimization): Define specialization for basic_stacktrace and stacktrace_entry. * include/std/thread (enable_nonlocking_formatter_optimization): Define specialization for thread::id. * include/std/vector (enable_nonlocking_formatter_optimization): Define specialization for vector::reference. * testsuite/23_containers/vector/bool/format.cc: Test value of enable_nonlocking_formatter_optimization. * testsuite/30_threads/thread/id/output.cc: Likewise. * testsuite/std/format/ranges/adaptors.cc: Likewise. * testsuite/std/format/ranges/formatter.cc: Likewise. * testsuite/std/format/tuple.cc: Likewise. * testsuite/std/time/format/empty_spec.cc: Extract Rep class to custom_rep.h. * testsuite/std/time/format/custom_rep.h: Extracted from empty_spec.cc. * testsuite/std/time/format/nonlocking.cc: New test. Reviewed-by: Jonathan Wakely --- diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 1e2f45b0bf8..df047f1103b 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -2234,6 +2234,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = enable_nonlocking_formatter_optimization<_Rep>; +#endif + template<__format::__char _CharT> struct formatter { @@ -2270,6 +2277,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2308,6 +2321,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2344,6 +2363,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2382,6 +2407,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2420,6 +2451,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2458,6 +2495,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2497,6 +2540,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2535,6 +2584,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2574,6 +2629,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2613,6 +2674,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2651,6 +2718,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2693,6 +2766,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2740,6 +2819,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2795,6 +2880,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2846,6 +2937,12 @@ namespace __format __format::__formatter_chrono<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template struct formatter>, _CharT> { @@ -2890,6 +2987,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI template<__format::__char _CharT> struct formatter @@ -2908,6 +3012,12 @@ namespace __format __format::__formatter_chrono_info<_CharT> _M_f; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template<__format::__char _CharT> struct formatter { @@ -2924,6 +3034,12 @@ namespace __format private: __format::__formatter_chrono_info<_CharT> _M_f; }; + +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif #endif template @@ -2962,6 +3078,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3006,6 +3129,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3041,6 +3171,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3076,6 +3213,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3111,6 +3255,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3145,6 +3296,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> + = true; +#endif + template struct formatter, _CharT> { @@ -3205,6 +3363,13 @@ namespace __format __format::__formatter_duration<_CharT> _M_f{__defSpec}; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization< + chrono::__detail::__local_time_fmt<_Duration>> = true; +#endif + #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI template struct formatter, _CharT> @@ -3224,6 +3389,13 @@ namespace __format return _Base::format(__lf, __fc); } }; + +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization< + chrono::zoned_time<_Duration, const chrono::time_zone*>> = true; +#endif #endif namespace chrono diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 1c0f43e465b..83f1817bf8e 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1865,7 +1865,7 @@ ftms = { ftms = { name = print; values = { - v = 202403; + v = 202406; cxxmin = 23; hosted = yes; }; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index 7b97accc47e..0d6692d244a 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2083,9 +2083,9 @@ #if !defined(__cpp_lib_print) # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED -# define __glibcxx_print 202403L +# define __glibcxx_print 202406L # if defined(__glibcxx_want_all) || defined(__glibcxx_want_print) -# define __cpp_lib_print 202403L +# define __cpp_lib_print 202406L # endif # endif #endif /* !defined(__cpp_lib_print) */ diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 1d01bc39e9c..ad29f9336e8 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -5872,6 +5872,14 @@ namespace __format { return this->_M_format_elems(__p.first, __p.second, __fc); } }; +#if __glibcxx_print >= 202406L + template + constexpr bool enable_nonlocking_formatter_optimization> + // TODO this should have remove_cvref_t. + = enable_nonlocking_formatter_optimization<_Fp> + && enable_nonlocking_formatter_optimization<_Sp>; +#endif + template<__format::__char _CharT, formattable<_CharT>... _Tps> struct formatter, _CharT> : __format::__tuple_formatter<_CharT, remove_cvref_t<_Tps>...> @@ -5890,6 +5898,13 @@ namespace __format { return this->_M_format(__t, index_sequence_for<_Tps...>(), __fc); } }; +#if __glibcxx_print >= 202406L + template + // TODO this should have remove_cvref_t. + constexpr bool enable_nonlocking_formatter_optimization> + = (enable_nonlocking_formatter_optimization<_Tps> && ...); +#endif + // [format.range.formatter], class template range_formatter template requires same_as, _Tp> && formattable<_Tp, _CharT> @@ -6184,6 +6199,13 @@ namespace __format range_formatter<_Vt, _CharT>>; _Formatter_under _M_under; }; + +#if __glibcxx_print >= 202406L + template + requires (format_kind<_Rg> != range_format::disabled) + constexpr bool enable_nonlocking_formatter_optimization<_Rg> = false; +#endif + #endif // C++23 formatting ranges #undef _GLIBCXX_WIDEN diff --git a/libstdc++-v3/include/std/queue b/libstdc++-v3/include/std/queue index 1b76088b31b..ade09f42ea8 100644 --- a/libstdc++-v3/include/std/queue +++ b/libstdc++-v3/include/std/queue @@ -112,6 +112,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION range_formatter<_Tp, _CharT> _M_f; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + // TODO should be false + enable_nonlocking_formatter_optimization> = true; +#endif + template<__format::__char _CharT, typename _Tp, formattable<_CharT> _Container, typename _Compare> struct formatter, _CharT> @@ -146,6 +153,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION range_formatter<_Tp, _CharT> _M_f; }; +#if __glibcxx_print >= 202406L + template + constexpr bool + // TODO should be false + enable_nonlocking_formatter_optimization< + priority_queue<_Tp, _Container, _Comparator>> = true; +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __glibcxx_format_ranges diff --git a/libstdc++-v3/include/std/stack b/libstdc++-v3/include/std/stack index a57a5a08bc3..88bc0d2cb6b 100644 --- a/libstdc++-v3/include/std/stack +++ b/libstdc++-v3/include/std/stack @@ -105,6 +105,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Standard uses formatter, _CharT>. range_formatter<_Tp, _CharT> _M_f; }; + +#if __glibcxx_print >= 202406L + template + constexpr bool + // TODO should be false + enable_nonlocking_formatter_optimization> = true; +#endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __glibcxx_format_ranges diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 491122293c5..01e18ba171c 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -765,6 +765,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __format::_Spec _M_spec; }; +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + template class formatter> { @@ -790,6 +796,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } }; +#if __glibcxx_print >= 202406L + template + constexpr bool + enable_nonlocking_formatter_optimization> = true; +#endif + namespace pmr { using stacktrace diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index 94ded714e9e..ccab1e44fbc 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -384,6 +384,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: __format::_Spec<_CharT> _M_spec; }; + +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization = true; +#endif + #endif // __cpp_lib_formatters /// @} group threads diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 3146f283944..920f852f794 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -169,6 +169,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: __format::__formatter_int<_CharT> _M_f; }; + +#if __glibcxx_print >= 202406L + template<> + inline constexpr bool + enable_nonlocking_formatter_optimization<_GLIBCXX_STD_C::_Bit_reference> = true; +#endif + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __glibcxx_format_ranges diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc index cecc535f15f..833727f4b41 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc @@ -7,6 +7,7 @@ static_assert(!std::formattable::reference, int>); static_assert(!std::formattable::reference, char32_t>); +static_assert(std::enable_nonlocking_formatter_optimization::reference>); template bool diff --git a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc index 3d1dd38d998..c3e0d421d19 100644 --- a/libstdc++-v3/testsuite/30_threads/thread/id/output.cc +++ b/libstdc++-v3/testsuite/30_threads/thread/id/output.cc @@ -81,7 +81,6 @@ void test02() { #if __cpp_lib_formatters >= 202302 - static_assert( std::is_default_constructible_v> ); std::thread t1([]{}); @@ -155,6 +154,10 @@ test02() #endif } +#if __cplusplus >= 202302L +static_assert(std::enable_nonlocking_formatter_optimization); +#endif + int main() { test01(); diff --git a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc index a4e2dfb3321..d9fc01ab893 100644 --- a/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc +++ b/libstdc++-v3/testsuite/std/format/ranges/adaptors.cc @@ -121,6 +121,16 @@ test_output() // Formatter check if container is formattable, not container elements. static_assert(!std::formattable>, CharT>); + + // TODO should be false + static_assert(std::enable_nonlocking_formatter_optimization< + Adaptor>); + static_assert(std::enable_nonlocking_formatter_optimization< + Adaptor>); + static_assert(std::enable_nonlocking_formatter_optimization< + Adaptor>>); + static_assert(std::enable_nonlocking_formatter_optimization< + Adaptor>>); } template> class Adaptor> diff --git a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc index d3e089767bf..a50c5b1033f 100644 --- a/libstdc++-v3/testsuite/std/format/ranges/formatter.cc +++ b/libstdc++-v3/testsuite/std/format/ranges/formatter.cc @@ -4,6 +4,7 @@ #include #include #include +#include #define WIDEN_(C, S) ::std::__format::_Widen(S, L##S) #define WIDEN(S) WIDEN_(CharT, S) @@ -145,7 +146,7 @@ struct MyFlatMap : std::flat_map template struct std::formatter - // This cannot apply format BitVector const&, because formatted type would + // We cannot format MyFlatMap const&, because formatted type would // be std::pair, and formatter for // pair cannot format it. : std::range_formatter @@ -161,10 +162,21 @@ void test_const_ref_type_mismatch() template using VectorFormatter = std::formatter, CharT>; +template typename Range> +void test_nonblocking() +{ + static_assert(!std::enable_nonlocking_formatter_optimization< + Range>); +} + int main() { test_outputs(); test_outputs(); test_nested(); test_const_ref_type_mismatch(); + + test_nonblocking(); + test_nonblocking(); + test_nonblocking(); } diff --git a/libstdc++-v3/testsuite/std/format/tuple.cc b/libstdc++-v3/testsuite/std/format/tuple.cc index ba6dae8935b..001235ba643 100644 --- a/libstdc++-v3/testsuite/std/format/tuple.cc +++ b/libstdc++-v3/testsuite/std/format/tuple.cc @@ -341,6 +341,40 @@ void test_padding() VERIFY( check_elems(resv) ); } +struct Custom {}; + +template +struct std::formatter +{ + constexpr std::basic_format_parse_context::iterator + parse(const std::basic_format_parse_context& pc) + { return pc.begin(); } + + template + typename std::basic_format_context::iterator + format(Custom, const std::basic_format_context& fc) const + { return fc.out(); } +}; + +template typename Tuple> +void test_nonblocking() +{ + static_assert(std::enable_nonlocking_formatter_optimization< + Tuple>); + // TODO missing remove_cv_ref + static_assert(!std::enable_nonlocking_formatter_optimization< + Tuple>); + static_assert(!std::enable_nonlocking_formatter_optimization< + Tuple>); + + static_assert(!std::enable_nonlocking_formatter_optimization< + Tuple>); + static_assert(!std::enable_nonlocking_formatter_optimization< + Tuple>); + static_assert(!std::enable_nonlocking_formatter_optimization< + Tuple>); +} + int main() { test_format_string(); @@ -348,4 +382,7 @@ int main() test_outputs(); test_nested(); test_padding(); + + test_nonblocking(); + test_nonblocking(); } diff --git a/libstdc++-v3/testsuite/std/time/format/custom_rep.h b/libstdc++-v3/testsuite/std/time/format/custom_rep.h new file mode 100644 index 00000000000..8363eaafebc --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/custom_rep.h @@ -0,0 +1,92 @@ +#include +#include + +#define WIDEN_(C, S) ::std::__format::_Widen(S, L##S) +#define WIDEN(S) WIDEN_(CharT, S) + +template +struct Rep +{ + using Return + = std::conditional_t, Rep, Ret>; + + Rep(Under v = 0) : val(v) {} + + template + Rep(Rep o) : val(o.val) {} + + operator Under() const + { return val; } + + Return + operator+() const + { return val; } + + Rep + operator-() const + { return -val; } + + friend Rep + operator+(Rep lhs, Rep rhs) + { return lhs.val + rhs.val; } + + friend Rep + operator-(Rep lhs, Rep rhs) + { return lhs.val - rhs.val; } + + friend Rep + operator*(Rep lhs, Rep rhs) + { return lhs.val * rhs.val; } + + friend Rep + operator/(Rep lhs, Rep rhs) + { return lhs.val / rhs.val; } + + friend auto operator<=>(Rep, Rep) = default; + + template + friend std::basic_ostream& + operator<<(std::basic_ostream& os, const Rep& t) + { return os << t.val << WIDEN("[via <<]"); } + + Under val; +}; + +template +struct std::common_type, Rep> +{ + using type = Rep>; +}; + +template + requires std::is_integral_v +struct std::common_type, Other> +{ + using type = Rep>; +}; + +template + requires std::is_integral_v +struct std::common_type> + : std::common_type, Other> +{ }; + +template +struct std::numeric_limits> + : std::numeric_limits +{ }; + +template +struct std::formatter, CharT> + : std::formatter +{ + template + typename std::basic_format_context::iterator + format(const Rep& t, std::basic_format_context& ctx) const + { + constexpr std::basic_string_view suffix = WIDEN("[via format]"); + auto out = std::formatter::format(t.val, ctx); + return std::ranges::copy(suffix, out).out; + } +}; + diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc index a20c074018e..b84f84a3069 100644 --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc @@ -6,11 +6,10 @@ #include #include #include +#include "custom_rep.h" using namespace std::chrono; -#define WIDEN_(C, S) ::std::__format::_Widen(S, L##S) -#define WIDEN(S) WIDEN_(CharT, S) template void @@ -77,92 +76,6 @@ test_padding() VERIFY( res == WIDEN("==16 is not a valid month==") ); } -template -struct Rep -{ - using Return - = std::conditional_t, Rep, Ret>; - - Rep(Under v = 0) : val(v) {} - - template - Rep(Rep o) : val(o.val) {} - - operator Under() const - { return val; } - - Return - operator+() const - { return val; } - - Rep - operator-() const - { return -val; } - - friend Rep - operator+(Rep lhs, Rep rhs) - { return lhs.val + rhs.val; } - - friend Rep - operator-(Rep lhs, Rep rhs) - { return lhs.val - rhs.val; } - - friend Rep - operator*(Rep lhs, Rep rhs) - { return lhs.val * rhs.val; } - - friend Rep - operator/(Rep lhs, Rep rhs) - { return lhs.val / rhs.val; } - - friend auto operator<=>(Rep, Rep) = default; - - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const Rep& t) - { return os << t.val << WIDEN("[via <<]"); } - - Under val; -}; - -template -struct std::common_type, Rep> -{ - using type = Rep>; -}; - -template - requires std::is_integral_v -struct std::common_type, Other> -{ - using type = Rep>; -}; - -template - requires std::is_integral_v -struct std::common_type> - : std::common_type, Other> -{ }; - -template -struct std::numeric_limits> - : std::numeric_limits -{ }; - -template -struct std::formatter, CharT> - : std::formatter -{ - template - typename std::basic_format_context::iterator - format(const Rep& t, std::basic_format_context& ctx) const - { - constexpr std::basic_string_view suffix = WIDEN("[via format]"); - auto out = std::formatter::format(t.val, ctx); - return std::ranges::copy(suffix, out).out; - } -}; - using deciseconds = duration; template diff --git a/libstdc++-v3/testsuite/std/time/format/nonlocking.cc b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc new file mode 100644 index 00000000000..c7aac75cb83 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/nonlocking.cc @@ -0,0 +1,164 @@ +// { dg-do compile { target c++23 } } + +#include +#include +#include "custom_rep.h" + +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::day>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::month>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::weekday>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::weekday_indexed>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::weekday_last>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::month_day>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::month_day_last>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::month_weekday>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::month_weekday_last>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year_month>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year_month_day>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year_month_day_last>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year_month_weekday>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::year_month_weekday_last>); + +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::local_info>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::sys_info>); +#endif + +template +using local_time_fmt + = decltype(std::chrono::local_time_format(std::chrono::local_time{})); + +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::seconds>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::duration>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::duration>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::local_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::sys_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::utc_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::gps_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::tai_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::file_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + local_time_fmt>); + +using BufferedDuration = std::chrono::duration>; + +static_assert(!std::enable_nonlocking_formatter_optimization< + BufferedDuration>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::local_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::sys_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::utc_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::gps_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::tai_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::file_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + local_time_fmt>); + +template<> +inline constexpr bool + std::enable_nonlocking_formatter_optimization> = true; + +using NonBufferedRep = std::chrono::duration>; + +static_assert(std::enable_nonlocking_formatter_optimization< + NonBufferedRep>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::local_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::sys_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::utc_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::gps_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::tai_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::file_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + local_time_fmt>); + +using NonBufferedDuration = std::chrono::duration>; + +template<> +inline constexpr bool + std::enable_nonlocking_formatter_optimization = true; + +static_assert(std::enable_nonlocking_formatter_optimization< + NonBufferedDuration>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::local_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::sys_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::utc_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::gps_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::tai_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::file_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + local_time_fmt>); + +#if _GLIBCXX_USE_CXX11_ABI || !_GLIBCXX_USE_DUAL_ABI +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); + +struct MyTimeZone : std::chrono::time_zone +{}; + +template<> +struct std::chrono::zoned_traits +{ + static const MyTimeZone* default_zone(); + static const MyTimeZone* locate_zone(std::string_view name); +}; + +static_assert(!std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(!std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(!std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +static_assert(!std::enable_nonlocking_formatter_optimization< + std::chrono::zoned_time>); +#endif +