-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[libc++] Implement part of P2562R1: constexpr std::inplace_merge
#129008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Implement part of P2562R1: constexpr std::inplace_merge
#129008
Conversation
@llvm/pr-subscribers-libcxx Author: A. Jiang (frederick-vs-ja) ChangesFixes #119398. Patch is 22.96 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/129008.diff 6 Files Affected:
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 1fc31b66f4bd6..ca49196320981 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -203,7 +203,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
}
template <class _AlgPolicy, class _BidirectionalIterator, class _Compare>
-_LIBCPP_HIDE_FROM_ABI void __inplace_merge(
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare&& __comp) {
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
@@ -223,14 +223,14 @@ _LIBCPP_HIDE_FROM_ABI void __inplace_merge(
}
template <class _BidirectionalIterator, class _Compare>
-inline _LIBCPP_HIDE_FROM_ABI void inplace_merge(
+_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX26 void inplace_merge(
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) {
std::__inplace_merge<_ClassicAlgPolicy>(
std::move(__first), std::move(__middle), std::move(__last), static_cast<__comp_ref_type<_Compare> >(__comp));
}
template <class _BidirectionalIterator>
-inline _LIBCPP_HIDE_FROM_ABI void
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last) {
std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last), __less<>());
}
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 7b4cb8e496196..916d162c9fa86 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1606,11 +1606,11 @@ template <class InputIterator1, class InputIterator2, class OutputIterator, clas
InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
template <class BidirectionalIterator>
- void
+ constexpr void // constexpr in C++26
inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last);
template <class BidirectionalIterator, class Compare>
- void
+ constexpr void // constexpr in C++26
inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last, Compare comp);
template <class InputIterator1, class InputIterator2>
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
index 87bf9dc3854b3..21ade1d9fcfeb 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
@@ -8,11 +8,9 @@
// <algorithm>
-// template<BidirectionalIterator Iter>
-// requires ShuffleIterator<Iter>
-// && LessThanComparable<Iter::value_type>
-// void
-// inplace_merge(Iter first, Iter middle, Iter last);
+// template<class BidirectionalIterator>
+// constexpr void // constexpr since C++26
+// inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last);
#include <algorithm>
#include <cassert>
@@ -25,99 +23,142 @@
#if TEST_STD_VER >= 11
struct S {
- S() : i_(0) {}
- S(int i) : i_(i) {}
+ TEST_CONSTEXPR_CXX26 S() : i_(0) {}
+ TEST_CONSTEXPR_CXX26 S(int i) : i_(i) {}
+
+ TEST_CONSTEXPR_CXX26 S(const S& rhs) : i_(rhs.i_) {}
+ TEST_CONSTEXPR_CXX26 S(S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
+
+ TEST_CONSTEXPR_CXX26 S& operator=(const S& rhs) {
+ i_ = rhs.i_;
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX26 S& operator=(S&& rhs) {
+ i_ = rhs.i_;
+ rhs.i_ = -2;
+ assert(this != &rhs);
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX26 S& operator=(int i) {
+ i_ = i;
+ return *this;
+ }
+
+ TEST_CONSTEXPR_CXX26 bool operator<(const S& rhs) const { return i_ < rhs.i_; }
+ TEST_CONSTEXPR_CXX26 bool operator==(const S& rhs) const { return i_ == rhs.i_; }
+ TEST_CONSTEXPR_CXX26 bool operator==(int i) const { return i_ == i; }
+
+ TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
+
+ int i_;
+};
+#endif // TEST_STD_VER >= 11
- S(const S& rhs) : i_(rhs.i_) {}
- S( S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
-
- S& operator =(const S& rhs) { i_ = rhs.i_; return *this; }
- S& operator =( S&& rhs) { i_ = rhs.i_; rhs.i_ = -2; assert(this != &rhs); return *this; }
- S& operator =(int i) { i_ = i; return *this; }
-
- bool operator <(const S& rhs) const { return i_ < rhs.i_; }
- bool operator ==(const S& rhs) const { return i_ == rhs.i_; }
- bool operator ==(int i) const { return i_ == i; }
-
- void set(int i) { i_ = i; }
+std::mt19937 randomness;
- int i_;
- };
-#endif
+template <class Iter>
+void test_one_randomized(unsigned N, unsigned M) {
+ typedef typename std::iterator_traits<Iter>::value_type value_type;
+ value_type* ia = new value_type[N];
+
+ for (unsigned i = 0; i < N; ++i)
+ ia[i] = i;
+ std::shuffle(ia, ia + N, randomness);
+ std::sort(ia, ia + M);
+ std::sort(ia + M, ia + N);
+ std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N));
+ if (N > 0) {
+ assert(ia[0] == 0);
+ assert(ia[N - 1] == static_cast<value_type>(N - 1));
+ assert(std::is_sorted(ia, ia + N));
+ }
+ delete[] ia;
+}
-std::mt19937 randomness;
+template <class Iter>
+TEST_CONSTEXPR_CXX26 void test_one_non_randomized(unsigned N, unsigned M) {
+ typedef typename std::iterator_traits<Iter>::value_type value_type;
+ value_type* ia = new value_type[N];
+ const unsigned long small_prime = 19937;
+ const unsigned long large_prime = 212987;
+ unsigned long product_mod = small_prime;
+ for (unsigned i = 0; i < N; ++i) {
+ ia[i] = static_cast<int>(product_mod);
+ product_mod = product_mod * small_prime % large_prime;
+ }
+ std::sort(ia, ia + M);
+ std::sort(ia + M, ia + N);
+ std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N));
+ if (N > 0) {
+ assert(std::is_sorted(ia, ia + N));
+ }
+ delete[] ia;
+}
template <class Iter>
-void
-test_one(unsigned N, unsigned M)
-{
- typedef typename std::iterator_traits<Iter>::value_type value_type;
- assert(M <= N);
- value_type* ia = new value_type[N];
- for (unsigned i = 0; i < N; ++i)
- ia[i] = i;
- std::shuffle(ia, ia+N, randomness);
- std::sort(ia, ia+M);
- std::sort(ia+M, ia+N);
- std::inplace_merge(Iter(ia), Iter(ia+M), Iter(ia+N));
- if(N > 0)
- {
- assert(ia[0] == 0);
- assert(ia[N-1] == static_cast<value_type>(N-1));
- assert(std::is_sorted(ia, ia+N));
- }
- delete [] ia;
+TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
+ assert(M <= N);
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ test_one_randomized<Iter>(N, M);
+ }
+ test_one_non_randomized<Iter>(N, M);
}
template <class Iter>
-void
-test(unsigned N)
-{
- test_one<Iter>(N, 0);
- test_one<Iter>(N, N/4);
- test_one<Iter>(N, N/2);
- test_one<Iter>(N, 3*N/4);
- test_one<Iter>(N, N);
+TEST_CONSTEXPR_CXX26 void test(unsigned N) {
+ test_one<Iter>(N, 0);
+ test_one<Iter>(N, N / 4);
+ test_one<Iter>(N, N / 2);
+ test_one<Iter>(N, 3 * N / 4);
+ test_one<Iter>(N, N);
}
template <class Iter>
-void
-test()
-{
- test_one<Iter>(0, 0);
- test_one<Iter>(1, 0);
- test_one<Iter>(1, 1);
- test_one<Iter>(2, 0);
- test_one<Iter>(2, 1);
- test_one<Iter>(2, 2);
- test_one<Iter>(3, 0);
- test_one<Iter>(3, 1);
- test_one<Iter>(3, 2);
- test_one<Iter>(3, 3);
- test<Iter>(4);
- test<Iter>(100);
+TEST_CONSTEXPR_CXX26 void test() {
+ test_one<Iter>(0, 0);
+ test_one<Iter>(1, 0);
+ test_one<Iter>(1, 1);
+ test_one<Iter>(2, 0);
+ test_one<Iter>(2, 1);
+ test_one<Iter>(2, 2);
+ test_one<Iter>(3, 0);
+ test_one<Iter>(3, 1);
+ test_one<Iter>(3, 2);
+ test_one<Iter>(3, 3);
+ test<Iter>(4);
+ test<Iter>(100);
+ if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
test<Iter>(1000);
+ }
}
-int main(int, char**)
-{
- test<bidirectional_iterator<int*> >();
- test<random_access_iterator<int*> >();
- test<int*>();
+TEST_CONSTEXPR_CXX26 bool test() {
+ test<bidirectional_iterator<int*> >();
+ test<random_access_iterator<int*> >();
+ test<int*>();
#if TEST_STD_VER >= 11
- test<bidirectional_iterator<S*> >();
- test<random_access_iterator<S*> >();
- test<S*>();
-#endif
+ test<bidirectional_iterator<S*> >();
+ test<random_access_iterator<S*> >();
+ test<S*>();
+#endif // TEST_STD_VER >= 11
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER >= 26
+ static_assert(test());
+#endif // TEST_STD_VER >= 26
#if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
- {
- std::vector<int> vec(150, 3);
- getGlobalMemCounter()->throw_after = 0;
- std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end());
- assert(std::all_of(vec.begin(), vec.end(), [](int i) { return i == 3; }));
- }
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ std::vector<int> vec(150, 3);
+ getGlobalMemCounter()->throw_after = 0;
+ std::inplace_merge(vec.begin(), vec.begin() + 100, vec.end());
+ assert(std::all_of(vec.begin(), vec.end(), [](int i) { return i == 3; }));
+ }
#endif // TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
return 0;
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp
index bcde2323ad1de..3c98c8377de21 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp
@@ -8,11 +8,9 @@
// <algorithm>
-// template<BidirectionalIterator Iter, StrictWeakOrder<auto, Iter::value_type> Compare>
-// requires ShuffleIterator<Iter>
-// && CopyConstructible<Compare>
-// void
-// inplace_merge(Iter first, Iter middle, Iter last, Compare comp);
+// template<class BidirectionalIterator, class Compare>
+// constexpr void // constexpr since C++26
+// inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last, Compare comp);
#include <algorithm>
#include <cassert>
@@ -23,37 +21,46 @@
#include "test_macros.h"
#if TEST_STD_VER >= 11
-#include <memory>
+# include <memory>
struct indirect_less {
template <class P>
- bool operator()(const P& x, const P& y) const {
+ TEST_CONSTEXPR_CXX26 bool operator()(const P& x, const P& y) const {
return *x < *y;
}
};
struct S {
- S() : i_(0) {}
- S(int i) : i_(i) {}
+ TEST_CONSTEXPR_CXX26 S() : i_(0) {}
+ TEST_CONSTEXPR_CXX26 S(int i) : i_(i) {}
- S(const S& rhs) : i_(rhs.i_) {}
- S( S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
+ TEST_CONSTEXPR_CXX26 S(const S& rhs) : i_(rhs.i_) {}
+ TEST_CONSTEXPR_CXX26 S(S&& rhs) : i_(rhs.i_) { rhs.i_ = -1; }
- S& operator =(const S& rhs) { i_ = rhs.i_; return *this; }
- S& operator =( S&& rhs) { i_ = rhs.i_; rhs.i_ = -2; assert(this != &rhs); return *this; }
- S& operator =(int i) { i_ = i; return *this; }
-
- bool operator <(const S& rhs) const { return i_ < rhs.i_; }
- bool operator >(const S& rhs) const { return i_ > rhs.i_; }
- bool operator ==(const S& rhs) const { return i_ == rhs.i_; }
- bool operator ==(int i) const { return i_ == i; }
-
- void set(int i) { i_ = i; }
+ TEST_CONSTEXPR_CXX26 S& operator=(const S& rhs) {
+ i_ = rhs.i_;
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX26 S& operator=(S&& rhs) {
+ i_ = rhs.i_;
+ rhs.i_ = -2;
+ assert(this != &rhs);
+ return *this;
+ }
+ TEST_CONSTEXPR_CXX26 S& operator=(int i) {
+ i_ = i;
+ return *this;
+ }
- int i_;
- };
+ TEST_CONSTEXPR_CXX26 bool operator<(const S& rhs) const { return i_ < rhs.i_; }
+ TEST_CONSTEXPR_CXX26 bool operator>(const S& rhs) const { return i_ > rhs.i_; }
+ TEST_CONSTEXPR_CXX26 bool operator==(const S& rhs) const { return i_ == rhs.i_; }
+ TEST_CONSTEXPR_CXX26 bool operator==(int i) const { return i_ == i; }
+ TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
+ int i_;
+};
#endif // TEST_STD_VER >= 11
#include "test_iterators.h"
@@ -62,114 +69,173 @@ struct S {
std::mt19937 randomness;
template <class Iter>
-void
-test_one(unsigned N, unsigned M)
-{
- assert(M <= N);
- typedef typename std::iterator_traits<Iter>::value_type value_type;
- value_type* ia = new value_type[N];
- for (unsigned i = 0; i < N; ++i)
- ia[i] = i;
- std::shuffle(ia, ia+N, randomness);
- std::sort(ia, ia+M, std::greater<value_type>());
- std::sort(ia+M, ia+N, std::greater<value_type>());
- binary_counting_predicate<std::greater<value_type>, value_type, value_type> pred((std::greater<value_type>()));
- std::inplace_merge(Iter(ia), Iter(ia+M), Iter(ia+N), std::ref(pred));
- if(N > 0)
- {
- assert(ia[0] == static_cast<int>(N)-1);
- assert(ia[N-1] == 0);
- assert(std::is_sorted(ia, ia+N, std::greater<value_type>()));
+void test_one_randomized(unsigned N, unsigned M) {
+ typedef typename std::iterator_traits<Iter>::value_type value_type;
+
+ value_type* ia = new value_type[N];
+ for (unsigned i = 0; i < N; ++i)
+ ia[i] = i;
+ std::shuffle(ia, ia + N, randomness);
+ std::sort(ia, ia + M, std::greater<value_type>());
+ std::sort(ia + M, ia + N, std::greater<value_type>());
+ binary_counting_predicate<std::greater<value_type>, value_type, value_type> pred((std::greater<value_type>()));
+ std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N), std::ref(pred));
+ if (N > 0) {
+ assert(ia[0] == static_cast<int>(N) - 1);
+ assert(ia[N - 1] == 0);
+ assert(std::is_sorted(ia, ia + N, std::greater<value_type>()));
+#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
+ assert(pred.count() <= (N - 1));
+#endif
+ }
+ delete[] ia;
+}
+
+template <class Iter>
+TEST_CONSTEXPR_CXX26 void test_one_non_randomized(unsigned N, unsigned M) {
+ typedef typename std::iterator_traits<Iter>::value_type value_type;
+
+ value_type* ia = new value_type[N];
+ const unsigned long small_prime = 19937;
+ const unsigned long large_prime = 212987;
+ unsigned long product_mod = small_prime;
+ for (unsigned i = 0; i < N; ++i) {
+ ia[i] = static_cast<int>(product_mod);
+ product_mod = product_mod * small_prime % large_prime;
+ }
+ std::sort(ia, ia + M, std::greater<value_type>());
+ std::sort(ia + M, ia + N, std::greater<value_type>());
+ binary_counting_predicate<std::greater<value_type>, value_type, value_type> pred((std::greater<value_type>()));
+ std::inplace_merge(Iter(ia), Iter(ia + M), Iter(ia + N), std::ref(pred));
+ if (N > 0) {
+ assert(std::is_sorted(ia, ia + N, std::greater<value_type>()));
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
- assert(pred.count() <= (N-1));
+ assert(pred.count() <= (N - 1));
#endif
- }
- delete [] ia;
+ }
+ delete[] ia;
+}
+
+template <class Iter>
+TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
+ assert(M <= N);
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ test_one_randomized<Iter>(N, M);
+ }
+ test_one_non_randomized<Iter>(N, M);
}
template <class Iter>
-void
-test(unsigned N)
-{
- test_one<Iter>(N, 0);
- test_one<Iter>(N, N/4);
- test_one<Iter>(N, N/2);
- test_one<Iter>(N, 3*N/4);
- test_one<Iter>(N, N);
+TEST_CONSTEXPR_CXX26 void test(unsigned N) {
+ test_one<Iter>(N, 0);
+ test_one<Iter>(N, N / 4);
+ test_one<Iter>(N, N / 2);
+ test_one<Iter>(N, 3 * N / 4);
+ test_one<Iter>(N, N);
}
template <class Iter>
-void
-test()
-{
- test_one<Iter>(0, 0);
- test_one<Iter>(1, 0);
- test_one<Iter>(1, 1);
- test_one<Iter>(2, 0);
- test_one<Iter>(2, 1);
- test_one<Iter>(2, 2);
- test_one<Iter>(3, 0);
- test_one<Iter>(3, 1);
- test_one<Iter>(3, 2);
- test_one<Iter>(3, 3);
- test<Iter>(4);
- test<Iter>(20);
- test<Iter>(100);
+TEST_CONSTEXPR_CXX26 void test() {
+ test_one<Iter>(0, 0);
+ test_one<Iter>(1, 0);
+ test_one<Iter>(1, 1);
+ test_one<Iter>(2, 0);
+ test_one<Iter>(2, 1);
+ test_one<Iter>(2, 2);
+ test_one<Iter>(3, 0);
+ test_one<Iter>(3, 1);
+ test_one<Iter>(3, 2);
+ test_one<Iter>(3, 3);
+ test<Iter>(4);
+ test<Iter>(20);
+ test<Iter>(100);
+ if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
test<Iter>(1000);
+ }
}
struct less_by_first {
template <typename Pair>
- bool operator()(const Pair& lhs, const Pair& rhs) const {
+ TEST_CONSTEXPR_CXX26 bool operator()(const Pair& lhs, const Pair& rhs) const {
return std::less<typename Pair::first_type>()(lhs.first, rhs.first);
}
};
-void test_PR31166 ()
-{
- typedef std::pair<int, int> P;
- typedef std::vector<P> V;
- P vec[5] = {P(1, 0), P(2, 0), P(2, 1), P(2, 2), P(2, 3)};
- for ( int i = 0; i < 5; ++i ) {
- V res(vec, vec + 5);
- std::inplace_merge(res.begin(), res.begin() + i, res.end(), less_by_first());
- assert(res.size() == 5);
- assert(std::equal(res.begin(), res.end(), vec));
- }
+TEST_CONSTEXPR_CXX26 void test_PR31166() {
+ typedef std::pair<int, int> P;
+ typedef std::vector<P> V;
+ P vec[5] = {P(1, 0), P(2, 0), P(2, 1), P(2, 2), P(2, 3)};
+ for (int i = 0; i < 5; ++i) {
+ V res(vec, vec + 5);
+ std::inplace_merge(res.begin(), res.begin() + i, res.end(), less_by_first());
+ assert(res.size() == 5);
+ assert(std::equal(res.begin(), res.end(), vec));
+ }
}
-int main(int, char**)
-{
- test<bidirectional_iterator<int*> >();
- test<random_access_iterator<int*> >();
- test<int*>();
+#if TEST_STD_VER >= 11
+void test_wrapped_randomized(int N, unsigned M) {
+ std::unique_ptr<int>* ia = new std::unique_ptr<int>[N];
+ for (int i = 0; i < N; ++i)
+ ia[i].reset(new int(i));
+ std::shuffle(ia, ia + N, randomness);
+ std::sort(ia, ia + M, indirect_less());
+ std::sort(ia + M, ia + N, indirect_less());
+ std::inplace_merge(ia, ia + M, ia + N, indirect_less());
+ if (N > 0) {
+ assert(*ia[0] == 0);
+ assert(*ia[N - 1] == N - 1);
+ assert(std::is_sorted(ia, ia + N, indirect_less()));
+ }
+ delete[] ia;
+}
+
+TEST_CONSTEXPR_CXX26 void test_wrapped_non_randomized(int N, unsigned M) {
+ std::unique_ptr<int>* ia = new std::unique_ptr<int>[N];
+
+ const unsigned long small_prime = 19937;
+ const unsigned long large_prime = 212987;
+ unsigned long product_mod = small_prime;
+ for (unsigned i = 0; i < N; ++i) {
+ ia[i].reset(new int(static_cast<int>(product_mod)));
+ product_mod = product_mod * small_prime % large_prime;
+ }
+ std::sort(ia, ia + M, indirect_less());
+ std::sort(ia + M, ia + N, indirect_less());
+ std::inplace_merge(ia, ia + M, ia + N, indirect_less());
+ if (N > 0) {
+ assert(std::is_sorted(ia, ia + N, indirect_less()));
+ }
+ delete[] ia;
+}
+#endif // TEST_STD_VER >= 11
+
+TEST_CONSTEXPR_CXX26 bool test() {
+ test<bidirectional_iterator<int*> >();
+ test<random_access_iterator<int*> >();
+ test<int*>();
#if TEST_STD_VER >= 11
- test<bidirectional_iterator<S*> >();
- test<random_access_iterator<S*> >();
- test<S*>();
-
- {
- int N = 100;
- unsigned M = 50;
- std::unique_ptr<int>* ia = new std::unique_ptr<int>[N];
- for (int i = 0; i < N; ++i)
- ia[i].reset(new int(i));
- std::shuffle(ia, ia+N, randomness);
- std::sort(ia, ia+M, indirect_less());
- std::sort(ia+M, ia+N, indirect_less());
- std::inplace_merge(ia, ia+M, ia+N, indirect_less());
- if(N > 0)
- {
- assert(*ia[0] == 0);
- assert(*ia[N-1] == N-1);
- assert(std::is_sorted(ia, ia+N, indirect_less()));
- }
- delete [] ia;
- }
+ test<bidirectional_iterator<S*> >();
+ test<random_access_iterator<S*> >();
+ test<S*>();
+
+ if (!TEST_IS_CONSTANT_EVALUATED)...
[truncated]
|
210e9f3
to
129af09
Compare
129af09
to
76b5ef4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! Some comments regarding the tests.
libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
Outdated
Show resolved
Hide resolved
✅ With the latest revision this PR passed the C/C++ code formatter. |
libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
Outdated
Show resolved
Hide resolved
- Uses a simpler RNG. - Improves comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a few minor issues, otherwise LGTM!
libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp
Outdated
Show resolved
Hide resolved
- Skip 100 cases for constant evaluation. - Cite the source of MS UCRT's constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
test<random_access_iterator<int*> >(); | ||
test<int*>(); | ||
TEST_CONSTEXPR_CXX26 bool test() { | ||
support::simple_random_generator randomness; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I think I would have favoured an approach where we get rid of the randomness in these tests instead, but I think this is acceptable and certainly has benefits. No action needed.
* libcxx/test/support/min_allocator.h + Fix `tiny_size_allocator::rebind` which mistakenly said `T` instead of `U`. * libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/stable_partition.pass.cpp + `std::stable_partition` requires bidirectional iterators. * libcxx/test/std/containers/sequences/vector.bool/max_size.pass.cpp + Fix allocator type given to `std::vector<bool>`. The element types are required to match, [N5008](https://isocpp.org/files/papers/N5008.pdf) \[container.alloc.reqmts\]/5: "*Mandates:* `allocator_type::value_type` is the same as `X::value_type`." * libcxx/test/std/time/time.clock/time.clock.utc/types.compile.pass.cpp + Mark `is_steady` as `[[maybe_unused]]`, as it appears within `LIBCPP_STATIC_ASSERT` only. * libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp * libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/swap_ranges.pass.cpp * libcxx/test/std/utilities/utility/utility.swap/swap_array.pass.cpp + Fix MSVC warning C4127 "conditional expression is constant". `TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED` was introduced for this purpose, so it should be used consistently. * libcxx/test/std/numerics/numeric.ops/numeric.ops.gcd/gcd.pass.cpp + Fix `gcd()` precondition violation for `signed char`. This test case was causing `-128` to be passed as a `signed char` to `gcd()`, which is forbidden. * libcxx/test/std/containers/sequences/array/assert.iterators.pass.cpp * libcxx/test/std/containers/sequences/vector/vector.modifiers/assert.push_back.invalidation.pass.cpp * libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp + Split some REQUIRES and XFAIL lines. This is a "nice to have" for MSVC's internal test harness, which is extremely simple and looks for exact comment matches to skip tests. We can recognize the specific lines "REQUIRES: has-unix-headers" and "XFAIL: msvc", but it's a headache to maintain if they're chained with other conditions. * libcxx/test/support/sized_allocator.h + Fix x86 truncation warnings. `std::allocator` takes `std::size_t`, so we need to `static_cast`. * libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp + Fix x86 truncation warning. `std::min()` is returning `std::streamoff`, which was being unnecessarily narrowed to `std::size_t`. * libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp + Fix MSVC warning C4127 "conditional expression is constant" for an always-true branch. This was very recently introduced by #129008 making `N` constexpr. As it's a local constant just nine lines above, we don't need to test whether 100 is greater than 0.
Fixes #119398.
Drive-by:
constexpr_random.h
for pseudo-randomizing or shuffling in tests for constant evaluation.