From 2366f3cd4a0c4f20a925008bd27e020ebaa2b160 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 27 Sep 2024 21:36:37 +0200 Subject: [PATCH 01/37] constexpr stable_sort --- libcxx/include/__algorithm/sort.h | 2 +- libcxx/include/__algorithm/stable_sort.h | 48 +++++++++++++----------- libcxx/include/__memory/destruct_n.h | 20 +++++----- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h index ed828b6d72314..0e4d68ca56560 100644 --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -240,7 +240,7 @@ __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, // Sort the iterator range [__first, __last) using the comparator __comp using // the insertion sort algorithm. template -_LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) { using _Ops = _IterOps<_AlgPolicy>; diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 43f591ac02b01..6e9fb3a7eca17 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -69,7 +69,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( } template -_LIBCPP_HIDE_FROM_ABI void __merge_move_construct( +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, @@ -107,7 +107,7 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_construct( } template -_LIBCPP_HIDE_FROM_ABI void __merge_move_assign( +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_assign( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, @@ -135,19 +135,21 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_assign( } template -void __stable_sort(_RandomAccessIterator __first, - _RandomAccessIterator __last, - _Compare __comp, - typename iterator_traits<_RandomAccessIterator>::difference_type __len, - typename iterator_traits<_RandomAccessIterator>::value_type* __buff, - ptrdiff_t __buff_size); +_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( + _RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __buff, + ptrdiff_t __buff_size); template -void __stable_sort_move(_RandomAccessIterator __first1, - _RandomAccessIterator __last1, - _Compare __comp, - typename iterator_traits<_RandomAccessIterator>::difference_type __len, - typename iterator_traits<_RandomAccessIterator>::value_type* __first2) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( + _RandomAccessIterator __first1, + _RandomAccessIterator __last1, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __first2) { using _Ops = _IterOps<_AlgPolicy>; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; @@ -191,12 +193,13 @@ struct __stable_sort_switch { }; template -void __stable_sort(_RandomAccessIterator __first, - _RandomAccessIterator __last, - _Compare __comp, - typename iterator_traits<_RandomAccessIterator>::difference_type __len, - typename iterator_traits<_RandomAccessIterator>::value_type* __buff, - ptrdiff_t __buff_size) { +_LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( + _RandomAccessIterator __first, + _RandomAccessIterator __last, + _Compare __comp, + typename iterator_traits<_RandomAccessIterator>::difference_type __len, + typename iterator_traits<_RandomAccessIterator>::value_type* __buff, + ptrdiff_t __buff_size) { typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; switch (__len) { @@ -236,7 +239,7 @@ void __stable_sort(_RandomAccessIterator __first, } template -inline _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) { using value_type = typename iterator_traits<_RandomAccessIterator>::value_type; using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; @@ -255,13 +258,14 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, } template -inline _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp); } template -inline _LIBCPP_HIDE_FROM_ABI void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void +stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { std::stable_sort(__first, __last, __less<>()); } diff --git a/libcxx/include/__memory/destruct_n.h b/libcxx/include/__memory/destruct_n.h index 66adefb0f51fc..db227a4ea1dc7 100644 --- a/libcxx/include/__memory/destruct_n.h +++ b/libcxx/include/__memory/destruct_n.h @@ -25,35 +25,35 @@ struct __destruct_n { size_t __size_; template - _LIBCPP_HIDE_FROM_ABI void __process(_Tp* __p, false_type) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp* __p, false_type) _NOEXCEPT { for (size_t __i = 0; __i < __size_; ++__i, ++__p) __p->~_Tp(); } template - _LIBCPP_HIDE_FROM_ABI void __process(_Tp*, true_type) _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __process(_Tp*, true_type) _NOEXCEPT {} - _LIBCPP_HIDE_FROM_ABI void __incr(false_type) _NOEXCEPT { ++__size_; } - _LIBCPP_HIDE_FROM_ABI void __incr(true_type) _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(false_type) _NOEXCEPT { ++__size_; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr(true_type) _NOEXCEPT {} - _LIBCPP_HIDE_FROM_ABI void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; } - _LIBCPP_HIDE_FROM_ABI void __set(size_t, true_type) _NOEXCEPT {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, false_type) _NOEXCEPT { __size_ = __s; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t, true_type) _NOEXCEPT {} public: - _LIBCPP_HIDE_FROM_ABI explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {} template - _LIBCPP_HIDE_FROM_ABI void __incr() _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr() _NOEXCEPT { __incr(integral_constant::value>()); } template - _LIBCPP_HIDE_FROM_ABI void __set(size_t __s, _Tp*) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __set(size_t __s, _Tp*) _NOEXCEPT { __set(__s, integral_constant::value>()); } template - _LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void operator()(_Tp* __p) _NOEXCEPT { __process(__p, integral_constant::value>()); } }; From 0ea964a2ef72971bac7dd9d657291249492fef93 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 27 Sep 2024 21:36:54 +0200 Subject: [PATCH 02/37] tests --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 233 ++++++++++++------ 1 file changed, 163 insertions(+), 70 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 4301d22027de8..92803c89dbcb7 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -14,7 +14,9 @@ // void // stable_sort(Iter first, Iter last); +#include <__config> #include +#include #include #include #include @@ -23,8 +25,6 @@ #include "count_new.h" #include "test_macros.h" -std::mt19937 randomness; - template void test_sort_helper(RI f, RI l) @@ -80,66 +80,149 @@ test_sort_() } } -void -test_larger_sorts(int N, int M) -{ - assert(N != 0); - assert(M != 0); - // create array length N filled with M different numbers - int* array = new int[N]; - int x = 0; - for (int i = 0; i < N; ++i) - { - array[i] = x; - if (++x == M) - x = 0; +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array init_saw_tooth_pattern() { + std::array array; + for (int i = 0, x = 0; i < N; ++i) { + array[i] = x; + if (++x == M) + x = 0; + } + return array; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_saw_tooth_pattern() { + std::array array = init_saw_tooth_pattern(); + std::stable_sort(array.begin(), array.end()); + return array; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_already_sorted() { + std::array array = sort_saw_tooth_pattern(); + std::stable_sort(array.begin(), array.end()); + return array; +} + +template +std::array sort_reversely_sorted() { + std::array array = sort_saw_tooth_pattern(); + std::reverse(array.begin(), array.end()); + std::stable_sort(array.begin(), array.end()); + return array; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_swapped_sorted_ranges() { + std::array array = sort_saw_tooth_pattern(); + std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); + std::stable_sort(array.begin(), array.end()); + return array; +} + +template +std::array sort_reversely_swapped_sorted_ranges() { + std::array array = sort_saw_tooth_pattern(); + std::reverse(array.begin(), array.end()); + std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); + std::stable_sort(array.begin(), array.end()); + return array; +} + +#if _LIBCPP_STD_VER >= 26 +# define COMPILE_OR_RUNTIME_ASSERT(func) \ + if consteval { \ + static_assert(func); \ + } else { \ + assert(func); \ } - // test saw tooth pattern - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test random pattern - std::shuffle(array, array+N, randomness); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test sorted pattern - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test reverse sorted pattern - std::reverse(array, array+N); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test swap ranges 2 pattern - std::swap_ranges(array, array+N/2, array+N/2); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test reverse swap ranges 2 pattern - std::reverse(array, array+N); - std::swap_ranges(array, array+N/2, array+N/2); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - delete [] array; +#else +# define COMPILE_OR_RUNTIME_ASSERT(func) assert(func); +#endif + +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { + static_assert(N > 0, ""); + static_assert(M > 0, ""); + + { // test saw tooth pattern + _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_saw_tooth_pattern(); + COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + } + +#if _LIBCPP_STD_VER >= 26 + if !consteval +#endif + { // test random pattern + // random-number generators not constexpr-friendly + static std::mt19937 randomness; + std::array array = init_saw_tooth_pattern(); + std::shuffle(array.begin(), array.end(), randomness); + std::stable_sort(array.begin(), array.end()); + assert(std::is_sorted(array.begin(), array.end())); + } + + { // test sorted pattern + _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_already_sorted(); + COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + } + +#if _LIBCPP_STD_VER >= 26 + if !consteval +#endif + { // test reverse sorted pattern + // consteval error: "constexpr evaluation hit maximum step limit" + std::array array = sort_reversely_sorted(); + assert(std::is_sorted(array.begin(), array.end())); + } + + { // test swap ranges 2 pattern + _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_swapped_sorted_ranges(); + COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + } + +#if _LIBCPP_STD_VER >= 26 + if !consteval +#endif + { // test reverse swap ranges 2 pattern + // consteval error: "constexpr evaluation hit maximum step limit" + std::array array = sort_reversely_swapped_sorted_ranges(); + assert(std::is_sorted(array.begin(), array.end())); + } } -void -test_larger_sorts(int N) -{ - test_larger_sorts(N, 1); - test_larger_sorts(N, 2); - test_larger_sorts(N, 3); - test_larger_sorts(N, N/2-1); - test_larger_sorts(N, N/2); - test_larger_sorts(N, N/2+1); - test_larger_sorts(N, N-2); - test_larger_sorts(N, N-1); - test_larger_sorts(N, N); +template +_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); } -int main(int, char**) -{ - // test null range +#if _LIBCPP_STD_VER >= 26 +# define COMPILE_AND_RUNTIME_CALL(func) \ + func; \ + static_assert((func, true)); +#else +# define COMPILE_AND_RUNTIME_CALL(func) func; +#endif + +int main(int, char**) { + { // test null range int d = 0; std::stable_sort(&d, &d); - // exhaustively test all possibilities up to length 8 +#if _LIBCPP_STD_VER >= 26 + static_assert((std::stable_sort(&d, &d), true)); +#endif + } + + { // exhaustively test all possibilities up to length 8 test_sort_<1>(); test_sort_<2>(); test_sort_<3>(); @@ -148,22 +231,32 @@ int main(int, char**) test_sort_<6>(); test_sort_<7>(); test_sort_<8>(); + } - test_larger_sorts(256); - test_larger_sorts(257); - test_larger_sorts(499); - test_larger_sorts(500); - test_larger_sorts(997); - test_larger_sorts(1000); - test_larger_sorts(1009); - -#if !defined(TEST_HAS_NO_EXCEPTIONS) - { // check that the algorithm works without memory - std::vector vec(150, 3); - getGlobalMemCounter()->throw_after = 0; - std::stable_sort(vec.begin(), vec.end()); - } -#endif // !defined(TEST_HAS_NO_EXCEPTIONS) + { // larger sorts + // run- and conditionally compile-time tests + test_larger_sorts<256>(); + test_larger_sorts<257>(); +#if _LIBCPP_STD_VER >= 26 + static_assert((test_larger_sorts<256>(), true)); + static_assert((test_larger_sorts<257>(), true)); +#endif + + // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" + test_larger_sorts<499>(); + test_larger_sorts<500>(); + test_larger_sorts<997>(); + test_larger_sorts<1000>(); + test_larger_sorts<1009>(); + } + +#ifndef TEST_HAS_NO_EXCEPTIONS + { // check that the algorithm works without memory + std::vector vec(150, 3); + getGlobalMemCounter()->throw_after = 0; + std::stable_sort(vec.begin(), vec.end()); + } +#endif return 0; } From 2a4251654665527353e32ee39981131147d6b28e Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 27 Sep 2024 21:48:37 +0200 Subject: [PATCH 03/37] update algorithm synopsis --- libcxx/include/algorithm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 14355d63f2901..a093c6ad21b70 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1530,11 +1530,11 @@ template sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp); template - void + constexpr void // constexpr in C++26 stable_sort(RandomAccessIterator first, RandomAccessIterator last); template - void + constexpr void // constexpr in C++26 stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp); template From 7cf77e73c43675b39e403dd74bfbfb6c6020bfc4 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 27 Sep 2024 21:50:51 +0200 Subject: [PATCH 04/37] update docs --- libcxx/docs/Status/Cxx2cPapers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 6659d815612d0..c64b32ee00ab5 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -2,7 +2,7 @@ "`P2497R0 `__","Testing for success or failure of ```` functions","2023-06 (Varna)","|Complete|","18","" "`P2592R3 `__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","","" "`P2587R3 `__","``to_string`` or not ``to_string``","2023-06 (Varna)","","","" -"`P2562R1 `__","``constexpr`` Stable Sorting","2023-06 (Varna)","","","" +"`P2562R1 `__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Complete|","20.0","" "`P2545R4 `__","Read-Copy Update (RCU)","2023-06 (Varna)","","","" "`P2530R3 `__","Hazard Pointers for C++26","2023-06 (Varna)","","","" "`P2538R1 `__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18","" From 05a13a74d94ae4a0cd64ce73efc6fb1f1d9c9ac8 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 2 Oct 2024 22:39:53 +0200 Subject: [PATCH 05/37] paper status: partial --- libcxx/docs/Status/Cxx2cPapers.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index c64b32ee00ab5..0827aeb96a2c2 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -2,7 +2,7 @@ "`P2497R0 `__","Testing for success or failure of ```` functions","2023-06 (Varna)","|Complete|","18","" "`P2592R3 `__","Hashing support for ``std::chrono`` value classes","2023-06 (Varna)","","","" "`P2587R3 `__","``to_string`` or not ``to_string``","2023-06 (Varna)","","","" -"`P2562R1 `__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Complete|","20.0","" +"`P2562R1 `__","``constexpr`` Stable Sorting","2023-06 (Varna)","|Partial|","20.0","" "`P2545R4 `__","Read-Copy Update (RCU)","2023-06 (Varna)","","","" "`P2530R3 `__","Hazard Pointers for C++26","2023-06 (Varna)","","","" "`P2538R1 `__","ADL-proof ``std::projected``","2023-06 (Varna)","|Complete|","18","" From e5b51d9cf58ff6fed8c573c25a2839f4436be536 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 19:13:04 +0200 Subject: [PATCH 06/37] remove include of internal header --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 92803c89dbcb7..14560a98fff72 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -14,7 +14,6 @@ // void // stable_sort(Iter first, Iter last); -#include <__config> #include #include #include From 2ae4f9fd3528c151e74b5aff259c0199a5554367 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 19:15:42 +0200 Subject: [PATCH 07/37] replace _LIBCPP_CONSTEXPR_SINCE_CXX26 by TEST_CONSTEXPR_CXX26 --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 14560a98fff72..89cf06bad3046 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -80,7 +80,7 @@ test_sort_() } template -_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array init_saw_tooth_pattern() { +TEST_CONSTEXPR_CXX26 std::array init_saw_tooth_pattern() { std::array array; for (int i = 0, x = 0; i < N; ++i) { array[i] = x; @@ -91,14 +91,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array init_saw_tooth_pattern() { } template -_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_saw_tooth_pattern() { +TEST_CONSTEXPR_CXX26 std::array sort_saw_tooth_pattern() { std::array array = init_saw_tooth_pattern(); std::stable_sort(array.begin(), array.end()); return array; } template -_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_already_sorted() { +TEST_CONSTEXPR_CXX26 std::array sort_already_sorted() { std::array array = sort_saw_tooth_pattern(); std::stable_sort(array.begin(), array.end()); return array; @@ -113,7 +113,7 @@ std::array sort_reversely_sorted() { } template -_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array sort_swapped_sorted_ranges() { +TEST_CONSTEXPR_CXX26 std::array sort_swapped_sorted_ranges() { std::array array = sort_saw_tooth_pattern(); std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); std::stable_sort(array.begin(), array.end()); @@ -141,12 +141,12 @@ std::array sort_reversely_swapped_sorted_ranges() { #endif template -_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { +TEST_CONSTEXPR_CXX26 void test_larger_sorts() { static_assert(N > 0, ""); static_assert(M > 0, ""); { // test saw tooth pattern - _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_saw_tooth_pattern(); + TEST_CONSTEXPR_CXX26 std::array array = sort_saw_tooth_pattern(); COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } @@ -163,7 +163,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { } { // test sorted pattern - _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_already_sorted(); + TEST_CONSTEXPR_CXX26 std::array array = sort_already_sorted(); COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } @@ -177,7 +177,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { } { // test swap ranges 2 pattern - _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array array = sort_swapped_sorted_ranges(); + TEST_CONSTEXPR_CXX26 std::array array = sort_swapped_sorted_ranges(); COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } @@ -192,7 +192,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { } template -_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() { +TEST_CONSTEXPR_CXX26 void test_larger_sorts() { test_larger_sorts(); test_larger_sorts(); test_larger_sorts(); From bf479373697179f48a80ac1c37fbc646c3748700 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 4 Oct 2024 19:14:05 +0200 Subject: [PATCH 08/37] documentation: use proper function declaration --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 89cf06bad3046..cb32174a2ca0c 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -8,11 +8,9 @@ // -// template -// requires ShuffleIterator -// && LessThanComparable -// void -// stable_sort(Iter first, Iter last); +// template +// constexpr void // constexpr in C++26 +// stable_sort(RandomAccessIterator first, RandomAccessIterator last); #include #include From 5081abde98ea020984c90491f000f42b03d1e3ba Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 5 Oct 2024 22:13:23 +0200 Subject: [PATCH 09/37] workaround for gcc bug with placement new --- libcxx/include/__algorithm/stable_sort.h | 38 ++++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 6e9fb3a7eca17..6ed8ccc060790 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -35,6 +35,18 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) +# define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer) \ + do { \ + [__placement_args] { ::new (__placement_args) __type(__new_initializer); }(); \ + } while (0) +#else +# define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer) \ + do { \ + ::new (__placement_args) __type(__new_initializer); \ + } while (0) +#endif + template _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( _BidirectionalIterator __first1, @@ -48,19 +60,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( __destruct_n __d(0); unique_ptr __h(__first2, __d); value_type* __last2 = __first2; - ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move(__first1)); __d.template __incr(); for (++__last2; ++__first1 != __last1; ++__last2) { value_type* __j2 = __last2; value_type* __i2 = __j2; if (__comp(*__first1, *--__i2)) { - ::new ((void*)__j2) value_type(std::move(*__i2)); + __STABLE_SORT_NEW((void*)__j2, value_type, std::move(*__i2)); __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); *__j2 = _Ops::__iter_move(__first1); } else { - ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move(__first1)); __d.template __incr(); } } @@ -84,22 +96,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( for (; true; ++__result) { if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) - ::new ((void*)__result) value_type(_Ops::__iter_move(__first2)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2)); __h.release(); return; } if (__first2 == __last2) { for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) - ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1)); __h.release(); return; } if (__comp(*__first2, *__first1)) { - ::new ((void*)__result) value_type(_Ops::__iter_move(__first2)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2)); __d.template __incr(); ++__first2; } else { - ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1)); __d.template __incr(); ++__first1; } @@ -157,21 +169,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( case 0: return; case 1: - ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); return; case 2: __destruct_n __d(0); unique_ptr __h2(__first2, __d); if (__comp(*--__last1, *__first1)) { - ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1)); __d.template __incr(); ++__first2; - ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); } else { - ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); __d.template __incr(); ++__first2; - ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1)); } __h2.release(); return; @@ -269,8 +281,8 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { std::stable_sort(__first, __last, __less<>()); } +#undef __STABLE_SORT_NEW _LIBCPP_END_NAMESPACE_STD - _LIBCPP_POP_MACROS #endif // _LIBCPP___ALGORITHM_STABLE_SORT_H From 9b139d384bfc478b16c201c311d80792bb1ecf78 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 6 Oct 2024 15:00:48 +0200 Subject: [PATCH 10/37] workaround for gcc bug with placement new: fix lambda capturing --- libcxx/include/__algorithm/stable_sort.h | 40 ++++++++++++++---------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 6ed8ccc060790..dc418fd19ad6b 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -35,15 +35,22 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +#define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ + do { \ + ::new (__placement_arg) __type(__new_initializer_func(__new_initializer_arg)); \ + } while (0) + #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) -# define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer) \ +# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ do { \ - [__placement_args] { ::new (__placement_args) __type(__new_initializer); }(); \ + [__placement_arg, &__new_initializer_arg] { \ + __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ + }(); \ } while (0) #else -# define __STABLE_SORT_NEW(__placement_args, __type, __new_initializer) \ +# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ do { \ - ::new (__placement_args) __type(__new_initializer); \ + __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ } while (0) #endif @@ -60,19 +67,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( __destruct_n __d(0); unique_ptr __h(__first2, __d); value_type* __last2 = __first2; - __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); for (++__last2; ++__first1 != __last1; ++__last2) { value_type* __j2 = __last2; value_type* __i2 = __j2; if (__comp(*__first1, *--__i2)) { - __STABLE_SORT_NEW((void*)__j2, value_type, std::move(*__i2)); + __STABLE_SORT_NEW((void*)__j2, value_type, std::move, *__i2); __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); *__j2 = _Ops::__iter_move(__first1); } else { - __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); } } @@ -96,22 +103,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( for (; true; ++__result) { if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2); __h.release(); return; } if (__first2 == __last2) { for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1); __h.release(); return; } if (__comp(*__first2, *__first1)) { - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first2)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2); __d.template __incr(); ++__first2; } else { - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first1; } @@ -169,21 +176,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( case 0: return; case 1: - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); return; case 2: __destruct_n __d(0); unique_ptr __h2(__first2, __d); if (__comp(*--__last1, *__first1)) { - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); } else { - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__first1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move(__last1)); + __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1); } __h2.release(); return; @@ -282,6 +289,7 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { } #undef __STABLE_SORT_NEW +#undef __STABLE_SORT_NEW_IMPL _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS From 7dbd0043c33ec316ce1b12aaef33e6c96790809c Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 6 Oct 2024 21:16:33 +0200 Subject: [PATCH 11/37] workaround for gcc bug with placement new: v3 --- libcxx/include/__algorithm/stable_sort.h | 33 ++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index dc418fd19ad6b..e0ff647e08ef0 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -35,20 +35,21 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD +// Workaround for "constexpr placement new" bug in gcc (fixed in 14.2). +// See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. #define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ do { \ - ::new (__placement_arg) __type(__new_initializer_func(__new_initializer_arg)); \ + ::new ((void*)__placement_arg) __type(__new_initializer_func(__new_initializer_arg)); \ } while (0) - #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) # define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ do { \ - [__placement_arg, &__new_initializer_arg] { \ + [__placement_arg, &__new_initializer_arg] { \ __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ }(); \ } while (0) #else -# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ +# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ do { \ __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ } while (0) @@ -67,19 +68,19 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( __destruct_n __d(0); unique_ptr __h(__first2, __d); value_type* __last2 = __first2; - __STABLE_SORT_NEW((void*)__last2, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__last2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); for (++__last2; ++__first1 != __last1; ++__last2) { value_type* __j2 = __last2; value_type* __i2 = __j2; if (__comp(*__first1, *--__i2)) { - __STABLE_SORT_NEW((void*)__j2, value_type, std::move, *__i2); + __STABLE_SORT_NEW(__j2, value_type, std::move, *__i2); __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); *__j2 = _Ops::__iter_move(__first1); } else { - __STABLE_SORT_NEW((void*)__j2, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__j2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); } } @@ -103,22 +104,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( for (; true; ++__result) { if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2); + __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2); __h.release(); return; } if (__first2 == __last2) { for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); __h.release(); return; } if (__comp(*__first2, *__first1)) { - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first2); + __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2); __d.template __incr(); ++__first2; } else { - __STABLE_SORT_NEW((void*)__result, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first1; } @@ -176,21 +177,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( case 0: return; case 1: - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); return; case 2: __destruct_n __d(0); unique_ptr __h2(__first2, __d); if (__comp(*--__last1, *__first1)) { - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1); + __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); } else { - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __first1); + __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW((void*)__first2, value_type, _Ops::__iter_move, __last1); + __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1); } __h2.release(); return; From 363eb7c451b95271873b454f04aa3d3dadad9979 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 6 Oct 2024 21:26:55 +0200 Subject: [PATCH 12/37] workaround for gcc bug with placement new: v4 --- libcxx/include/__algorithm/stable_sort.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index e0ff647e08ef0..c56a1701d4c25 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -74,7 +74,10 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( value_type* __j2 = __last2; value_type* __i2 = __j2; if (__comp(*__first1, *--__i2)) { - __STABLE_SORT_NEW(__j2, value_type, std::move, *__i2); + { + value_type& __tmp = *__i2; + __STABLE_SORT_NEW(__j2, value_type, std::move, __tmp); + } __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); From 11310980343b68471d279929bc59451e120d58a4 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 11 Oct 2024 21:53:13 +0200 Subject: [PATCH 13/37] workaround for gcc bug with placement new: v5 (test) --- libcxx/include/__algorithm/stable_sort.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index c56a1701d4c25..d1f457ec47c67 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -122,7 +122,12 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( __d.template __incr(); ++__first2; } else { - __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); +// __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); +#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) + [__result, &__first1] { ::new (__result) value_type(_Ops::__iter_move(__first1)); }(); +#else + ::new (__result) value_type(_Ops::__iter_move(__first1)); +#endif __d.template __incr(); ++__first1; } From 2aada1a62b38db06ed72f4e5d8ee5aee433bbf6e Mon Sep 17 00:00:00 2001 From: PaulXiCao Date: Sat, 12 Oct 2024 09:14:30 +0000 Subject: [PATCH 14/37] workaround for gcc bug with placement new: v6 Co-authored-by: A. Jiang --- libcxx/include/__algorithm/stable_sort.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index d1f457ec47c67..3c84c5b1dd7dc 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -124,9 +124,9 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( } else { // __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) - [__result, &__first1] { ::new (__result) value_type(_Ops::__iter_move(__first1)); }(); + [__result, &__first1] { ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); }(); #else - ::new (__result) value_type(_Ops::__iter_move(__first1)); + ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); #endif __d.template __incr(); ++__first1; From 8f16d4ff6fac76f2b437c4cf2dea417c27a96724 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 18:57:43 +0200 Subject: [PATCH 15/37] workaround for gcc bug with placement new: v7 --- libcxx/include/__algorithm/stable_sort.h | 50 ++++++++---------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 3c84c5b1dd7dc..640babe4c4466 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -37,22 +37,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD // Workaround for "constexpr placement new" bug in gcc (fixed in 14.2). // See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. -#define __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ - do { \ - ::new ((void*)__placement_arg) __type(__new_initializer_func(__new_initializer_arg)); \ - } while (0) #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) -# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ - do { \ - [__placement_arg, &__new_initializer_arg] { \ - __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ - }(); \ - } while (0) +# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ + [__ptr, &__iter] { ::new ((void*)__ptr) __type(__move_func(__iter)); }() #else -# define __STABLE_SORT_NEW(__placement_arg, __type, __new_initializer_func, __new_initializer_arg) \ - do { \ - __STABLE_SORT_NEW_IMPL(__placement_arg, __type, __new_initializer_func, __new_initializer_arg); \ - } while (0) +# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ + ::new ((void*)__ptr) __type(__move_func(__iter)) #endif template @@ -68,7 +58,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( __destruct_n __d(0); unique_ptr __h(__first2, __d); value_type* __last2 = __first2; - __STABLE_SORT_NEW(__last2, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__last2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); for (++__last2; ++__first1 != __last1; ++__last2) { value_type* __j2 = __last2; @@ -76,14 +66,14 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( if (__comp(*__first1, *--__i2)) { { value_type& __tmp = *__i2; - __STABLE_SORT_NEW(__j2, value_type, std::move, __tmp); + _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, std::move, __tmp); } __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); *__j2 = _Ops::__iter_move(__first1); } else { - __STABLE_SORT_NEW(__j2, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); } } @@ -107,27 +97,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( for (; true; ++__result) { if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2); + _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2); __h.release(); return; } if (__first2 == __last2) { for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) - __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1); __h.release(); return; } if (__comp(*__first2, *__first1)) { - __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first2); + _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2); __d.template __incr(); ++__first2; } else { -// __STABLE_SORT_NEW(__result, value_type, _Ops::__iter_move, __first1); -#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) - [__result, &__first1] { ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); }(); -#else - ::new ((void*)__result) value_type(_Ops::__iter_move(__first1)); -#endif + _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first1; } @@ -185,21 +170,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( case 0: return; case 1: - __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); return; case 2: __destruct_n __d(0); unique_ptr __h2(__first2, __d); if (__comp(*--__last1, *__first1)) { - __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1); + _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); } else { - __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); __d.template __incr(); ++__first2; - __STABLE_SORT_NEW(__first2, value_type, _Ops::__iter_move, __last1); + _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1); } __h2.release(); return; @@ -297,8 +282,7 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { std::stable_sort(__first, __last, __less<>()); } -#undef __STABLE_SORT_NEW -#undef __STABLE_SORT_NEW_IMPL +#undef _LIBCPP_MOVING_PLACEMENT_NEW _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS From 2f90ac3f35926ce21902e7e445ef13e1e22e0539 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 13 Oct 2024 19:00:27 +0200 Subject: [PATCH 16/37] test: use TEST_STD_VER --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index cb32174a2ca0c..720b93e5d1779 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -127,7 +127,7 @@ std::array sort_reversely_swapped_sorted_ranges() { return array; } -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 # define COMPILE_OR_RUNTIME_ASSERT(func) \ if consteval { \ static_assert(func); \ @@ -148,7 +148,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 if !consteval #endif { // test random pattern @@ -165,7 +165,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 if !consteval #endif { // test reverse sorted pattern @@ -179,7 +179,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) } -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 if !consteval #endif { // test reverse swap ranges 2 pattern @@ -202,7 +202,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { test_larger_sorts(); } -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 # define COMPILE_AND_RUNTIME_CALL(func) \ func; \ static_assert((func, true)); @@ -214,7 +214,7 @@ int main(int, char**) { { // test null range int d = 0; std::stable_sort(&d, &d); -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 static_assert((std::stable_sort(&d, &d), true)); #endif } @@ -234,7 +234,7 @@ int main(int, char**) { // run- and conditionally compile-time tests test_larger_sorts<256>(); test_larger_sorts<257>(); -#if _LIBCPP_STD_VER >= 26 +#if TEST_STD_VER >= 26 static_assert((test_larger_sorts<256>(), true)); static_assert((test_larger_sorts<257>(), true)); #endif From c91a11af11795131d2e560f04579aa269243c2dc Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 18 Oct 2024 21:19:47 +0200 Subject: [PATCH 17/37] increase constexpr-steps as unstable abi tests cause more evaluation steps --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 720b93e5d1779..bcd5155138a16 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -12,6 +12,8 @@ // constexpr void // constexpr in C++26 // stable_sort(RandomAccessIterator first, RandomAccessIterator last); +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000 + #include #include #include @@ -234,14 +236,16 @@ int main(int, char**) { // run- and conditionally compile-time tests test_larger_sorts<256>(); test_larger_sorts<257>(); + test_larger_sorts<499>(); + test_larger_sorts<500>(); #if TEST_STD_VER >= 26 static_assert((test_larger_sorts<256>(), true)); static_assert((test_larger_sorts<257>(), true)); + static_assert((test_larger_sorts<499>(), true)); + static_assert((test_larger_sorts<500>(), true)); #endif // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" - test_larger_sorts<499>(); - test_larger_sorts<500>(); test_larger_sorts<997>(); test_larger_sorts<1000>(); test_larger_sorts<1009>(); From 47afcf17b679b0d8507fd02e92b928e82ebdd0cb Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 18 Oct 2024 22:06:51 +0200 Subject: [PATCH 18/37] simplify testing (possible b.c. increase of constexpr-steps) --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 53 +++++-------------- 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index bcd5155138a16..8302c59ef0ef5 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -12,7 +12,7 @@ // constexpr void // constexpr in C++26 // stable_sort(RandomAccessIterator first, RandomAccessIterator last); -// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 #include #include @@ -105,7 +105,7 @@ TEST_CONSTEXPR_CXX26 std::array sort_already_sorted() { } template -std::array sort_reversely_sorted() { +TEST_CONSTEXPR_CXX26 std::array sort_reversely_sorted() { std::array array = sort_saw_tooth_pattern(); std::reverse(array.begin(), array.end()); std::stable_sort(array.begin(), array.end()); @@ -121,7 +121,7 @@ TEST_CONSTEXPR_CXX26 std::array sort_swapped_sorted_ranges() { } template -std::array sort_reversely_swapped_sorted_ranges() { +TEST_CONSTEXPR_CXX26 std::array sort_reversely_swapped_sorted_ranges() { std::array array = sort_saw_tooth_pattern(); std::reverse(array.begin(), array.end()); std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); @@ -129,25 +129,14 @@ std::array sort_reversely_swapped_sorted_ranges() { return array; } -#if TEST_STD_VER >= 26 -# define COMPILE_OR_RUNTIME_ASSERT(func) \ - if consteval { \ - static_assert(func); \ - } else { \ - assert(func); \ - } -#else -# define COMPILE_OR_RUNTIME_ASSERT(func) assert(func); -#endif - template TEST_CONSTEXPR_CXX26 void test_larger_sorts() { static_assert(N > 0, ""); static_assert(M > 0, ""); { // test saw tooth pattern - TEST_CONSTEXPR_CXX26 std::array array = sort_saw_tooth_pattern(); - COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + std::array array = sort_saw_tooth_pattern(); + assert(std::is_sorted(array.begin(), array.end())); } #if TEST_STD_VER >= 26 @@ -163,29 +152,21 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { } { // test sorted pattern - TEST_CONSTEXPR_CXX26 std::array array = sort_already_sorted(); - COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + std::array array = sort_already_sorted(); + assert(std::is_sorted(array.begin(), array.end())); } -#if TEST_STD_VER >= 26 - if !consteval -#endif { // test reverse sorted pattern - // consteval error: "constexpr evaluation hit maximum step limit" std::array array = sort_reversely_sorted(); assert(std::is_sorted(array.begin(), array.end())); } { // test swap ranges 2 pattern - TEST_CONSTEXPR_CXX26 std::array array = sort_swapped_sorted_ranges(); - COMPILE_OR_RUNTIME_ASSERT(std::is_sorted(array.begin(), array.end())) + std::array array = sort_swapped_sorted_ranges(); + assert(std::is_sorted(array.begin(), array.end())); } -#if TEST_STD_VER >= 26 - if !consteval -#endif { // test reverse swap ranges 2 pattern - // consteval error: "constexpr evaluation hit maximum step limit" std::array array = sort_reversely_swapped_sorted_ranges(); assert(std::is_sorted(array.begin(), array.end())); } @@ -204,14 +185,6 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { test_larger_sorts(); } -#if TEST_STD_VER >= 26 -# define COMPILE_AND_RUNTIME_CALL(func) \ - func; \ - static_assert((func, true)); -#else -# define COMPILE_AND_RUNTIME_CALL(func) func; -#endif - int main(int, char**) { { // test null range int d = 0; @@ -233,19 +206,17 @@ int main(int, char**) { } { // larger sorts - // run- and conditionally compile-time tests + // run- and compile-time tests test_larger_sorts<256>(); test_larger_sorts<257>(); - test_larger_sorts<499>(); - test_larger_sorts<500>(); #if TEST_STD_VER >= 26 static_assert((test_larger_sorts<256>(), true)); static_assert((test_larger_sorts<257>(), true)); - static_assert((test_larger_sorts<499>(), true)); - static_assert((test_larger_sorts<500>(), true)); #endif // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" + test_larger_sorts<499>(); + test_larger_sorts<500>(); test_larger_sorts<997>(); test_larger_sorts<1000>(); test_larger_sorts<1009>(); From 61cc660f5a0f48de10cf3f767d3b8a99775bfec6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 9 Nov 2024 12:56:13 +0100 Subject: [PATCH 19/37] refactor tests: do not extract tests into separate functions --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 163 +++++++----------- 1 file changed, 60 insertions(+), 103 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 8302c59ef0ef5..e924d3562c924 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -80,96 +80,48 @@ test_sort_() } template -TEST_CONSTEXPR_CXX26 std::array init_saw_tooth_pattern() { - std::array array; - for (int i = 0, x = 0; i < N; ++i) { +TEST_CONSTEXPR_CXX26 void test_larger_sorts() { + static_assert(N != 0); + static_assert(M != 0); + + // create array length N filled with M different numbers + std::array array_; + int* const array = array_.data(); + int x = 0; + for (int i = 0; i < N; ++i) { array[i] = x; if (++x == M) x = 0; } - return array; -} - -template -TEST_CONSTEXPR_CXX26 std::array sort_saw_tooth_pattern() { - std::array array = init_saw_tooth_pattern(); - std::stable_sort(array.begin(), array.end()); - return array; -} - -template -TEST_CONSTEXPR_CXX26 std::array sort_already_sorted() { - std::array array = sort_saw_tooth_pattern(); - std::stable_sort(array.begin(), array.end()); - return array; -} - -template -TEST_CONSTEXPR_CXX26 std::array sort_reversely_sorted() { - std::array array = sort_saw_tooth_pattern(); - std::reverse(array.begin(), array.end()); - std::stable_sort(array.begin(), array.end()); - return array; -} - -template -TEST_CONSTEXPR_CXX26 std::array sort_swapped_sorted_ranges() { - std::array array = sort_saw_tooth_pattern(); - std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); - std::stable_sort(array.begin(), array.end()); - return array; -} - -template -TEST_CONSTEXPR_CXX26 std::array sort_reversely_swapped_sorted_ranges() { - std::array array = sort_saw_tooth_pattern(); - std::reverse(array.begin(), array.end()); - std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2); - std::stable_sort(array.begin(), array.end()); - return array; -} - -template -TEST_CONSTEXPR_CXX26 void test_larger_sorts() { - static_assert(N > 0, ""); - static_assert(M > 0, ""); - - { // test saw tooth pattern - std::array array = sort_saw_tooth_pattern(); - assert(std::is_sorted(array.begin(), array.end())); - } - + // test saw tooth pattern + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test random pattern #if TEST_STD_VER >= 26 - if !consteval + if !consteval // random-number generators not constexpr-friendly #endif - { // test random pattern - // random-number generators not constexpr-friendly + { static std::mt19937 randomness; - std::array array = init_saw_tooth_pattern(); - std::shuffle(array.begin(), array.end(), randomness); - std::stable_sort(array.begin(), array.end()); - assert(std::is_sorted(array.begin(), array.end())); - } - - { // test sorted pattern - std::array array = sort_already_sorted(); - assert(std::is_sorted(array.begin(), array.end())); - } - - { // test reverse sorted pattern - std::array array = sort_reversely_sorted(); - assert(std::is_sorted(array.begin(), array.end())); - } - - { // test swap ranges 2 pattern - std::array array = sort_swapped_sorted_ranges(); - assert(std::is_sorted(array.begin(), array.end())); - } - - { // test reverse swap ranges 2 pattern - std::array array = sort_reversely_swapped_sorted_ranges(); - assert(std::is_sorted(array.begin(), array.end())); + std::shuffle(array, array + N, randomness); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); } + // test sorted pattern + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test reverse sorted pattern + std::reverse(array, array + N); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test swap ranges 2 pattern + std::swap_ranges(array, array + N / 2, array + N / 2); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test reverse swap ranges 2 pattern + std::reverse(array, array + N); + std::swap_ranges(array, array + N / 2, array + N / 2); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); } template @@ -185,16 +137,16 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { test_larger_sorts(); } -int main(int, char**) { - { // test null range - int d = 0; - std::stable_sort(&d, &d); +TEST_CONSTEXPR_CXX26 void test() { + // test null range + int d = 0; + std::stable_sort(&d, &d); + + // exhaustively test all possibilities up to length 8 #if TEST_STD_VER >= 26 - static_assert((std::stable_sort(&d, &d), true)); + if !consteval #endif - } - - { // exhaustively test all possibilities up to length 8 + { test_sort_<1>(); test_sort_<2>(); test_sort_<3>(); @@ -205,30 +157,35 @@ int main(int, char**) { test_sort_<8>(); } - { // larger sorts - // run- and compile-time tests - test_larger_sorts<256>(); - test_larger_sorts<257>(); + test_larger_sorts<256>(); + test_larger_sorts<257>(); + test_larger_sorts<499>(); + test_larger_sorts<500>(); + test_larger_sorts<997>(); #if TEST_STD_VER >= 26 - static_assert((test_larger_sorts<256>(), true)); - static_assert((test_larger_sorts<257>(), true)); + if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" #endif - - // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" - test_larger_sorts<499>(); - test_larger_sorts<500>(); - test_larger_sorts<997>(); + { test_larger_sorts<1000>(); test_larger_sorts<1009>(); } -#ifndef TEST_HAS_NO_EXCEPTIONS +#if !defined(TEST_HAS_NO_EXCEPTIONS) +# if TEST_STD_VER >= 26 + if !consteval +# endif { // check that the algorithm works without memory std::vector vec(150, 3); getGlobalMemCounter()->throw_after = 0; std::stable_sort(vec.begin(), vec.end()); } -#endif +#endif // !defined(TEST_HAS_NO_EXCEPTIONS) +} +int main(int, char**) { + test(); +#if TEST_STD_VER >= 26 + static_assert((test(), true)); +#endif return 0; } From 648f1260d14b8a31a1e335db6f1e22330b6f0ccd Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 9 Nov 2024 13:04:48 +0100 Subject: [PATCH 20/37] tests: match previous formatting --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 185 +++++++++--------- 1 file changed, 96 insertions(+), 89 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index e924d3562c924..bcc4505b4c0f3 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -80,112 +80,119 @@ test_sort_() } template -TEST_CONSTEXPR_CXX26 void test_larger_sorts() { - static_assert(N != 0); - static_assert(M != 0); - - // create array length N filled with M different numbers - std::array array_; - int* const array = array_.data(); - int x = 0; - for (int i = 0; i < N; ++i) { - array[i] = x; - if (++x == M) - x = 0; - } - // test saw tooth pattern - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - // test random pattern +TEST_CONSTEXPR_CXX26 +void +test_larger_sorts() +{ + static_assert(N != 0); + static_assert(M != 0); + // create array length N filled with M different numbers + std::array array_; + int* array = array_.data(); + int x = 0; + for (int i = 0; i < N; ++i) + { + array[i] = x; + if (++x == M) + x = 0; + } + // test saw tooth pattern + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); + // test random pattern #if TEST_STD_VER >= 26 - if !consteval // random-number generators not constexpr-friendly + if !consteval // random-number generators not constexpr-friendly #endif - { - static std::mt19937 randomness; - std::shuffle(array, array + N, randomness); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - } - // test sorted pattern - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - // test reverse sorted pattern - std::reverse(array, array + N); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - // test swap ranges 2 pattern - std::swap_ranges(array, array + N / 2, array + N / 2); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - // test reverse swap ranges 2 pattern - std::reverse(array, array + N); - std::swap_ranges(array, array + N / 2, array + N / 2); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); + { + static std::mt19937 randomness; + std::shuffle(array, array+N, randomness); + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); + } + // test sorted pattern + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); + // test reverse sorted pattern + std::reverse(array, array+N); + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); + // test swap ranges 2 pattern + std::swap_ranges(array, array+N/2, array+N/2); + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); + // test reverse swap ranges 2 pattern + std::reverse(array, array+N); + std::swap_ranges(array, array+N/2, array+N/2); + std::stable_sort(array, array+N); + assert(std::is_sorted(array, array+N)); } template -TEST_CONSTEXPR_CXX26 void test_larger_sorts() { - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); +TEST_CONSTEXPR_CXX26 +void +test_larger_sorts() +{ + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); } -TEST_CONSTEXPR_CXX26 void test() { - // test null range - int d = 0; - std::stable_sort(&d, &d); - - // exhaustively test all possibilities up to length 8 +TEST_CONSTEXPR_CXX26 void test() +{ + // test null range + int d = 0; + std::stable_sort(&d, &d); + + // exhaustively test all possibilities up to length 8 #if TEST_STD_VER >= 26 - if !consteval + if !consteval #endif - { - test_sort_<1>(); - test_sort_<2>(); - test_sort_<3>(); - test_sort_<4>(); - test_sort_<5>(); - test_sort_<6>(); - test_sort_<7>(); - test_sort_<8>(); - } - - test_larger_sorts<256>(); - test_larger_sorts<257>(); - test_larger_sorts<499>(); - test_larger_sorts<500>(); - test_larger_sorts<997>(); + { + test_sort_<1>(); + test_sort_<2>(); + test_sort_<3>(); + test_sort_<4>(); + test_sort_<5>(); + test_sort_<6>(); + test_sort_<7>(); + test_sort_<8>(); + } + + test_larger_sorts<256>(); + test_larger_sorts<257>(); + test_larger_sorts<499>(); + test_larger_sorts<500>(); + test_larger_sorts<997>(); #if TEST_STD_VER >= 26 - if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" + if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" #endif - { - test_larger_sorts<1000>(); - test_larger_sorts<1009>(); - } + { + test_larger_sorts<1000>(); + test_larger_sorts<1009>(); + } #if !defined(TEST_HAS_NO_EXCEPTIONS) -# if TEST_STD_VER >= 26 - if !consteval -# endif - { // check that the algorithm works without memory - std::vector vec(150, 3); - getGlobalMemCounter()->throw_after = 0; - std::stable_sort(vec.begin(), vec.end()); - } +#if TEST_STD_VER >= 26 + if !consteval +#endif + { // check that the algorithm works without memory + std::vector vec(150, 3); + getGlobalMemCounter()->throw_after = 0; + std::stable_sort(vec.begin(), vec.end()); + } #endif // !defined(TEST_HAS_NO_EXCEPTIONS) } int main(int, char**) { - test(); + test(); #if TEST_STD_VER >= 26 - static_assert((test(), true)); + static_assert((test(), true)); #endif - return 0; + return 0; } From d24a71411937fa43d9428d5b32138e54fd2ae213 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 9 Nov 2024 13:21:56 +0100 Subject: [PATCH 21/37] disable large test at compiletime --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index bcc4505b4c0f3..eb484bc9440f2 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -168,11 +168,11 @@ TEST_CONSTEXPR_CXX26 void test() test_larger_sorts<257>(); test_larger_sorts<499>(); test_larger_sorts<500>(); - test_larger_sorts<997>(); #if TEST_STD_VER >= 26 if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" #endif { + test_larger_sorts<997>(); test_larger_sorts<1000>(); test_larger_sorts<1009>(); } From 61a5556fde397deec7e5ba250b85a0bd4624fcfc Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 9 Nov 2024 13:22:35 +0100 Subject: [PATCH 22/37] use construct_at for placement new gcc workaround --- libcxx/include/__algorithm/stable_sort.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 640babe4c4466..7048ae2caf08b 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -18,6 +18,7 @@ #include <__cstddef/ptrdiff_t.h> #include <__debug_utils/strict_weak_ordering_check.h> #include <__iterator/iterator_traits.h> +#include <__memory/construct_at.h> #include <__memory/destruct_n.h> #include <__memory/unique_ptr.h> #include <__memory/unique_temporary_buffer.h> @@ -37,9 +38,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD // Workaround for "constexpr placement new" bug in gcc (fixed in 14.2). // See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. -#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100) -# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ - [__ptr, &__iter] { ::new ((void*)__ptr) __type(__move_func(__iter)); }() +#if (_LIBCPP_STD_VER >= 20) || \ + (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)) +# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter)) #else # define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ ::new ((void*)__ptr) __type(__move_func(__iter)) From 58ab844ee49afa95b04a02ac0ed54ca07b7092b8 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 9 Nov 2024 17:20:53 +0100 Subject: [PATCH 23/37] tests: fix static asserts --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index eb484bc9440f2..8548f1b01d77a 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -84,8 +84,8 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { - static_assert(N != 0); - static_assert(M != 0); + static_assert(N != 0, ""); + static_assert(M != 0, ""); // create array length N filled with M different numbers std::array array_; int* array = array_.data(); From e9ec61509d23c1b44b0f12d66472dcb6209b4235 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 10 Nov 2024 16:49:56 +0100 Subject: [PATCH 24/37] test: gcc hits constexpr operation limit --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 8548f1b01d77a..ea5f787390a8d 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -166,12 +166,12 @@ TEST_CONSTEXPR_CXX26 void test() test_larger_sorts<256>(); test_larger_sorts<257>(); - test_larger_sorts<499>(); - test_larger_sorts<500>(); #if TEST_STD_VER >= 26 if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" #endif { + test_larger_sorts<499>(); + test_larger_sorts<500>(); test_larger_sorts<997>(); test_larger_sorts<1000>(); test_larger_sorts<1009>(); From 87b56292497dafe0b0641710c1267a363575cd21 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 22 Nov 2024 22:11:52 +0100 Subject: [PATCH 25/37] add missing CONSTEXPR26 macros --- libcxx/include/__algorithm/inplace_merge.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h index ad3fe6a7a505d..eca848ebfedd1 100644 --- a/libcxx/include/__algorithm/inplace_merge.h +++ b/libcxx/include/__algorithm/inplace_merge.h @@ -47,17 +47,17 @@ class __invert // invert the sense of a comparison _Predicate __p_; public: - _LIBCPP_HIDE_FROM_ABI __invert() {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __invert() {} - _LIBCPP_HIDE_FROM_ABI explicit __invert(_Predicate __p) : __p_(__p) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit __invert(_Predicate __p) : __p_(__p) {} template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x) { return !__p_(__x); } template - _LIBCPP_HIDE_FROM_ABI bool operator()(const _T1& __x, const _T2& __y) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool operator()(const _T1& __x, const _T2& __y) { return __p_(__y, __x); } }; @@ -69,7 +69,7 @@ template -_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge( +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __half_inplace_merge( _InputIterator1 __first1, _Sent1 __last1, _InputIterator2 __first2, @@ -94,7 +94,7 @@ _LIBCPP_HIDE_FROM_ABI void __half_inplace_merge( } template -_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge( +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __buffered_inplace_merge( _BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, @@ -125,7 +125,7 @@ _LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge( } template -void __inplace_merge( +_LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge( _BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, From a7eb8c677e560452f35c278f3f4dfbd396e62a2f Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 22 Nov 2024 22:12:29 +0100 Subject: [PATCH 26/37] simplify/fix placement new macro --- libcxx/include/__algorithm/stable_sort.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 7048ae2caf08b..858d5c1e0f9dd 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -36,10 +36,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -// Workaround for "constexpr placement new" bug in gcc (fixed in 14.2). -// See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. -#if (_LIBCPP_STD_VER >= 20) || \ - (!defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 <= 140100)) +// Making placement new available in constexpr contexts. This is necessary to work around a "constexpr placement new" +// bug in gcc (fixed in 14.2). See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. +#if _LIBCPP_STD_VER >= 20 # define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter)) #else # define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ From 50e50993aa64fdf8577987a90cc5d8a6e327b53e Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 23 Nov 2024 20:03:51 +0100 Subject: [PATCH 27/37] formatting --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 184 +++++++++--------- 1 file changed, 88 insertions(+), 96 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index ea5f787390a8d..0c8919c337e34 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -80,119 +80,111 @@ test_sort_() } template -TEST_CONSTEXPR_CXX26 -void -test_larger_sorts() -{ - static_assert(N != 0, ""); - static_assert(M != 0, ""); - // create array length N filled with M different numbers - std::array array_; - int* array = array_.data(); - int x = 0; - for (int i = 0; i < N; ++i) - { - array[i] = x; - if (++x == M) - x = 0; - } - // test saw tooth pattern - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test random pattern +TEST_CONSTEXPR_CXX26 void test_larger_sorts() { + static_assert(N != 0, ""); + static_assert(M != 0, ""); + // create array length N filled with M different numbers + std::array array_; + int* array = array_.data(); + int x = 0; + for (int i = 0; i < N; ++i) { + array[i] = x; + if (++x == M) + x = 0; + } + // test saw tooth pattern + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test random pattern #if TEST_STD_VER >= 26 - if !consteval // random-number generators not constexpr-friendly + if !consteval // random-number generators not constexpr-friendly #endif - { - static std::mt19937 randomness; - std::shuffle(array, array+N, randomness); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - } - // test sorted pattern - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test reverse sorted pattern - std::reverse(array, array+N); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test swap ranges 2 pattern - std::swap_ranges(array, array+N/2, array+N/2); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); - // test reverse swap ranges 2 pattern - std::reverse(array, array+N); - std::swap_ranges(array, array+N/2, array+N/2); - std::stable_sort(array, array+N); - assert(std::is_sorted(array, array+N)); + { + static std::mt19937 randomness; + std::shuffle(array, array + N, randomness); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + } + // test sorted pattern + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test reverse sorted pattern + std::reverse(array, array + N); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test swap ranges 2 pattern + std::swap_ranges(array, array + N / 2, array + N / 2); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); + // test reverse swap ranges 2 pattern + std::reverse(array, array + N); + std::swap_ranges(array, array + N / 2, array + N / 2); + std::stable_sort(array, array + N); + assert(std::is_sorted(array, array + N)); } template -TEST_CONSTEXPR_CXX26 -void -test_larger_sorts() -{ - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); +TEST_CONSTEXPR_CXX26 void test_larger_sorts() { + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); + test_larger_sorts(); } -TEST_CONSTEXPR_CXX26 void test() -{ - // test null range - int d = 0; - std::stable_sort(&d, &d); - - // exhaustively test all possibilities up to length 8 +TEST_CONSTEXPR_CXX26 void test() { + // test null range + int d = 0; + std::stable_sort(&d, &d); + + // exhaustively test all possibilities up to length 8 #if TEST_STD_VER >= 26 - if !consteval + if !consteval #endif - { - test_sort_<1>(); - test_sort_<2>(); - test_sort_<3>(); - test_sort_<4>(); - test_sort_<5>(); - test_sort_<6>(); - test_sort_<7>(); - test_sort_<8>(); - } - - test_larger_sorts<256>(); - test_larger_sorts<257>(); + { + test_sort_<1>(); + test_sort_<2>(); + test_sort_<3>(); + test_sort_<4>(); + test_sort_<5>(); + test_sort_<6>(); + test_sort_<7>(); + test_sort_<8>(); + } + + test_larger_sorts<256>(); + test_larger_sorts<257>(); #if TEST_STD_VER >= 26 - if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" + if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" #endif - { - test_larger_sorts<499>(); - test_larger_sorts<500>(); - test_larger_sorts<997>(); - test_larger_sorts<1000>(); - test_larger_sorts<1009>(); - } + { + test_larger_sorts<499>(); + test_larger_sorts<500>(); + test_larger_sorts<997>(); + test_larger_sorts<1000>(); + test_larger_sorts<1009>(); + } #if !defined(TEST_HAS_NO_EXCEPTIONS) -#if TEST_STD_VER >= 26 - if !consteval -#endif - { // check that the algorithm works without memory - std::vector vec(150, 3); - getGlobalMemCounter()->throw_after = 0; - std::stable_sort(vec.begin(), vec.end()); - } +# if TEST_STD_VER >= 26 + if !consteval +# endif + { // check that the algorithm works without memory + std::vector vec(150, 3); + getGlobalMemCounter()->throw_after = 0; + std::stable_sort(vec.begin(), vec.end()); + } #endif // !defined(TEST_HAS_NO_EXCEPTIONS) } int main(int, char**) { - test(); + test(); #if TEST_STD_VER >= 26 - static_assert((test(), true)); + static_assert((test(), true)); #endif - return 0; + return 0; } From af7995700adb795ba924a44dc5138d25c7dd3a9c Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 13 Dec 2024 22:04:08 +0100 Subject: [PATCH 28/37] make use of std::__construct_at --- libcxx/include/__algorithm/stable_sort.h | 34 +++++++++--------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 858d5c1e0f9dd..8f8226fdf8506 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -36,15 +36,6 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -// Making placement new available in constexpr contexts. This is necessary to work around a "constexpr placement new" -// bug in gcc (fixed in 14.2). See https://github.com/llvm/llvm-project/pull/110320#discussion_r1788557715. -#if _LIBCPP_STD_VER >= 20 -# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) std::construct_at(__ptr, __move_func(__iter)) -#else -# define _LIBCPP_MOVING_PLACEMENT_NEW(__ptr, __type, __move_func, __iter) \ - ::new ((void*)__ptr) __type(__move_func(__iter)) -#endif - template _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( _BidirectionalIterator __first1, @@ -58,7 +49,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( __destruct_n __d(0); unique_ptr __h(__first2, __d); value_type* __last2 = __first2; - _LIBCPP_MOVING_PLACEMENT_NEW(__last2, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__last2, _Ops::__iter_move(__first1)); __d.template __incr(); for (++__last2; ++__first1 != __last1; ++__last2) { value_type* __j2 = __last2; @@ -66,14 +57,14 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( if (__comp(*__first1, *--__i2)) { { value_type& __tmp = *__i2; - _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, std::move, __tmp); + std::__construct_at(__j2, std::move(__tmp)); } __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); *__j2 = _Ops::__iter_move(__first1); } else { - _LIBCPP_MOVING_PLACEMENT_NEW(__j2, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__j2, _Ops::__iter_move(__first1)); __d.template __incr(); } } @@ -97,22 +88,22 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __merge_move_construct( for (; true; ++__result) { if (__first1 == __last1) { for (; __first2 != __last2; ++__first2, (void)++__result, __d.template __incr()) - _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2); + std::__construct_at(__result, _Ops::__iter_move(__first2)); __h.release(); return; } if (__first2 == __last2) { for (; __first1 != __last1; ++__first1, (void)++__result, __d.template __incr()) - _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__result, _Ops::__iter_move(__first1)); __h.release(); return; } if (__comp(*__first2, *__first1)) { - _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first2); + std::__construct_at(__result, _Ops::__iter_move(__first2)); __d.template __incr(); ++__first2; } else { - _LIBCPP_MOVING_PLACEMENT_NEW(__result, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__result, _Ops::__iter_move(__first1)); __d.template __incr(); ++__first1; } @@ -170,21 +161,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort_move( case 0: return; case 1: - _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__first2, _Ops::__iter_move(__first1)); return; case 2: __destruct_n __d(0); unique_ptr __h2(__first2, __d); if (__comp(*--__last1, *__first1)) { - _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1); + std::__construct_at(__first2, _Ops::__iter_move(__last1)); __d.template __incr(); ++__first2; - _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__first2, _Ops::__iter_move(__first1)); } else { - _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __first1); + std::__construct_at(__first2, _Ops::__iter_move(__first1)); __d.template __incr(); ++__first2; - _LIBCPP_MOVING_PLACEMENT_NEW(__first2, value_type, _Ops::__iter_move, __last1); + std::__construct_at(__first2, _Ops::__iter_move(__last1)); } __h2.release(); return; @@ -282,7 +273,6 @@ stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) { std::stable_sort(__first, __last, __less<>()); } -#undef _LIBCPP_MOVING_PLACEMENT_NEW _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS From f26f23898649544232fd3894e67c328622dad1f9 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 13 Dec 2024 22:04:56 +0100 Subject: [PATCH 29/37] cleanup: undo unnecessary temp variable --- libcxx/include/__algorithm/stable_sort.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 8f8226fdf8506..6b28252963186 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -55,10 +55,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( value_type* __j2 = __last2; value_type* __i2 = __j2; if (__comp(*__first1, *--__i2)) { - { - value_type& __tmp = *__i2; - std::__construct_at(__j2, std::move(__tmp)); - } + std::__construct_at(__j2, std::move(*__i2)); __d.template __incr(); for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2) *__j2 = std::move(*__i2); From 96c36b28a65f9e45268414606c874cb93beafc2b Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 13 Dec 2024 22:14:08 +0100 Subject: [PATCH 30/37] test: use macro TEST_IS_CONSTANT_EVALUATED --- .../alg.sort/stable.sort/stable_sort.pass.cpp | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 0c8919c337e34..e8e84421f9b99 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -96,9 +96,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { std::stable_sort(array, array + N); assert(std::is_sorted(array, array + N)); // test random pattern -#if TEST_STD_VER >= 26 - if !consteval // random-number generators not constexpr-friendly -#endif + if (!TEST_IS_CONSTANT_EVALUATED) // random-number generators not constexpr-friendly { static std::mt19937 randomness; std::shuffle(array, array + N, randomness); @@ -142,10 +140,7 @@ TEST_CONSTEXPR_CXX26 void test() { std::stable_sort(&d, &d); // exhaustively test all possibilities up to length 8 -#if TEST_STD_VER >= 26 - if !consteval -#endif - { + if (!TEST_IS_CONSTANT_EVALUATED) { test_sort_<1>(); test_sort_<2>(); test_sort_<3>(); @@ -158,9 +153,7 @@ TEST_CONSTEXPR_CXX26 void test() { test_larger_sorts<256>(); test_larger_sorts<257>(); -#if TEST_STD_VER >= 26 - if !consteval // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" -#endif + if (!TEST_IS_CONSTANT_EVALUATED) // only runtime tests bc. error: "constexpr evaluation hit maximum step limit" { test_larger_sorts<499>(); test_larger_sorts<500>(); @@ -169,16 +162,14 @@ TEST_CONSTEXPR_CXX26 void test() { test_larger_sorts<1009>(); } -#if !defined(TEST_HAS_NO_EXCEPTIONS) -# if TEST_STD_VER >= 26 - if !consteval -# endif - { // check that the algorithm works without memory + // check that the algorithm works without memory +#ifndef TEST_HAS_NO_EXCEPTIONS + if (!TEST_IS_CONSTANT_EVALUATED) { std::vector vec(150, 3); getGlobalMemCounter()->throw_after = 0; std::stable_sort(vec.begin(), vec.end()); } -#endif // !defined(TEST_HAS_NO_EXCEPTIONS) +#endif } int main(int, char**) { From 032d66a14facd3e0b680abe6922fdcbbfc3687be Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 13 Dec 2024 22:15:46 +0100 Subject: [PATCH 31/37] test: return bool from test() --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index e8e84421f9b99..07eb8be6faae1 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -134,7 +134,7 @@ TEST_CONSTEXPR_CXX26 void test_larger_sorts() { test_larger_sorts(); } -TEST_CONSTEXPR_CXX26 void test() { +TEST_CONSTEXPR_CXX26 bool test() { // test null range int d = 0; std::stable_sort(&d, &d); @@ -170,12 +170,14 @@ TEST_CONSTEXPR_CXX26 void test() { std::stable_sort(vec.begin(), vec.end()); } #endif + + return true; } int main(int, char**) { test(); #if TEST_STD_VER >= 26 - static_assert((test(), true)); + static_assert(test()); #endif return 0; } From 18e8581deacd5c3b30aa1ab7ec8dc0b010ec0855 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 20 Dec 2024 21:01:34 +0100 Subject: [PATCH 32/37] increase constexpr-steps for gcc --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 07eb8be6faae1..7f4114b32f920 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -13,6 +13,7 @@ // stable_sort(RandomAccessIterator first, RandomAccessIterator last); // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 #include #include From 88dc8c88aa0ba2c3259fd5b044d7afe42fd77534 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 13 Jan 2025 11:09:46 -0500 Subject: [PATCH 33/37] Fix tests for stable_sort with predicate too --- libcxx/include/__algorithm/stable_sort.h | 2 +- .../alg.sort/stable.sort/stable_sort.pass.cpp | 242 +++++++++--------- .../stable.sort/stable_sort_comp.pass.cpp | 90 ++++--- 3 files changed, 184 insertions(+), 150 deletions(-) diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h index 4d546f366c45d..3cfbcf08d2c5c 100644 --- a/libcxx/include/__algorithm/stable_sort.h +++ b/libcxx/include/__algorithm/stable_sort.h @@ -42,7 +42,7 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD template -_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move( +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __insertion_sort_move( _BidirectionalIterator __first1, _BidirectionalIterator __last1, typename iterator_traits<_BidirectionalIterator>::value_type* __first2, diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 14880ac686b32..5fb349b670104 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -9,14 +9,13 @@ // // template -// constexpr void // constexpr in C++26 +// constexpr void // constexpr since C++26 // stable_sort(RandomAccessIterator first, RandomAccessIterator last); // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 #include -#include #include #include #include @@ -25,154 +24,167 @@ #include "count_new.h" #include "test_macros.h" -template -void -test_sort_helper(RI f, RI l) -{ - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - - if (f != l) - { - difference_type len = l - f; - value_type* save(new value_type[len]); - do - { - std::copy(f, l, save); - std::stable_sort(save, save+len); - assert(std::is_sorted(save, save+len)); - } while (std::next_permutation(f, l)); - delete [] save; - } +template +TEST_CONSTEXPR_CXX26 void test_all_permutations(Iterator first, Iterator last) { + using T = typename std::iterator_traits::value_type; + + do { + std::vector save(first, last); + std::stable_sort(save.begin(), save.end()); + assert(std::is_sorted(save.begin(), save.end())); + } while (std::next_permutation(first, last)); } -template -void -test_sort_driver_driver(RI f, RI l, int start, RI real_last) -{ - using value_type = typename std::iterator_traits::value_type; +template +TEST_CONSTEXPR_CXX26 void test_sort_exhaustive_impl(Iterator first, Iterator last, int start, Iterator real_last) { + using T = typename std::iterator_traits::value_type; - for (RI i = l; i > f + start;) { - *--i = static_cast(start); - if (f == i) { - test_sort_helper(f, real_last); + for (Iterator i = last; i > first + start;) { + *--i = static_cast(start); + if (first == i) { + test_all_permutations(first, real_last); } if (start > 0) - test_sort_driver_driver(f, i, start-1, real_last); + test_sort_exhaustive_impl(first, i, start - 1, real_last); } } -template -void -test_sort_driver(RI f, RI l, int start) -{ - test_sort_driver_driver(f, l, start, l); -} - -template -void test_sort_() { - V ia[sa]; - for (int i = 0; i < sa; ++i) { - test_sort_driver(ia, ia + sa, i); +template +TEST_CONSTEXPR_CXX26 void test_sort_exhaustive(int N) { + std::vector vec; + vec.resize(N); + for (int i = 0; i < N; ++i) { + test_sort_exhaustive_impl(vec.begin(), vec.end(), i, vec.end()); } } -template -void test_sort_() { - test_sort_(); - test_sort_(); -} - -template -void test_larger_sorts(int N, int M) { - assert(N != 0); - assert(M != 0); - // create array length N filled with M different numbers - V* array = new V[N]; - int x = 0; +template +TEST_CONSTEXPR_CXX26 std::vector generate_sawtooth(int N, int M) { + // Populate a sequence of length N with M different numbers + std::vector v; + T x = 0; for (int i = 0; i < N; ++i) { - array[i] = static_cast(x); + v.push_back(x); if (++x == M) x = 0; } + return v; +} + +template +TEST_CONSTEXPR_CXX26 void test_larger_sorts(int N, int M) { + assert(N != 0); + assert(M != 0); + // test saw tooth pattern - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); + { + auto v = generate_sawtooth(N, M); + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } + // test random pattern - std::shuffle(array, array + N, randomness); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); + { + if (!TEST_IS_CONSTANT_EVALUATED) { + auto v = generate_sawtooth(N, M); + std::mt19937 randomness; + std::shuffle(v.begin(), v.end(), randomness); + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } + } + // test sorted pattern - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); + { + auto v = generate_sawtooth(N, M); + std::sort(v.begin(), v.end()); + + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } + // test reverse sorted pattern - std::reverse(array, array + N); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); + { + auto v = generate_sawtooth(N, M); + std::sort(v.begin(), v.end()); + std::reverse(v.begin(), v.end()); + + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } + // test swap ranges 2 pattern - std::swap_ranges(array, array + N / 2, array + N / 2); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - // test reverse swap ranges 2 pattern - std::reverse(array, array + N); - std::swap_ranges(array, array + N / 2, array + N / 2); - std::stable_sort(array, array + N); - assert(std::is_sorted(array, array + N)); - delete[] array; -} + { + auto v = generate_sawtooth(N, M); + std::sort(v.begin(), v.end()); + std::swap_ranges(v.begin(), v.begin() + (N / 2), v.begin() + (N / 2)); + + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } -void test_larger_sorts(int N, int M) { - test_larger_sorts(N, M); - test_larger_sorts(N, M); + // test reverse swap ranges 2 pattern + { + auto v = generate_sawtooth(N, M); + std::sort(v.begin(), v.end()); + std::reverse(v.begin(), v.end()); + std::swap_ranges(v.begin(), v.begin() + (N / 2), v.begin() + (N / 2)); + + std::stable_sort(v.begin(), v.end()); + assert(std::is_sorted(v.begin(), v.end())); + } } -template -TEST_CONSTEXPR_CXX26 void test_larger_sorts() { - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); - test_larger_sorts(); +template +TEST_CONSTEXPR_CXX26 void test_larger_sorts(int N) { + test_larger_sorts(N, 1); + test_larger_sorts(N, 2); + test_larger_sorts(N, 3); + test_larger_sorts(N, N / 2 - 1); + test_larger_sorts(N, N / 2); + test_larger_sorts(N, N / 2 + 1); + test_larger_sorts(N, N - 2); + test_larger_sorts(N, N - 1); + test_larger_sorts(N, N); } +template TEST_CONSTEXPR_CXX26 bool test() { // test null range - int d = 0; - std::stable_sort(&d, &d); + { + T value = 0; + std::stable_sort(&value, &value); + } // exhaustively test all possibilities up to length 8 if (!TEST_IS_CONSTANT_EVALUATED) { - test_sort_<1>(); - test_sort_<2>(); - test_sort_<3>(); - test_sort_<4>(); - test_sort_<5>(); - test_sort_<6>(); - test_sort_<7>(); - test_sort_<8>(); + test_sort_exhaustive(1); + test_sort_exhaustive(2); + test_sort_exhaustive(3); + test_sort_exhaustive(4); + test_sort_exhaustive(5); + test_sort_exhaustive(6); + test_sort_exhaustive(7); + test_sort_exhaustive(8); } - test_larger_sorts(256); - test_larger_sorts(257); + test_larger_sorts(256); + test_larger_sorts(257); if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constexpr evaluation limit - test_larger_sorts(499); - test_larger_sorts(500); - test_larger_sorts(997); - test_larger_sorts(1000); - test_larger_sorts(1009); - test_larger_sorts(1024); - test_larger_sorts(1031); - test_larger_sorts(2053); + test_larger_sorts(499); + test_larger_sorts(500); + test_larger_sorts(997); + test_larger_sorts(1000); + test_larger_sorts(1009); + test_larger_sorts(1024); + test_larger_sorts(1031); + test_larger_sorts(2053); } // check that the algorithm works without memory #ifndef TEST_HAS_NO_EXCEPTIONS if (!TEST_IS_CONSTANT_EVALUATED) { - std::vector vec(150, 3); + std::vector vec(150, T(3)); getGlobalMemCounter()->throw_after = 0; std::stable_sort(vec.begin(), vec.end()); } @@ -182,9 +194,11 @@ TEST_CONSTEXPR_CXX26 bool test() { } int main(int, char**) { - test(); + test(); + test(); #if TEST_STD_VER >= 26 - static_assert(test()); + static_assert(test()); + static_assert(test()); #endif return 0; } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp index 5ee6d89064941..17b9c572a1729 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp @@ -9,10 +9,8 @@ // // template Compare> -// requires ShuffleIterator -// && CopyConstructible -// void -// stable_sort(Iter first, Iter last, Compare comp); +// requires ShuffleIterator && CopyConstructible +// constexpr void stable_sort(Iter first, Iter last, Compare comp); // constexpr since C++26 #include #include @@ -27,57 +25,79 @@ struct indirect_less { template - bool operator()(const P& x, const P& y) const { + TEST_CONSTEXPR_CXX26 bool operator()(const P& x, const P& y) const { return *x < *y; } }; -std::mt19937 randomness; - struct first_only { - bool operator()(const std::pair& x, const std::pair& y) const { return x.first < y.first; } + TEST_CONSTEXPR_CXX26 bool operator()(const std::pair& x, const std::pair& y) const { + return x.first < y.first; + } }; -void test() -{ - typedef std::pair P; - const int N = 1000; - const int M = 10; - std::vector

