Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

frederick-vs-ja
Copy link
Contributor

Fixes #119398.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner February 27, 2025 06:09
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Feb 27, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 27, 2025

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

Changes

Fixes #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:

  • (modified) libcxx/include/__algorithm/inplace_merge.h (+3-3)
  • (modified) libcxx/include/algorithm (+2-2)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge.pass.cpp (+121-80)
  • (modified) libcxx/test/std/algorithms/alg.sorting/alg.merge/inplace_merge_comp.pass.cpp (+174-108)
  • (modified) libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp (+7-2)
  • (modified) libcxx/test/support/counting_predicates.h (+14-12)
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]

@frederick-vs-ja frederick-vs-ja force-pushed the constexpr-std-inplace_merge branch from 10c2e0d to 975e7ad Compare February 27, 2025 06:29
@frederick-vs-ja frederick-vs-ja force-pushed the constexpr-std-inplace_merge branch from 975e7ad to df9720b Compare February 27, 2025 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[libc++] P2562R1: inplace_merge
2 participants