[libcxx-commits] [libcxx] [libc++] Implement part of P2562R1: constexpr `std::inplace_merge` (PR #129008)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Sat Mar 1 10:32:32 PST 2025


https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/129008

>From 1b37480f62af09a8300c3a1d763d378522916dbc Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 2 Mar 2025 02:26:14 +0800
Subject: [PATCH 1/2] [libc++] Implement constexpr `std::inplace_merge`

---
 libcxx/include/__algorithm/inplace_merge.h    |  11 +-
 libcxx/include/algorithm                      |   4 +-
 .../alg.merge/inplace_merge.pass.cpp          |  91 +++++++---
 .../alg.merge/inplace_merge_comp.pass.cpp     | 158 +++++++++++++-----
 ...robust_re_difference_type.compile.pass.cpp |   9 +-
 libcxx/test/support/counting_predicates.h     |  10 +-
 6 files changed, 201 insertions(+), 82 deletions(-)

diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 1fc31b66f4bd6..6d1153be4a240 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -22,6 +22,7 @@
 #include <__functional/identity.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/reverse_iterator.h>
+#include <__memory/construct_at.h>
 #include <__memory/destruct_n.h>
 #include <__memory/unique_ptr.h>
 #include <__memory/unique_temporary_buffer.h>
@@ -106,13 +107,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __buffered_inplace_merg
     value_type* __p = __buff;
     for (_BidirectionalIterator __i = __first; __i != __middle;
          __d.template __incr<value_type>(), (void)++__i, (void)++__p)
-      ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
+      std::__construct_at(__p, _IterOps<_AlgPolicy>::__iter_move(__i));
     std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp);
   } else {
     value_type* __p = __buff;
     for (_BidirectionalIterator __i = __middle; __i != __last;
          __d.template __incr<value_type>(), (void)++__i, (void)++__p)
-      ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
+      std::__construct_at(__p, _IterOps<_AlgPolicy>::__iter_move(__i));
     typedef reverse_iterator<_BidirectionalIterator> _RBi;
     typedef reverse_iterator<value_type*> _Rv;
     typedef __invert<_Compare> _Inverted;
@@ -203,7 +204,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 +224,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
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline 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..36714ac4c53fe 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,21 +23,21 @@
 
 #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) {}
 
-    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; }
+    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; }
 
-    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; }
+    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; }
 
-    void set(int i) { i_ = i; }
+    TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
 
     int i_;
     };
@@ -49,10 +47,9 @@ std::mt19937 randomness;
 
 template <class Iter>
 void
-test_one(unsigned N, unsigned M)
+test_one_randomized(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;
@@ -70,7 +67,36 @@ test_one(unsigned N, unsigned M)
 }
 
 template <class Iter>
-void
+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>
+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>
+TEST_CONSTEXPR_CXX26 void
 test(unsigned N)
 {
     test_one<Iter>(N, 0);
@@ -81,7 +107,7 @@ test(unsigned N)
 }
 
 template <class Iter>
-void
+TEST_CONSTEXPR_CXX26 void
 test()
 {
     test_one<Iter>(0, 0);
@@ -95,11 +121,19 @@ test()
     test_one<Iter>(3, 2);
     test_one<Iter>(3, 3);
     test<Iter>(4);
-    test<Iter>(100);
-    test<Iter>(1000);
+#if defined(_LIBCPP_HARDENING_MODE)
+    if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
+#endif
+    {
+        test<Iter>(100);
+    }
+    if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
+        test<Iter>(1000);
+    }
 }
 
-int main(int, char**)
+TEST_CONSTEXPR_CXX26 bool
+test()
 {
     test<bidirectional_iterator<int*> >();
     test<random_access_iterator<int*> >();
@@ -111,8 +145,17 @@ int main(int, char**)
     test<S*>();
 #endif
 
+    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)
-    {
+    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());
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..1af1bea46ba70 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>
@@ -27,28 +25,28 @@
 
 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; }
+    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; }
 
-    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; }
+    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; }
 
-    void set(int i) { i_ = i; }
+    TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
 
     int i_;
     };
@@ -63,9 +61,8 @@ std::mt19937 randomness;
 
 template <class Iter>
 void
-test_one(unsigned N, unsigned M)
+test_one_randomized(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)
@@ -88,7 +85,41 @@ test_one(unsigned N, unsigned M)
 }
 
 template <class Iter>
-void
+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));
+#endif
+  }
+  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>
+TEST_CONSTEXPR_CXX26 void
 test(unsigned N)
 {
     test_one<Iter>(N, 0);
@@ -99,7 +130,7 @@ test(unsigned N)
 }
 
 template <class Iter>
