[libcxx-commits] [libcxx] [libc++][C++26] P2562R1: `constexpr` Stable Sorting (PR #110320)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 27 12:40:37 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: None (PaulXiCao)
<details>
<summary>Changes</summary>
Closes #<!-- -->105360.
---
Full diff: https://github.com/llvm/llvm-project/pull/110320.diff
4 Files Affected:
- (modified) libcxx/include/__algorithm/sort.h (+1-1)
- (modified) libcxx/include/__algorithm/stable_sort.h (+26-22)
- (modified) libcxx/include/__memory/destruct_n.h (+10-10)
- (modified) libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/stable_sort.pass.cpp (+163-70)
``````````diff
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 0b2137dee2f77e..2e858fd15022d8 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -283,7 +283,7 @@ __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
// Sort the iterator range [__first, __last) using the comparator __comp using
// the insertion sort algorithm.
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_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 ec556aad82e8d8..4f7f8b7615781c 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -68,7 +68,7 @@ _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
}
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
-_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,
@@ -106,7 +106,7 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
}
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
-_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,
@@ -134,19 +134,21 @@ _LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
}
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-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 <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-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;
@@ -190,12 +192,13 @@ struct __stable_sort_switch {
};
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
-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) {
@@ -235,7 +238,7 @@ void __stable_sort(_RandomAccessIterator __first,
}
template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-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;
@@ -254,13 +257,14 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
}
template <class _RandomAccessIterator, class _Compare>
-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 <class _RandomAccessIterator>
-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 78635ad0af04bd..1445a909162d32 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 <class _Tp>
- _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 <class _Tp>
- _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 <class _Tp>
- _LIBCPP_HIDE_FROM_ABI void __incr() _NOEXCEPT {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __incr() _NOEXCEPT {
__incr(integral_constant<bool, is_trivially_destructible<_Tp>::value>());
}
template <class _Tp>
- _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<bool, is_trivially_destructible<_Tp>::value>());
}
template <class _Tp>
- _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<bool, is_trivially_destructible<_Tp>::value>());
}
};
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 4301d22027de85..92803c89dbcb7c 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 <algorithm>
+#include <array>
#include <cassert>
#include <iterator>
#include <random>
@@ -23,8 +25,6 @@
#include "count_new.h"
#include "test_macros.h"
-std::mt19937 randomness;
-
template <class RI>
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 <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> init_saw_tooth_pattern() {
+ std::array<int, N> array;
+ for (int i = 0, x = 0; i < N; ++i) {
+ array[i] = x;
+ if (++x == M)
+ x = 0;
+ }
+ return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_saw_tooth_pattern() {
+ std::array<int, N> array = init_saw_tooth_pattern<N, M>();
+ std::stable_sort(array.begin(), array.end());
+ return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_already_sorted() {
+ std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+ std::stable_sort(array.begin(), array.end());
+ return array;
+}
+
+template <int N, int M>
+std::array<int, N> sort_reversely_sorted() {
+ std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+ std::reverse(array.begin(), array.end());
+ std::stable_sort(array.begin(), array.end());
+ return array;
+}
+
+template <int N, int M>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> sort_swapped_sorted_ranges() {
+ std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+ std::swap_ranges(array.begin(), array.begin() + N / 2, array.begin() + N / 2);
+ std::stable_sort(array.begin(), array.end());
+ return array;
+}
+
+template <int N, int M>
+std::array<int, N> sort_reversely_swapped_sorted_ranges() {
+ std::array<int, N> array = sort_saw_tooth_pattern<N, M>();
+ 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 <int N, int M>
+_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<int, N> array = sort_saw_tooth_pattern<N, M>();
+ 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<int, N> array = init_saw_tooth_pattern<N, M>();
+ 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<int, N> array = sort_already_sorted<N, M>();
+ 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<int, N> array = sort_reversely_sorted<N, M>();
+ assert(std::is_sorted(array.begin(), array.end()));
+ }
+
+ { // test swap ranges 2 pattern
+ _LIBCPP_CONSTEXPR_SINCE_CXX26 std::array<int, N> array = sort_swapped_sorted_ranges<N, M>();
+ 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<int, N> array = sort_reversely_swapped_sorted_ranges<N, M>();
+ 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 <int N>
+_LIBCPP_CONSTEXPR_SINCE_CXX26 void test_larger_sorts() {
+ 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>();
}
-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<int> 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<int> vec(150, 3);
+ getGlobalMemCounter()->throw_after = 0;
+ std::stable_sort(vec.begin(), vec.end());
+ }
+#endif
return 0;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/110320
More information about the libcxx-commits
mailing list