[libcxx-commits] [libcxx] [libc++][C++26] `constexpr std::stable_sort` (part of P2562) (PR #105379)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 20 18:47:22 PDT 2024
https://github.com/PaulXiCao updated https://github.com/llvm/llvm-project/pull/105379
>From 26d5a32b4301426d1b5311da28c5edd2cee6021e Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 20 Aug 2024 22:21:57 +0200
Subject: [PATCH 1/2] constexpr stable sort; tests
---
libcxx/include/__algorithm/inplace_merge.h | 6 +-
libcxx/include/__algorithm/sort.h | 2 +-
libcxx/include/__algorithm/stable_sort.h | 63 +++--
libcxx/include/__memory/destruct_n.h | 14 +-
.../alg.sort/stable.sort/stable_sort.pass.cpp | 228 ++++++++++++------
5 files changed, 209 insertions(+), 104 deletions(-)
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 62a8bc53e23f3c..5cdaf38a1b600c 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -68,7 +68,7 @@ template <class _AlgPolicy,
class _InputIterator2,
class _Sent2,
class _OutputIterator>
-_LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __half_inplace_merge(
_InputIterator1 __first1,
_Sent1 __last1,
_InputIterator2 __first2,
@@ -93,7 +93,7 @@ _LIBCPP_HIDE_FROM_ABI void __half_inplace_merge(
}
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 void __buffered_inplace_merge(
_BidirectionalIterator __first,
_BidirectionalIterator __middle,
_BidirectionalIterator __last,
@@ -124,7 +124,7 @@ _LIBCPP_HIDE_FROM_ABI void __buffered_inplace_merge(
}
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-void __inplace_merge(
+_LIBCPP_CONSTEXPR_SINCE_CXX23 void __inplace_merge(
_BidirectionalIterator __first,
_BidirectionalIterator __middle,
_BidirectionalIterator __last,
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 0b2137dee2f77e..a90d39ac6b9262 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_CXX23 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..af97035544ca50 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -24,6 +24,7 @@
#include <__utility/move.h>
#include <__utility/pair.h>
#include <new>
+#include <vector>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -35,7 +36,7 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
-_LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
+_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI void __insertion_sort_move(
_BidirectionalIterator __first1,
_BidirectionalIterator __last1,
typename iterator_traits<_BidirectionalIterator>::value_type* __first2,
@@ -68,7 +69,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_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI void __merge_move_construct(
_InputIterator1 __first1,
_InputIterator1 __last1,
_InputIterator2 __first2,
@@ -106,7 +107,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_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI void __merge_move_assign(
_InputIterator1 __first1,
_InputIterator1 __last1,
_InputIterator2 __first2,
@@ -134,19 +135,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_CXX23 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_CXX23 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 +193,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_CXX23 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 +239,7 @@ void __stable_sort(_RandomAccessIterator __first,
}
template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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;
@@ -243,10 +247,22 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
difference_type __len = __last - __first;
__unique_temporary_buffer<value_type> __unique_buf;
pair<value_type*, ptrdiff_t> __buf(0, 0);
+ std::vector<value_type> __h_vec;
if (__len > static_cast<difference_type>(__stable_sort_switch<value_type>::value)) {
+#if _LIBCPP_STD_VER >= 23
+ if consteval {
+ __h_vec.reserve(__len);
+ __buf.first = __h_vec.data();
+ __buf.second = __h_vec.size();
+ } else {
+#else
__unique_buf = std::__allocate_unique_temporary_buffer<value_type>(__len);
__buf.first = __unique_buf.get();
__buf.second = __unique_buf.get_deleter().__count_;
+#endif
+#if _LIBCPP_STD_VER >= 23
+ }
+#endif
}
std::__stable_sort<_AlgPolicy, __comp_ref_type<_Compare> >(__first, __last, __comp, __len, __buf.first, __buf.second);
@@ -254,13 +270,14 @@ __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last,
}
template <class _RandomAccessIterator, class _Compare>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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) {
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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..f15c076e70a836 100644
--- a/libcxx/include/__memory/destruct_n.h
+++ b/libcxx/include/__memory/destruct_n.h
@@ -25,25 +25,25 @@ 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_CXX23 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_CXX23 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_CXX23 void __incr(false_type) _NOEXCEPT { ++__size_; }
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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 {}
public:
- _LIBCPP_HIDE_FROM_ABI explicit __destruct_n(size_t __s) _NOEXCEPT : __size_(__s) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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_CXX23 void __incr() _NOEXCEPT {
__incr(integral_constant<bool, is_trivially_destructible<_Tp>::value>());
}
@@ -53,7 +53,7 @@ struct __destruct_n {
}
template <class _Tp>
- _LIBCPP_HIDE_FROM_ABI void operator()(_Tp* __p) _NOEXCEPT {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 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..5f327c3d859452 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,148 @@ 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_CXX23 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_CXX23 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_CXX23 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_CXX23 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 >= 23
+# 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_CXX23 void test_larger_sorts() {
+ static_assert(N > 0, "");
+ static_assert(M > 0, "");
+
+ { // test saw tooth pattern
+ _LIBCPP_CONSTEXPR_SINCE_CXX23 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 >= 23
+ 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_CXX23 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 >= 23
+ 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_CXX23 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 >= 23
+ 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_CXX23 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 >= 23
+# 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
+ COMPILE_AND_RUNTIME_CALL(std::stable_sort(&d, &d))
+ }
+
+ { // exhaustively test all possibilities up to length 8
+ test_sort_<1>();
test_sort_<1>();
test_sort_<2>();
test_sort_<3>();
@@ -148,22 +230,28 @@ 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
+ // compile- and runtime tests
+ COMPILE_AND_RUNTIME_CALL(test_larger_sorts<256>())
+ COMPILE_AND_RUNTIME_CALL(test_larger_sorts<257>())
+
+ // 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;
}
>From 55c19d3fcacdbe49d086f9c8e20bd8a59204fa70 Mon Sep 17 00:00:00 2001
From: Paul <paulxicao7 at gmail.com>
Date: Tue, 20 Aug 2024 22:55:25 +0200
Subject: [PATCH 2/2] stable_sort: stability test (keep relative order)
---
.../alg.sort/stable.sort/stable_sort.pass.cpp | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
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 5f327c3d859452..3cc71c44d573f9 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
@@ -205,6 +205,36 @@ _LIBCPP_CONSTEXPR_SINCE_CXX23 void test_larger_sorts() {
test_larger_sorts<N, N>();
}
+namespace stability_test {
+struct Element {
+ int key;
+ int value;
+ _LIBCPP_CONSTEXPR_SINCE_CXX23 Element(int key, int value) : key(key), value(value) {}
+ _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const Element other) const {
+ return (key == other.key) and (value == other.value);
+ }
+};
+
+struct Comparer_by_key {
+ _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator()(const Element lhs, const Element rhs) { return lhs.key < rhs.key; }
+};
+
+_LIBCPP_CONSTEXPR_SINCE_CXX23 std::array<Element, 5> get_by_key_sorted_array() {
+ std::array<Element, 5> a = {Element(1, 0), Element(1, 1), Element(0, 0), Element(0, 1), Element(0, 2)};
+ std::stable_sort(a.begin(), a.end(), Comparer_by_key());
+ return a;
+}
+
+_LIBCPP_CONSTEXPR_SINCE_CXX23 void run() {
+ _LIBCPP_CONSTEXPR_SINCE_CXX23 std::array<Element, 5> a = get_by_key_sorted_array();
+ COMPILE_OR_RUNTIME_ASSERT(a[0] == Element(0, 0));
+ COMPILE_OR_RUNTIME_ASSERT(a[1] == Element(0, 1));
+ COMPILE_OR_RUNTIME_ASSERT(a[2] == Element(0, 2));
+ COMPILE_OR_RUNTIME_ASSERT(a[3] == Element(1, 0));
+ COMPILE_OR_RUNTIME_ASSERT(a[4] == Element(1, 1));
+}
+} // namespace stability_test
+
#if _LIBCPP_STD_VER >= 23
# define COMPILE_AND_RUNTIME_CALL(func) \
func; \
@@ -245,6 +275,10 @@ int main(int, char**) {
test_larger_sorts<1009>();
}
+ { // test "stable" aka leaving already sorted elements in relative order
+ COMPILE_AND_RUNTIME_CALL(stability_test::run());
+ }
+
#ifndef TEST_HAS_NO_EXCEPTIONS
{ // check that the algorithm works without memory
std::vector<int> vec(150, 3);
More information about the libcxx-commits
mailing list