-void
+TEST_CONSTEXPR_CXX26 void
 test()
 {
     test_one<Iter>(0, 0);
@@ -114,18 +145,25 @@ test()
     test_one<Iter>(3, 3);
     test<Iter>(4);
     test<Iter>(20);
-    test<Iter>(100);
-    test<Iter>(1000);
+#if defined(_LIBCPP_HARDENING_MODE)
+    if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
+#endif
+    {
+      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 ()
+TEST_CONSTEXPR_CXX26 void test_PR31166()
 {
     typedef std::pair<int, int> P;
     typedef std::vector<P> V;
@@ -138,7 +176,44 @@ void test_PR31166 ()
     }
 }
 
-int main(int, char**)
+#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 (int 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*> >();
@@ -149,27 +224,22 @@ int main(int, char**)
     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;
+    if (!TEST_IS_CONSTANT_EVALUATED) {
+      test_wrapped_randomized(100, 50);
     }
+    test_wrapped_non_randomized(100, 50);
 #endif // TEST_STD_VER >= 11
 
     test_PR31166();
 
+    return true;
+}
+
+int main(int, char**) {
+  test();
+#if TEST_STD_VER >= 26
+  static_assert(test());
+#endif // TEST_STD_VER >= 26
+
   return 0;
 }
diff --git a/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp b/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
index 7d6be48430179..8e7abffe0fc92 100644
--- a/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
+++ b/libcxx/test/std/algorithms/robust_re_difference_type.compile.pass.cpp
@@ -141,8 +141,13 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
     (void)std::is_sorted(first, last, std::less<void*>());
     (void)std::is_sorted_until(first, last);
     (void)std::is_sorted_until(first, last, std::less<void*>());
-    if (!TEST_IS_CONSTANT_EVALUATED) (void)std::inplace_merge(first, mid, last);
-    if (!TEST_IS_CONSTANT_EVALUATED) (void)std::inplace_merge(first, mid, last, std::less<void*>());
+#if TEST_STD_VER < 26
+    if (!TEST_IS_CONSTANT_EVALUATED)
+#endif
+    {
+      (void)std::inplace_merge(first, mid, last);
+      (void)std::inplace_merge(first, mid, last, std::less<void*>());
+    }
     (void)std::iter_swap(first, mid);
     (void)std::lexicographical_compare(first, last, first2, last2);
     (void)std::lexicographical_compare(first, last, first2, last2, std::less<void*>());
diff --git a/libcxx/test/support/counting_predicates.h b/libcxx/test/support/counting_predicates.h
index db7ee481991c4..eb5ba91e6d467 100644
--- a/libcxx/test/support/counting_predicates.h
+++ b/libcxx/test/support/counting_predicates.h
@@ -41,12 +41,12 @@ struct binary_counting_predicate {
     typedef Arg2 second_argument_type;
     typedef bool result_type;
 
-    binary_counting_predicate ( Predicate p ) : p_(p), count_(0) {}
-    ~binary_counting_predicate() {}
+    TEST_CONSTEXPR_CXX20 binary_counting_predicate( Predicate p ) : p_(p), count_(0) {}
+    TEST_CONSTEXPR_CXX20 ~binary_counting_predicate() {}
 
-    bool operator () (const Arg1 &a1, const Arg2 &a2) const { ++count_; return p_(a1, a2); }
-    std::size_t count() const { return count_; }
-    void reset() { count_ = 0; }
+    TEST_CONSTEXPR_CXX20 bool operator () (const Arg1 &a1, const Arg2 &a2) const { ++count_; return p_(a1, a2); }
+    TEST_CONSTEXPR_CXX20 std::size_t count() const { return count_; }
+    TEST_CONSTEXPR_CXX20 void reset() { count_ = 0; }
 
 private:
     Predicate p_;

>From 129af09197ac41bc2008a8c6568105ee3efeeb15 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Sun, 2 Mar 2025 02:31:33 +0800
Subject: [PATCH 2/2] Clang-format some test files

---
 .../alg.merge/inplace_merge.pass.cpp          | 158 +++++++--------
 .../alg.merge/inplace_merge_comp.pass.cpp     | 183 +++++++++---------
 libcxx/test/support/counting_predicates.h     |   9 +-
 3 files changed, 178 insertions(+), 172 deletions(-)

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 36714ac4c53fe..24ad88aacccbe 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
@@ -23,47 +23,55 @@
 
 #if TEST_STD_VER >= 11
 struct S {
-    TEST_CONSTEXPR_CXX26 S() : i_(0) {}
-    TEST_CONSTEXPR_CXX26 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(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 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 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; }
+  TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
 
-    int i_;
-    };
+  int i_;
+};
 #endif
 
 std::mt19937 randomness;
 
 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;
+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;
 }
 
 template <class Iter>
@@ -96,71 +104,65 @@ TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
 }
 
 template <class Iter>
-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);
+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>
-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_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);
 #if defined(_LIBCPP_HARDENING_MODE)
-    if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
+  if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
 #endif