v(N); - int x = 0; - int ver = 0; - for (int i = 0; i < N; ++i) - { - v[i] = P(x, ver); - if (++x == M) - { - x = 0; - ++ver; - } - } - for (int i = 0; i < N - M; i += M) - { - std::shuffle(v.begin() + i, v.begin() + i + M, randomness); +using Pair = std::pair; + +TEST_CONSTEXPR_CXX26 std::vector generate_sawtooth(int N, int M) { + std::vector v(N); + int x = 0; + int ver = 0; + for (int i = 0; i < N; ++i) { + v[i] = Pair(x, ver); + if (++x == M) { + x = 0; + ++ver; } + } + return v; +} + +TEST_CONSTEXPR_CXX26 bool test() { + int const N = 1000; + int const M = 10; + + // test sawtooth pattern + { + auto v = generate_sawtooth(N, M); std::stable_sort(v.begin(), v.end(), first_only()); assert(std::is_sorted(v.begin(), v.end())); -} + } -int main(int, char**) -{ - test(); + // Test sorting a sequence where subsequences of elements are not sorted with <, + // but everything is already sorted with respect to the first element. This ensures + // that we don't change the order of "equivalent" elements. + { + if (!TEST_IS_CONSTANT_EVALUATED) { + auto v = generate_sawtooth(N, M); + std::mt19937 randomness; + for (int i = 0; i < N - M; i += M) { + std::shuffle(v.begin() + i, v.begin() + i + M, randomness); + } + std::stable_sort(v.begin(), v.end(), first_only()); + assert(std::is_sorted(v.begin(), v.end())); + } + } #if TEST_STD_VER >= 11 - { + { std::vector > v(1000); for (int i = 0; static_cast(i) < v.size(); ++i) - v[i].reset(new int(i)); + v[i].reset(new int(i)); std::stable_sort(v.begin(), v.end(), indirect_less()); assert(std::is_sorted(v.begin(), v.end(), indirect_less())); assert(*v[0] == 0); assert(*v[1] == 1); assert(*v[2] == 2); - } + } +#endif + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 26 + static_assert(test()); #endif return 0; From 6c108330cb520164b17d66b6c099ada67533b731 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 13 Jan 2025 14:46:04 -0500 Subject: [PATCH 34/37] Fix module issue --- libcxx/include/module.modulemap | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 69f1b7d094ada..cdac9c883ecab 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -819,7 +819,10 @@ module std [system] { module sort_heap { header "__algorithm/sort_heap.h" } module sort { header "__algorithm/sort.h" } module stable_partition { header "__algorithm/stable_partition.h" } - module stable_sort { header "__algorithm/stable_sort.h" } + module stable_sort { + header "__algorithm/stable_sort.h" + export std.memory.unique_temporary_buffer // TODO: Workaround for https://github.com/llvm/llvm-project/issues/120108 + } module swap_ranges { header "__algorithm/swap_ranges.h" } module three_way_comp_ref_type { header "__algorithm/three_way_comp_ref_type.h" } module transform { header "__algorithm/transform.h" } From d5130b5c79781e01ae654f3a61fd3b5b2885b20c Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 13 Jan 2025 14:47:16 -0500 Subject: [PATCH 35/37] Try bumping constexpr ops limit on GCC --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 5fb349b670104..9baaf20dec58e 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -13,7 +13,7 @@ // stable_sort(RandomAccessIterator first, RandomAccessIterator last); // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 -// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000 #include #include From d1d4653f066af0ebb8a244592c70ed96edee4d36 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 13 Jan 2025 15:21:26 -0500 Subject: [PATCH 36/37] Bump GCC constexpr limit --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index 9baaf20dec58e..c3a95d3fd1ec7 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -13,7 +13,7 @@ // stable_sort(RandomAccessIterator first, RandomAccessIterator last); // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 -// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=100000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000 #include #include From e2b160765cb46385290b6b818d15869498f6bf26 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 14 Jan 2025 10:23:44 -0500 Subject: [PATCH 37/37] Adjust constexpr steps --- .../alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp | 2 +- .../alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp index c3a95d3fd1ec7..b3b458808c44a 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp @@ -12,7 +12,7 @@ // constexpr void // constexpr since C++26 // stable_sort(RandomAccessIterator first, RandomAccessIterator last); -// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200000000 // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000 #include diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp index 17b9c572a1729..a2c0ca747d039 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort_comp.pass.cpp @@ -11,6 +11,9 @@ // template Compare> // requires ShuffleIterator && CopyConstructible // constexpr void stable_sort(Iter first, Iter last, Compare comp); // constexpr since C++26 +// +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=200000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=200000000 #include #include