-    {
-        test<Iter>(100);
-    }
-    if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
-        test<Iter>(1000);
-    }
+  {
+    test<Iter>(100);
+  }
+  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
+    test<Iter>(1000);
+  }
 }
 
-TEST_CONSTEXPR_CXX26 bool
-test()
-{
-    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*>();
+  test<bidirectional_iterator<S*> >();
+  test<random_access_iterator<S*> >();
+  test<S*>();
 #endif
 
-    return true;
+  return true;
 }
 
 int main(int, char**) {
-    test();
+  test();
 #if TEST_STD_VER >= 26
-    static_assert(test());
+  static_assert(test());
 #endif // TEST_STD_VER >= 26
 
 #if TEST_STD_VER >= 11 && !defined(TEST_HAS_NO_EXCEPTIONS)
-    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; }));
-    }
+  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 1af1bea46ba70..23ca153b65623 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
@@ -31,26 +31,36 @@ struct indirect_less {
 };
 
 struct S {
-    TEST_CONSTEXPR_CXX26 S() : i_(0) {}
-    TEST_CONSTEXPR_CXX26 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(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 ==(const S&  rhs) const { return i_ == rhs.i_; }
-    TEST_CONSTEXPR_CXX26 bool operator ==(int i)         const { return 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;
+  }
 
-    TEST_CONSTEXPR_CXX26 void set(int i) { i_ = 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; }
 
-    int i_;
-    };
+  TEST_CONSTEXPR_CXX26 void set(int i) { i_ = i; }
 
+  int i_;
+};
 
 #endif // TEST_STD_VER >= 11
 
@@ -60,28 +70,25 @@ struct S {
 std::mt19937 randomness;
 
 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::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));
+    assert(pred.count() <= (N - 1));
 #endif
-    }
-    delete [] ia;
+  }
+  delete[] ia;
 }
 
 template <class Iter>
@@ -119,41 +126,37 @@ TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M) {
 }
 
 template <class Iter>
-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);
+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>
-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_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);
 #if defined(_LIBCPP_HARDENING_MODE)
-    if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
+  if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
 #endif
-    {
-      test<Iter>(100);
-    }
-    if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
-      test<Iter>(1000);
-    }
+  {
+    test<Iter>(100);
+  }
+  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
+    test<Iter>(1000);
+  }
 }
 
 struct less_by_first {
@@ -163,17 +166,16 @@ struct less_by_first {
   }
 };
 
-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));
-    }
+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));
+  }
 }
 
 #if TEST_STD_VER >= 11
@@ -213,26 +215,25 @@ TEST_CONSTEXPR_CXX26 void test_wrapped_non_randomized(int N, unsigned M) {
 }
 #endif // TEST_STD_VER >= 11
 
-TEST_CONSTEXPR_CXX26 bool test()
-{
-    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*>();
-
-    if (!TEST_IS_CONSTANT_EVALUATED) {
-      test_wrapped_randomized(100, 50);
-    }
-    test_wrapped_non_randomized(100, 50);
+  test<bidirectional_iterator<S*> >();
+  test<random_access_iterator<S*> >();
+  test<S*>();
+
+  if (!TEST_IS_CONSTANT_EVALUATED) {
+    test_wrapped_randomized(100, 50);
+  }
+  test_wrapped_non_randomized(100, 50);
 #endif // TEST_STD_VER >= 11
 
-    test_PR31166();
+  test_PR31166();
 
-    return true;
+  return true;
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/support/counting_predicates.h b/libcxx/test/support/counting_predicates.h
index eb5ba91e6d467..569bf0131be21 100644
--- a/libcxx/test/support/counting_predicates.h
+++ b/libcxx/test/support/counting_predicates.h
@@ -41,14 +41,17 @@ struct binary_counting_predicate {
     typedef Arg2 second_argument_type;
     typedef bool result_type;
 
-    TEST_CONSTEXPR_CXX20 binary_counting_predicate( Predicate p ) : p_(p), count_(0) {}
+    TEST_CONSTEXPR_CXX20 binary_counting_predicate(Predicate p) : p_(p), count_(0) {}
     TEST_CONSTEXPR_CXX20 ~binary_counting_predicate() {}
 
-    TEST_CONSTEXPR_CXX20 bool operator () (const Arg1 &a1, const Arg2 &a2) const { ++count_; return p_(a1, a2); }
+    TEST_CONSTEXPR_CXX20 bool operator()(const Arg1& a1, const Arg2& a2) const {
+      ++count_;
+      return p_(a1, a2);
+    }
     TEST_CONSTEXPR_CXX20 std::size_t count() const { return count_; }
     TEST_CONSTEXPR_CXX20 void reset() { count_ = 0; }
 
-private:
+  private:
     Predicate p_;
     mutable std::size_t count_;
 };



More information about the libcxx-commits mailing list