[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
Sun Mar 16 09:11:17 PDT 2025


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

>From 4ae5ab293c01e631f0d75aaa0050f773878ab7bd 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 01/11] [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 76b5ef463e096ed7daa2d01ac3145866abb7bbb3 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 02/11] 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_;
 };

>From 7b090e18fc45765833bddb9c907b25d14d893d8d Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:31:08 +0800
Subject: [PATCH 03/11] Change `constexpr in` to `constexpr since` in comments

---
 libcxx/include/algorithm | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 5ca77eeb79753..aea24e53019cc 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1609,11 +1609,11 @@ template <class InputIterator1, class InputIterator2, class OutputIterator, clas
           InputIterator2 first2, InputIterator2 last2, OutputIterator result, Compare comp);
 
 template <class BidirectionalIterator>
-    constexpr void                                    // constexpr in C++26
+    constexpr void                                    // constexpr since C++26
     inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last);
 
 template <class BidirectionalIterator, class Compare>
-    constexpr void                                    // constexpr in C++26
+    constexpr void                                    // constexpr since C++26
     inplace_merge(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last, Compare comp);
 
 template <class InputIterator1, class InputIterator2>

>From 0fd8637273e30b88ac80fb67ed84f2ec45b00162 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:31:40 +0800
Subject: [PATCH 04/11] Add `constexpr_random.h` for test suite

---
 libcxx/test/support/constexpr_random.h | 704 +++++++++++++++++++++++++
 1 file changed, 704 insertions(+)
 create mode 100644 libcxx/test/support/constexpr_random.h

diff --git a/libcxx/test/support/constexpr_random.h b/libcxx/test/support/constexpr_random.h
new file mode 100644
index 0000000000000..5f9a16fa69f90
--- /dev/null
+++ b/libcxx/test/support/constexpr_random.h
@@ -0,0 +1,704 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SUPPORT_CONSTEXPR_RANDOM_H
+#define TEST_SUPPORT_CONSTEXPR_RANDOM_H
+
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+namespace support {
+
+namespace detail {
+
+template <class>
+struct is_valid_integer_type_for_random : std::false_type {};
+template <>
+struct is_valid_integer_type_for_random<std::int8_t> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<short> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<int> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<long> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<long long> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<std::uint8_t> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<unsigned short> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<unsigned int> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<unsigned long> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<unsigned long long> : std::true_type {};
+
+#ifndef TEST_HAS_NO_INT128
+template <>
+struct is_valid_integer_type_for_random<__int128_t> : std::true_type {};
+template <>
+struct is_valid_integer_type_for_random<__uint128_t> : std::true_type {};
+#endif // TEST_HAS_NO_INT128
+
+template <class, class = void>
+struct is_valid_urng : std::false_type {};
+template <class Gen>
+struct is_valid_urng<
+    Gen,
+    typename std::enable_if<std::is_unsigned<typename Gen::result_type>::value &&
+                            std::is_same<decltype(std::declval<Gen&>()()), typename Gen::result_type>::value>::type>
+    : std::true_type {};
+
+template <class Sseq, class Engine>
+struct is_seed_sequence {
+  static TEST_CONSTEXPR const bool value =
+      !std::is_convertible<Sseq, typename Engine::result_type>::value &&
+      !std::is_same<typename std::remove_cv<Sseq>::type, Engine>::value;
+};
+
+template <class UIntType, UIntType N, std::size_t R>
+struct meta_log2_imp;
+
+template <unsigned long long N, std::size_t R>
+struct meta_log2_imp<unsigned long long, N, R> {
+  static const std::size_t value =
+      N & ((unsigned long long)(1) << R) ? R : meta_log2_imp<unsigned long long, N, R - 1>::value;
+};
+
+template <unsigned long long N>
+struct meta_log2_imp<unsigned long long, N, 0> {
+  static const std::size_t value = 0;
+};
+
+template <size_t R>
+struct meta_log2_imp<unsigned long long, 0, R> {
+  static const std::size_t value = R + 1;
+};
+
+#ifndef TEST_HAS_NO_INT128
+template <__uint128_t N, std::size_t R>
+struct meta_log2_imp<__uint128_t, N, R> {
+  static const size_t value =
+      (N >> 64) ? (64 + meta_log2_imp<unsigned long long, (N >> 64), 63>::value)
+                : meta_log2_imp<unsigned long long, N, 63>::value;
+};
+#endif // TEST_HAS_NO_INT128
+
+template <class UIntType, UIntType N>
+struct meta_log2 {
+  static const size_t value = meta_log2_imp<
+#ifndef TEST_HAS_NO_INT128
+      typename std::conditional<sizeof(UIntType) <= sizeof(unsigned long long), unsigned long long, __uint128_t>::type,
+#else
+      unsigned long long,
+#endif // TEST_HAS_NO_INT128
+      N,
+      sizeof(UIntType) * CHAR_BIT - 1 >::value;
+};
+
+#ifdef TEST_COMPILER_MSVC
+template <int Width, class T, typename std::enable_if<(Width <= 1), int>::type = 0>
+TEST_CONSTEXPR int countl_zero_div_conq(T n) TEST_NOEXCEPT {
+  return static_cast<int>(~n) & 1;
+}
+
+template <int Width, class T, typename std::enable_if<(Width > 1), int>::type = 0>
+TEST_CONSTEXPR int countl_zero_div_conq(T n) TEST_NOEXCEPT {
+  return n >= (static_cast<T>(1) << (Width / 2))
+           ? detail::countl_zero_div_conq<Width / 2>(n >> (Width / 2))
+           : detail::countl_zero_div_conq<Width / 2>(n) + Width / 2;
+}
+#endif
+
+template <class T, typename std::enable_if<std::is_same<T, unsigned int>::value, int>::type = 0>
+TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT {
+#ifdef TEST_COMPILER_MSVC
+  return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n);
+#else
+  return __builtin_clz(n);
+#endif
+}
+
+template <class T, typename std::enable_if<std::is_same<T, unsigned long>::value, int>::type = 0>
+TEST_CONSTEXPR_CXX14 int countl_zero(T n) TEST_NOEXCEPT {
+#ifdef TEST_COMPILER_MSVC
+  return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n);
+#else
+  return __builtin_clzl(n);
+#endif
+}
+
+template <class T, typename std::enable_if<std::is_same<T, unsigned long long>::value, int>::type = 0>
+TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT {
+#ifdef TEST_COMPILER_MSVC
+  return detail::countl_zero_div_conq<std::numeric_limits<T>::digits>(n);
+#else
+  return __builtin_clzll(n);
+#endif
+}
+
+#ifndef TEST_HAS_NO_INT128
+template <class T, typename std::enable_if<std::is_same<T, __uint128_t>::value, int>::type = 0>
+TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT {
+  return n > std::numeric_limits<std::uint64_t>::max()
+           ? detail::countl_zero(static_cast<std::uint64_t>(n >> 64))
+           : detail::countl_zero(static_cast<std::uint64_t>(n)) + 64;
+}
+#endif // TEST_HAS_NO_INT128
+
+template <class T,
+          typename std::enable_if<std::is_same<T, unsigned char>::value || std::is_same<T, unsigned short>::value,
+                                  int>::type = 0>
+TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT {
+  return detail::countl_zero(static_cast<unsigned int>(n)) -
+         (std::numeric_limits<unsigned int>::digits - std::numeric_limits<T>::digits);
+}
+
+enum lce_alg_type {
+  LCE_Full,
+  LCE_Part,
+  LCE_Schrage,
+  LCE_Promote,
+};
+
+template <unsigned long long a,
+          unsigned long long c,
+          unsigned long long m,
+          unsigned long long Mp,
+          bool HasOverflow = (a != 0ull && (m & (m - 1ull)) != 0ull),    // a != 0, m != 0, m != 2^n
+          bool Full        = (!HasOverflow || m - 1ull <= (Mp - c) / a), // (a * x + c) % m works
+          bool Part        = (!HasOverflow || m - 1ull <= Mp / a),       // (a * x) % m works
+          bool Schrage     = (HasOverflow && m % a <= m / a)>                // r <= q
+struct lce_alg_picker {
+  static TEST_CONSTEXPR const lce_alg_type mode =
+      Full      ? LCE_Full
+      : Part    ? LCE_Part
+      : Schrage ? LCE_Schrage
+                : LCE_Promote;
+
+#ifndef TEST_HAS_NO_INT128
+  static_assert(Mp != static_cast<unsigned long long>(-1) || Full || Part || Schrage,
+                "The current values for a, c, and m are not currently supported on platforms without __int128");
+#endif // TEST_HAS_NO_INT128
+};
+
+template <unsigned long long a,
+          unsigned long long c,
+          unsigned long long m,
+          unsigned long long Mp,
+          lce_alg_type Mode = lce_alg_picker<a, c, m, Mp>::mode>
+struct lce_traits;
+
+// 64
+
+#ifndef TEST_HAS_NO_INT128
+template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
+struct lce_traits<Ap, Cp, Mp, static_cast<unsigned long long>(-1), LCE_Promote> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type xp) {
+    __extension__ using calc_type = unsigned __int128;
+    const calc_type a             = static_cast<calc_type>(Ap);
+    const calc_type c             = static_cast<calc_type>(Cp);
+    const calc_type m             = static_cast<calc_type>(Mp);
+    const calc_type x             = static_cast<calc_type>(xp);
+    return static_cast<result_type>((a * x + c) % m);
+  }
+};
+#endif // TEST_HAS_NO_INT128
+
+template <unsigned long long a, unsigned long long c, unsigned long long m>
+struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Schrage> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    // Schrage's algorithm
+    const result_type q  = m / a;
+    const result_type r  = m % a;
+    const result_type t0 = a * (x % q);
+    const result_type t1 = r * (x / q);
+    x                    = t0 + (t0 < t1) * m - t1;
+    x += c - (x >= m - c) * m;
+    return x;
+  }
+};
+
+template <unsigned long long a, unsigned long long m>
+struct lce_traits<a, 0ull, m, static_cast<unsigned long long>(-1), LCE_Schrage> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    // Schrage's algorithm
+    const result_type q  = m / a;
+    const result_type r  = m % a;
+    const result_type t0 = a * (x % q);
+    const result_type t1 = r * (x / q);
+    x                    = t0 + (t0 < t1) * m - t1;
+    return x;
+  }
+};
+
+template <unsigned long long a, unsigned long long c, unsigned long long m>
+struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Part> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    // Use (((a*x) % m) + c) % m
+    x = (a * x) % m;
+    x += c - (x >= m - c) * m;
+    return x;
+  }
+};
+
+template <unsigned long long a, unsigned long long c, unsigned long long m>
+struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Full> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) { return (a * x + c) % m; }
+};
+
+template <unsigned long long a, unsigned long long c>
+struct lce_traits<a, c, 0ull, static_cast<unsigned long long>(-1), LCE_Full> {
+  typedef unsigned long long result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) { return a * x + c; }
+};
+
+// 32
+
+template <unsigned long long a, unsigned long long c, unsigned long long m>
+struct lce_traits<a, c, m, static_cast<unsigned>(-1), LCE_Promote> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    return static_cast<result_type>(lce_traits<a, c, m, static_cast<unsigned long long>(-1)>::next(x));
+  }
+};
+
+template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
+struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Schrage> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    const result_type a = static_cast<result_type>(Ap);
+    const result_type c = static_cast<result_type>(Cp);
+    const result_type m = static_cast<result_type>(Mp);
+    // Schrage's algorithm
+    const result_type q  = m / a;
+    const result_type r  = m % a;
+    const result_type t0 = a * (x % q);
+    const result_type t1 = r * (x / q);
+    x                    = t0 + (t0 < t1) * m - t1;
+    x += c - (x >= m - c) * m;
+    return x;
+  }
+};
+
+template <unsigned long long Ap, unsigned long long Mp>
+struct lce_traits<Ap, 0ull, Mp, static_cast<unsigned>(-1), LCE_Schrage> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    const result_type a = static_cast<result_type>(Ap);
+    const result_type m = static_cast<result_type>(Mp);
+    // Schrage's algorithm
+    const result_type q  = m / a;
+    const result_type r  = m % a;
+    const result_type t0 = a * (x % q);
+    const result_type t1 = r * (x / q);
+    x                    = t0 + (t0 < t1) * m - t1;
+    return x;
+  }
+};
+
+template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
+struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Part> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    const result_type a = static_cast<result_type>(Ap);
+    const result_type c = static_cast<result_type>(Cp);
+    const result_type m = static_cast<result_type>(Mp);
+    // Use (((a*x) % m) + c) % m
+    x = (a * x) % m;
+    x += c - (x >= m - c) * m;
+    return x;
+  }
+};
+
+template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
+struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Full> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    const result_type a = static_cast<result_type>(Ap);
+    const result_type c = static_cast<result_type>(Cp);
+    const result_type m = static_cast<result_type>(Mp);
+    return (a * x + c) % m;
+  }
+};
+
+template <unsigned long long Ap, unsigned long long Cp>
+struct lce_traits<Ap, Cp, 0ull, static_cast<unsigned>(-1), LCE_Full> {
+  typedef unsigned result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    const result_type a = static_cast<result_type>(Ap);
+    const result_type c = static_cast<result_type>(Cp);
+    return a * x + c;
+  }
+};
+
+// 16
+
+template <unsigned long long a, unsigned long long c, unsigned long long m, lce_alg_type mode>
+struct lce_traits<a, c, m, static_cast<unsigned short>(-1), mode> {
+  typedef unsigned short result_type;
+  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
+    return static_cast<result_type>(lce_traits<a, c, m, static_cast<unsigned short>(-1)>::next(x));
+  }
+};
+
+template <class Engine, class UIntType>
+class independent_bits_engine {
+public:
+  typedef UIntType result_type;
+
+private:
+  typedef typename Engine::result_type engine_result_type;
+  typedef
+      typename std::conditional<sizeof(engine_result_type) <= sizeof(result_type), result_type, engine_result_type>::
+          type working_result_type;
+
+  Engine& eng_;
+  std::size_t width_;
+  std::size_t wid0_;
+  std::size_t round_count_all_;
+  std::size_t round_count_regular_;
+  working_result_type y0_;
+  working_result_type y1_;
+  engine_result_type mask0_;
+  engine_result_type mask1_;
+
+#if TEST_STD_VER >= 11
+  static constexpr working_result_type rp = Engine::max() - Engine::min() + working_result_type(1);
+#else
+  static const working_result_type rp = Engine::max_value - Engine::min_value + working_result_type(1);
+#endif
+  static TEST_CONSTEXPR const std::size_t rp_log2  = meta_log2<working_result_type, rp>::value;
+  static TEST_CONSTEXPR const std::size_t w_digits = std::numeric_limits<working_result_type>::digits;
+  static TEST_CONSTEXPR const std::size_t e_digits = std::numeric_limits<engine_result_type>::digits;
+
+public:
+  // constructors and seeding functions
+  TEST_CONSTEXPR_CXX14 independent_bits_engine(Engine& eng, std::size_t width)
+      : eng_(eng),
+        width_(width),
+        wid0_(),
+        round_count_all_(),
+        round_count_regular_(),
+        y0_(),
+        y1_(),
+        mask0_(),
+        mask1_() {
+    round_count_all_ = width_ / rp_log2 + (width_ % rp_log2 != 0);
+    wid0_            = width_ / round_count_all_;
+    if (rp == 0)
+      y0_ = rp;
+    else if (wid0_ < w_digits)
+      y0_ = (rp >> wid0_) << wid0_;
+    else
+      y0_ = 0;
+    if (rp - y0_ > y0_ / round_count_all_) {
+      ++round_count_all_;
+      wid0_ = width_ / round_count_all_;
+      if (wid0_ < w_digits)
+        y0_ = (rp >> wid0_) << wid0_;
+      else
+        y0_ = 0;
+    }
+    round_count_regular_ = round_count_all_ - width_ % round_count_all_;
+    if (wid0_ < w_digits - 1)
+      y1_ = (rp >> (wid0_ + 1)) << (wid0_ + 1);
+    else
+      y1_ = 0;
+    mask0_ = wid0_ > 0 ? engine_result_type(~0) >> (e_digits - wid0_) : engine_result_type(0);
+    mask1_ = wid0_ < e_digits - 1 ? engine_result_type(~0) >> (e_digits - (wid0_ + 1)) : engine_result_type(~0);
+  }
+
+  // generating functions
+  TEST_CONSTEXPR_CXX14 result_type operator()() { return generate(std::integral_constant<bool, (rp != 0)>()); }
+
+private:
+  TEST_CONSTEXPR_CXX14 result_type generate(std::false_type) { return static_cast<result_type>(eng_() & mask0_); }
+
+  TEST_CONSTEXPR_CXX14 result_type generate(std::true_type) {
+    const std::size_t r_digits = std::numeric_limits<result_type>::digits;
+    result_type result         = 0;
+    for (std::size_t k = 0; k < round_count_regular_; ++k) {
+      engine_result_type eng_result = 0;
+      do {
+        eng_result = eng_() - Engine::min();
+      } while (eng_result >= y0_);
+      if (wid0_ < r_digits)
+        result <<= wid0_;
+      else
+        result = 0;
+      result += eng_result & mask0_;
+    }
+    for (std::size_t k = round_count_regular_; k < round_count_all_; ++k) {
+      engine_result_type eng_result = 0;
+      do {
+        eng_result = eng_() - Engine::min();
+      } while (eng_result >= y1_);
+      if (wid0_ < r_digits - 1)
+        result <<= wid0_ + 1;
+      else
+        result = 0;
+      result += eng_result & mask1_;
+    }
+    return result;
+  }
+};
+
+} // namespace detail
+
+template <class UIntType, UIntType a, UIntType c, UIntType m>
+class linear_congruential_engine {
+public:
+  // types
+  typedef UIntType result_type;
+
+private:
+  result_type result_;
+
+  static TEST_CONSTEXPR const result_type Mp = result_type(-1);
+
+  static_assert(m == 0 || a < m, "linear_congruential_engine invalid parameters");
+  static_assert(m == 0 || c < m, "linear_congruential_engine invalid parameters");
+  static_assert(std::is_unsigned<UIntType>::value, "UIntType must be unsigned type");
+
+public:
+  static TEST_CONSTEXPR const result_type min_value = c == 0u ? 1u : 0u;
+  static TEST_CONSTEXPR const result_type max_value = m - UIntType(1u);
+  static_assert(min_value < max_value, "linear_congruential_engine invalid parameters");
+
+  // engine characteristics
+  static TEST_CONSTEXPR const result_type multiplier = a;
+  static TEST_CONSTEXPR const result_type increment  = c;
+  static TEST_CONSTEXPR const result_type modulus    = m;
+  static TEST_CONSTEXPR_CXX14 result_type min() { return min_value; }
+  static TEST_CONSTEXPR_CXX14 result_type max() { return max_value; }
+  static TEST_CONSTEXPR const result_type default_seed = 1u;
+
+  // constructors and seeding functions
+#if TEST_STD_VER >= 11
+  TEST_CONSTEXPR_CXX14 linear_congruential_engine() : linear_congruential_engine(default_seed) {}
+#else
+  linear_congruential_engine() { seed(default_seed); }
+#endif
+  TEST_CONSTEXPR_CXX14 explicit linear_congruential_engine(result_type s) { seed(s); }
+  template < class Sseq,
+             typename std::enable_if<detail::is_seed_sequence<Sseq, linear_congruential_engine>::value, int>::type = 0>
+  TEST_CONSTEXPR_CXX14 explicit linear_congruential_engine(Sseq& q) {
+    seed(q);
+  }
+  TEST_CONSTEXPR_CXX14 void seed(result_type s = default_seed) {
+    seed(std::integral_constant < bool, m == 0 > (), std::integral_constant < bool, c == 0 > (), s);
+  }
+  template < class Sseq,
+             typename std::enable_if<detail::is_seed_sequence<Sseq, linear_congruential_engine>::value, int>::type = 0>
+  TEST_CONSTEXPR_CXX14 void seed(Sseq& q) {
+    seed_impl(
+        q,
+        std::integral_constant< unsigned,
+                                1 + (m == 0 ? (sizeof(result_type) * CHAR_BIT - 1) / 32 : (m > 0x100000000ull))>());
+  }
+
+  // generating functions
+  TEST_CONSTEXPR_CXX14 result_type operator()() {
+    return result_ = static_cast<result_type>(detail::lce_traits<a, c, m, Mp>::next(result_));
+  }
+  TEST_CONSTEXPR_CXX14 void discard(unsigned long long z) {
+    for (; z; --z)
+      operator()();
+  }
+
+#if TEST_STD_VER >= 20
+  friend bool operator==(const linear_congruential_engine&, const linear_congruential_engine&) = default;
+#else
+  friend bool operator==(const linear_congruential_engine& lhs, const linear_congruential_engine& rhs) {
+    return lhs.result_ == rhs.result_;
+  }
+  friend bool operator!=(const linear_congruential_engine& lhs, const linear_congruential_engine& rhs) {
+    return !(lhs == rhs);
+  }
+#endif
+
+private:
+  TEST_CONSTEXPR_CXX14 void seed(std::true_type, std::true_type, result_type s) { result_ = s == 0 ? 1 : s; }
+  TEST_CONSTEXPR_CXX14 void seed(std::true_type, std::false_type, result_type s) { result_ = s; }
+  TEST_CONSTEXPR_CXX14 void seed(std::false_type, std::true_type, result_type s) { result_ = s % m == 0 ? 1 : s % m; }
+  TEST_CONSTEXPR_CXX14 void seed(std::false_type, std::false_type, result_type s) { result_ = s % m; }
+
+  template <class Sseq>
+  TEST_CONSTEXPR_CXX14 void seed_impl(Sseq& q, std::integral_constant<unsigned, 1>) {
+    const unsigned k         = 1;
+    std::uint32_t arr[k + 3] = {};
+    q.generate(arr, arr + k + 3);
+    result_type s = static_cast<result_type>(arr[3] % m);
+    result_       = c == 0 && s == 0 ? result_type(1) : s;
+  }
+  template <class Sseq>
+  TEST_CONSTEXPR_CXX14 void seed_impl(Sseq& q, std::integral_constant<unsigned, 2>) {
+    const unsigned k         = 2;
+    std::uint32_t arr[k + 3] = {};
+    q.generate(arr, arr + k + 3);
+    result_type s = static_cast<result_type>((arr[3] + (static_cast<std::uint64_t>(arr[4]) << 32)) % m);
+    result_       = c == 0 && s == 0 ? result_type(1) : s;
+  }
+};
+
+typedef linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
+typedef linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647> minstd_rand;
+
+template <class IntType = int>
+class uniform_int_distribution {
+  static_assert(detail::is_valid_integer_type_for_random<IntType>::value, "IntType must be a supported integer type");
+
+public:
+  // types
+  typedef IntType result_type;
+
+  class param_type {
+    result_type a_;
+    result_type b_;
+
+  public:
+    typedef uniform_int_distribution distribution_type;
+
+#if TEST_STD_VER >= 11
+    constexpr param_type() : param_type(0) {}
+#else
+    param_type() : a_(0), b_(std::numeric_limits<result_type>::max()) {}
+#endif
+    TEST_CONSTEXPR explicit param_type(result_type ax, result_type bx = std::numeric_limits<result_type>::max())
+        : a_(ax), b_(bx) {}
+
+    TEST_CONSTEXPR result_type a() const { return a_; }
+    TEST_CONSTEXPR result_type b() const { return b_; }
+
+#if TEST_STD_VER >= 20
+    friend bool operator==(const param_type&, const param_type&) = default;
+#else
+    TEST_CONSTEXPR friend bool operator==(const param_type& lhs, const param_type& rhs) {
+      return lhs.a_ == rhs.a_ && lhs.b_ == rhs.b_;
+    }
+    TEST_CONSTEXPR friend bool operator!=(const param_type& lhs, const param_type& rhs) { return !(lhs == rhs); }
+#endif
+  };
+
+private:
+  param_type param_;
+
+public:
+  // constructors and reset functions
+#if TEST_STD_VER >= 11
+  uniform_int_distribution() = default;
+#else
+  uniform_int_distribution() {}
+#endif
+  TEST_CONSTEXPR explicit uniform_int_distribution(result_type ax,
+                                                   result_type bx = std::numeric_limits<result_type>::max())
+      : param_(ax, bx) {}
+  TEST_CONSTEXPR explicit uniform_int_distribution(const param_type& param) : param_(param) {}
+  TEST_CONSTEXPR_CXX14 void reset() {}
+
+  // generating functions
+  template <class URNG>
+  TEST_CONSTEXPR_CXX14 result_type operator()(URNG& gen) {
+    return (*this)(gen, param_);
+  }
+
+#if TEST_HAS_FEATURE(no_sanitize) && !defined(TEST_COMPILER_GCC)
+#  define TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK __attribute__((__no_sanitize__("unsigned-integer-overflow")))
+#else
+#  define TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
+#endif
+  template <class URNG>
+  TEST_CONSTEXPR_CXX14 result_type operator()(URNG& gen, const param_type& param)
+      TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK {
+    static_assert(detail::is_valid_urng<URNG>::value, "invalid uniform random bit generator used");
+    typedef typename std::conditional<sizeof(result_type) <= sizeof(std::uint32_t),
+                                      std::uint32_t,
+                                      typename std::make_unsigned<result_type>::type>::type UIntType;
+    const UIntType rp = UIntType(param.b()) - UIntType(param.a()) + UIntType(1);
+    if (rp == 1)
+      return param.a();
+    const std::size_t ur_digits = std::numeric_limits<UIntType>::digits;
+    typedef detail::independent_bits_engine<URNG, UIntType> Eng;
+    if (rp == 0)
+      return static_cast<result_type>(Eng(gen, ur_digits)());
+    std::size_t width = ur_digits - detail::countl_zero(rp) - 1;
+    if ((rp & (std::numeric_limits<UIntType>::max() >> (ur_digits - width))) != 0)
+      ++width;
+    Eng eng(gen, width);
+    UIntType eng_result = 0;
+    do {
+      eng_result = eng();
+    } while (eng_result >= rp);
+    return static_cast<result_type>(eng_result + param.a());
+  }
+#undef TEST_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
+
+  // property functions
+  TEST_CONSTEXPR result_type a() const { return param_.a(); }
+  TEST_CONSTEXPR result_type b() const { return param_.b(); }
+
+  TEST_CONSTEXPR param_type param() const { return param_; }
+  TEST_CONSTEXPR_CXX14 void param(const param_type& param) { param_ = param; }
+
+  TEST_CONSTEXPR result_type min() const { return a(); }
+  TEST_CONSTEXPR result_type max() const { return b(); }
+
+#if TEST_STD_VER >= 20
+  friend bool operator==(const uniform_int_distribution&, const uniform_int_distribution&) = default;
+#else
+  TEST_CONSTEXPR friend bool operator==(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) {
+    return lhs.param_ == rhs.param_;
+  }
+  TEST_CONSTEXPR friend bool operator!=(const uniform_int_distribution& lhs, const uniform_int_distribution& rhs) {
+    return !(lhs == rhs);
+  }
+#endif
+};
+
+template <class RandomAccessIterator, class UniformRandomNumberGenerator>
+TEST_CONSTEXPR_CXX14 void
+#if TEST_STD_VER >= 11
+shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator&& gen)
+#else
+shuffle(RandomAccessIterator first, RandomAccessIterator last, UniformRandomNumberGenerator& gen)
+#endif
+{
+  typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_type;
+  typedef uniform_int_distribution<ptrdiff_t> dist;
+  typedef typename dist::param_type param_type;
+
+  RandomAccessIterator last_iter = last;
+  difference_type diff           = last_iter - first;
+  if (diff > 1) {
+    dist uid;
+    for (--last_iter, (void)--diff; first < last; ++first, (void)--diff) {
+      difference_type index = uid(gen, param_type(0, diff));
+      if (index != difference_type(0)) {
+        using std::swap;
+        swap(*first, *(first + index));
+      }
+    }
+  }
+}
+
+} // namespace support
+
+#endif // TEST_SUPPORT_CONSTEXPR_RANDOM_H

>From b9cb3f558f6221f62da3d40f877114bc23750fd4 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:32:29 +0800
Subject: [PATCH 05/11] Use constexpr-ized `minstd_rand` as random source in
 test files

---
 .../alg.merge/inplace_merge.pass.cpp          |  98 ++++-------
 .../alg.merge/inplace_merge_comp.pass.cpp     | 162 ++++++------------
 2 files changed, 89 insertions(+), 171 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 24ad88aacccbe..4389858653004 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
@@ -14,10 +14,10 @@
 
 #include <algorithm>
 #include <cassert>
-#include <random>
 #include <vector>
 
 #include "count_new.h"
+#include "constexpr_random.h"
 #include "test_iterators.h"
 #include "test_macros.h"
 
@@ -54,15 +54,15 @@ struct S {
 };
 #endif
 
-std::mt19937 randomness;
+template <class Iter, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M, RandSrc& randomness) {
+  assert(M <= N);
 
-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);
+  support::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));
@@ -74,77 +74,51 @@ void test_one_randomized(unsigned N, unsigned M) {
   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::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);
-  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, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test(unsigned N, RandSrc& randomness) {
+  test_one<Iter>(N, 0, randomness);
+  test_one<Iter>(N, N / 4, randomness);
+  test_one<Iter>(N, N / 2, randomness);
+  test_one<Iter>(N, 3 * N / 4, randomness);
+  test_one<Iter>(N, N, randomness);
 }
 
-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);
+template <class Iter, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test(RandSrc& randomness) {
+  test_one<Iter>(0, 0, randomness);
+  test_one<Iter>(1, 0, randomness);
+  test_one<Iter>(1, 1, randomness);
+  test_one<Iter>(2, 0, randomness);
+  test_one<Iter>(2, 1, randomness);
+  test_one<Iter>(2, 2, randomness);
+  test_one<Iter>(3, 0, randomness);
+  test_one<Iter>(3, 1, randomness);
+  test_one<Iter>(3, 2, randomness);
+  test_one<Iter>(3, 3, randomness);
+  test<Iter>(4, randomness);
+  test<Iter>(50, randomness);
 #if defined(_LIBCPP_HARDENING_MODE)
   if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
 #endif
   {
-    test<Iter>(100);
+    test<Iter>(100, randomness);
   }
   if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
-    test<Iter>(1000);
+    test<Iter>(1000, randomness);
   }
 }
 
 TEST_CONSTEXPR_CXX26 bool test() {
-  test<bidirectional_iterator<int*> >();
-  test<random_access_iterator<int*> >();
-  test<int*>();
+  support::minstd_rand randomness;
+
+  test<bidirectional_iterator<int*> >(randomness);
+  test<random_access_iterator<int*> >(randomness);
+  test<int*>(randomness);
 
 #if TEST_STD_VER >= 11
-  test<bidirectional_iterator<S*> >();
-  test<random_access_iterator<S*> >();
-  test<S*>();
+  test<bidirectional_iterator<S*> >(randomness);
+  test<random_access_iterator<S*> >(randomness);
+  test<S*>(randomness);
 #endif
 
   return true;
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 23ca153b65623..3480a5f3fdff3 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
@@ -15,9 +15,9 @@
 #include <algorithm>
 #include <cassert>
 #include <functional>
-#include <random>
 #include <vector>
 
+#include "constexpr_random.h"
 #include "test_macros.h"
 
 #if TEST_STD_VER >= 11
@@ -67,15 +67,14 @@ struct S {
 #include "test_iterators.h"
 #include "counting_predicates.h"
 
-std::mt19937 randomness;
-
-template <class Iter>
-void test_one_randomized(unsigned N, unsigned M) {
+template <class Iter, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test_one(unsigned N, unsigned M, RandSrc& randomness) {
+  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);
+  support::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>()));
@@ -91,71 +90,38 @@ void test_one_randomized(unsigned N, unsigned M) {
   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));
-#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);
-  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, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test(unsigned N, RandSrc& randomness) {
+  test_one<Iter>(N, 0, randomness);
+  test_one<Iter>(N, N / 4, randomness);
+  test_one<Iter>(N, N / 2, randomness);
+  test_one<Iter>(N, 3 * N / 4, randomness);
+  test_one<Iter>(N, N, randomness);
 }
 
-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);
+template <class Iter, class RandSrc>
+TEST_CONSTEXPR_CXX26 void test(RandSrc& randomness) {
+  test_one<Iter>(0, 0, randomness);
+  test_one<Iter>(1, 0, randomness);
+  test_one<Iter>(1, 1, randomness);
+  test_one<Iter>(2, 0, randomness);
+  test_one<Iter>(2, 1, randomness);
+  test_one<Iter>(2, 2, randomness);
+  test_one<Iter>(3, 0, randomness);
+  test_one<Iter>(3, 1, randomness);
+  test_one<Iter>(3, 2, randomness);
+  test_one<Iter>(3, 3, randomness);
+  test<Iter>(4, randomness);
+  test<Iter>(20, randomness);
+  test<Iter>(50, randomness);
 #if defined(_LIBCPP_HARDENING_MODE)
   if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
 #endif
   {
-    test<Iter>(100);
+    test<Iter>(100, randomness);
   }
   if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
-    test<Iter>(1000);
+    test<Iter>(1000, randomness);
   }
 }
 
@@ -178,57 +144,35 @@ TEST_CONSTEXPR_CXX26 void test_PR31166() {
   }
 }
 
-#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*> >();
-  test<int*>();
+  support::minstd_rand randomness;
+
+  test<bidirectional_iterator<int*> >(randomness);
+  test<random_access_iterator<int*> >(randomness);
+  test<int*>(randomness);
 
 #if TEST_STD_VER >= 11
-  test<bidirectional_iterator<S*> >();
-  test<random_access_iterator<S*> >();
-  test<S*>();
+  test<bidirectional_iterator<S*> >(randomness);
+  test<random_access_iterator<S*> >(randomness);
+  test<S*>(randomness);
 
-  if (!TEST_IS_CONSTANT_EVALUATED) {
-    test_wrapped_randomized(100, 50);
+  {
+    constexpr int N          = 100;
+    constexpr int 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));
+    support::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_wrapped_non_randomized(100, 50);
 #endif // TEST_STD_VER >= 11
 
   test_PR31166();

>From ed1b734f0440bf73f21002fdfec2a60151d4edc2 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:33:03 +0800
Subject: [PATCH 06/11] Implicitly declare destructor for
 `binary_counting_predicate`

---
 libcxx/test/support/counting_predicates.h | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/support/counting_predicates.h b/libcxx/test/support/counting_predicates.h
index 569bf0131be21..6f34ce76302a8 100644
--- a/libcxx/test/support/counting_predicates.h
+++ b/libcxx/test/support/counting_predicates.h
@@ -41,15 +41,13 @@ 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() {}
-
-    TEST_CONSTEXPR_CXX20 bool operator()(const Arg1& a1, const Arg2& a2) const {
+    TEST_CONSTEXPR binary_counting_predicate(Predicate p) : p_(p), count_(0) {}
+    TEST_CONSTEXPR_CXX14 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; }
+    TEST_CONSTEXPR std::size_t count() const { return count_; }
+    TEST_CONSTEXPR_CXX14 void reset() { count_ = 0; }
 
   private:
     Predicate p_;

>From b2c8cb82937daa319345b01b6672f5b94407a104 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:35:58 +0800
Subject: [PATCH 07/11] Reorder `inline` in production code

---
 libcxx/include/__algorithm/inplace_merge.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 6d1153be4a240..fbfe89936d554 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -224,14 +224,14 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __inplace_merge(
 }
 
 template <class _BidirectionalIterator, class _Compare>
-_LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX26 void inplace_merge(
+inline _LIBCPP_HIDE_FROM_ABI _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>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 inline 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<>());
 }

>From 7d9cad8bcce435fbb77b126034dc356b59f274f4 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 13:47:19 +0800
Subject: [PATCH 08/11] Clang-format `constexpr_random.h`

---
 libcxx/test/support/constexpr_random.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/support/constexpr_random.h b/libcxx/test/support/constexpr_random.h
index 5f9a16fa69f90..759e80bc23749 100644
--- a/libcxx/test/support/constexpr_random.h
+++ b/libcxx/test/support/constexpr_random.h
@@ -504,7 +504,7 @@ class linear_congruential_engine {
     seed(q);
   }
   TEST_CONSTEXPR_CXX14 void seed(result_type s = default_seed) {
-    seed(std::integral_constant < bool, m == 0 > (), std::integral_constant < bool, c == 0 > (), s);
+    seed(std::integral_constant< bool, m == 0 >(), std::integral_constant< bool, c == 0 >(), s);
   }
   template < class Sseq,
              typename std::enable_if<detail::is_seed_sequence<Sseq, linear_congruential_engine>::value, int>::type = 0>

>From bdabdd6278b1f5f44a1301ff06867572f810c8a7 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 15:03:10 +0800
Subject: [PATCH 09/11] Include `<limits>` in `constexpr_random.h`

---
 libcxx/test/support/constexpr_random.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/test/support/constexpr_random.h b/libcxx/test/support/constexpr_random.h
index 759e80bc23749..1833374dad86f 100644
--- a/libcxx/test/support/constexpr_random.h
+++ b/libcxx/test/support/constexpr_random.h
@@ -13,6 +13,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <iterator>
+#include <limits>
 #include <type_traits>
 #include <utility>
 

>From 712c95cfe389c8f783e6eae18889ff621deedf35 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 10 Mar 2025 15:52:00 +0800
Subject: [PATCH 10/11] Fix mis-versioned `constexpr` in `constexpr_random.h`

---
 libcxx/test/support/constexpr_random.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/support/constexpr_random.h b/libcxx/test/support/constexpr_random.h
index 1833374dad86f..70d3f8cbbae87 100644
--- a/libcxx/test/support/constexpr_random.h
+++ b/libcxx/test/support/constexpr_random.h
@@ -488,8 +488,8 @@ class linear_congruential_engine {
   static TEST_CONSTEXPR const result_type multiplier = a;
   static TEST_CONSTEXPR const result_type increment  = c;
   static TEST_CONSTEXPR const result_type modulus    = m;
-  static TEST_CONSTEXPR_CXX14 result_type min() { return min_value; }
-  static TEST_CONSTEXPR_CXX14 result_type max() { return max_value; }
+  static TEST_CONSTEXPR result_type min() { return min_value; }
+  static TEST_CONSTEXPR result_type max() { return max_value; }
   static TEST_CONSTEXPR const result_type default_seed = 1u;
 
   // constructors and seeding functions

>From 0c03d72dd7a539c24c0778337873ce9664aa04f4 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 17 Mar 2025 00:10:46 +0800
Subject: [PATCH 11/11] Address @mordante's review comments

- Uses a simpler RNG.
- Improves comments.
---
 .../alg.merge/inplace_merge.pass.cpp          |  12 +-
 .../alg.merge/inplace_merge_comp.pass.cpp     |   6 +-
 libcxx/test/support/constexpr_random.h        | 350 +++---------------
 3 files changed, 48 insertions(+), 320 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 4389858653004..1774f54a1ebc1 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
@@ -96,20 +96,14 @@ TEST_CONSTEXPR_CXX26 void test(RandSrc& randomness) {
   test_one<Iter>(3, 2, randomness);
   test_one<Iter>(3, 3, randomness);
   test<Iter>(4, randomness);
-  test<Iter>(50, randomness);
-#if defined(_LIBCPP_HARDENING_MODE)
-  if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
-#endif
-  {
-    test<Iter>(100, randomness);
-  }
-  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
+  test<Iter>(100, randomness);
+  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid exceeding the constant evaluation step limit
     test<Iter>(1000, randomness);
   }
 }
 
 TEST_CONSTEXPR_CXX26 bool test() {
-  support::minstd_rand randomness;
+  support::simple_random_generator randomness;
 
   test<bidirectional_iterator<int*> >(randomness);
   test<random_access_iterator<int*> >(randomness);
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 3480a5f3fdff3..a88792b5090ec 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
@@ -115,12 +115,12 @@ TEST_CONSTEXPR_CXX26 void test(RandSrc& randomness) {
   test<Iter>(20, randomness);
   test<Iter>(50, randomness);
 #if defined(_LIBCPP_HARDENING_MODE)
-  if (!TEST_IS_CONSTANT_EVALUATED) // avoid blowing past constant evaluation limit
+  if (!TEST_IS_CONSTANT_EVALUATED) // avoid exceeding the constant evaluation step limit
 #endif
   {
     test<Iter>(100, randomness);
   }
-  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constant evaluation limit
+  if (!TEST_IS_CONSTANT_EVALUATED) { // avoid exceeding the constant evaluation step limit
     test<Iter>(1000, randomness);
   }
 }
@@ -145,7 +145,7 @@ TEST_CONSTEXPR_CXX26 void test_PR31166() {
 }
 
 TEST_CONSTEXPR_CXX26 bool test() {
-  support::minstd_rand randomness;
+  support::simple_random_generator randomness;
 
   test<bidirectional_iterator<int*> >(randomness);
   test<random_access_iterator<int*> >(randomness);
diff --git a/libcxx/test/support/constexpr_random.h b/libcxx/test/support/constexpr_random.h
index 70d3f8cbbae87..e2646e2b559a4 100644
--- a/libcxx/test/support/constexpr_random.h
+++ b/libcxx/test/support/constexpr_random.h
@@ -62,13 +62,6 @@ struct is_valid_urng<
                             std::is_same<decltype(std::declval<Gen&>()()), typename Gen::result_type>::value>::type>
     : std::true_type {};
 
-template <class Sseq, class Engine>
-struct is_seed_sequence {
-  static TEST_CONSTEXPR const bool value =
-      !std::is_convertible<Sseq, typename Engine::result_type>::value &&
-      !std::is_same<typename std::remove_cv<Sseq>::type, Engine>::value;
-};
-
 template <class UIntType, UIntType N, std::size_t R>
 struct meta_log2_imp;
 
@@ -167,199 +160,6 @@ TEST_CONSTEXPR int countl_zero(T n) TEST_NOEXCEPT {
          (std::numeric_limits<unsigned int>::digits - std::numeric_limits<T>::digits);
 }
 
-enum lce_alg_type {
-  LCE_Full,
-  LCE_Part,
-  LCE_Schrage,
-  LCE_Promote,
-};
-
-template <unsigned long long a,
-          unsigned long long c,
-          unsigned long long m,
-          unsigned long long Mp,
-          bool HasOverflow = (a != 0ull && (m & (m - 1ull)) != 0ull),    // a != 0, m != 0, m != 2^n
-          bool Full        = (!HasOverflow || m - 1ull <= (Mp - c) / a), // (a * x + c) % m works
-          bool Part        = (!HasOverflow || m - 1ull <= Mp / a),       // (a * x) % m works
-          bool Schrage     = (HasOverflow && m % a <= m / a)>                // r <= q
-struct lce_alg_picker {
-  static TEST_CONSTEXPR const lce_alg_type mode =
-      Full      ? LCE_Full
-      : Part    ? LCE_Part
-      : Schrage ? LCE_Schrage
-                : LCE_Promote;
-
-#ifndef TEST_HAS_NO_INT128
-  static_assert(Mp != static_cast<unsigned long long>(-1) || Full || Part || Schrage,
-                "The current values for a, c, and m are not currently supported on platforms without __int128");
-#endif // TEST_HAS_NO_INT128
-};
-
-template <unsigned long long a,
-          unsigned long long c,
-          unsigned long long m,
-          unsigned long long Mp,
-          lce_alg_type Mode = lce_alg_picker<a, c, m, Mp>::mode>
-struct lce_traits;
-
-// 64
-
-#ifndef TEST_HAS_NO_INT128
-template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
-struct lce_traits<Ap, Cp, Mp, static_cast<unsigned long long>(-1), LCE_Promote> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type xp) {
-    __extension__ using calc_type = unsigned __int128;
-    const calc_type a             = static_cast<calc_type>(Ap);
-    const calc_type c             = static_cast<calc_type>(Cp);
-    const calc_type m             = static_cast<calc_type>(Mp);
-    const calc_type x             = static_cast<calc_type>(xp);
-    return static_cast<result_type>((a * x + c) % m);
-  }
-};
-#endif // TEST_HAS_NO_INT128
-
-template <unsigned long long a, unsigned long long c, unsigned long long m>
-struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Schrage> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    // Schrage's algorithm
-    const result_type q  = m / a;
-    const result_type r  = m % a;
-    const result_type t0 = a * (x % q);
-    const result_type t1 = r * (x / q);
-    x                    = t0 + (t0 < t1) * m - t1;
-    x += c - (x >= m - c) * m;
-    return x;
-  }
-};
-
-template <unsigned long long a, unsigned long long m>
-struct lce_traits<a, 0ull, m, static_cast<unsigned long long>(-1), LCE_Schrage> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    // Schrage's algorithm
-    const result_type q  = m / a;
-    const result_type r  = m % a;
-    const result_type t0 = a * (x % q);
-    const result_type t1 = r * (x / q);
-    x                    = t0 + (t0 < t1) * m - t1;
-    return x;
-  }
-};
-
-template <unsigned long long a, unsigned long long c, unsigned long long m>
-struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Part> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    // Use (((a*x) % m) + c) % m
-    x = (a * x) % m;
-    x += c - (x >= m - c) * m;
-    return x;
-  }
-};
-
-template <unsigned long long a, unsigned long long c, unsigned long long m>
-struct lce_traits<a, c, m, static_cast<unsigned long long>(-1), LCE_Full> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) { return (a * x + c) % m; }
-};
-
-template <unsigned long long a, unsigned long long c>
-struct lce_traits<a, c, 0ull, static_cast<unsigned long long>(-1), LCE_Full> {
-  typedef unsigned long long result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) { return a * x + c; }
-};
-
-// 32
-
-template <unsigned long long a, unsigned long long c, unsigned long long m>
-struct lce_traits<a, c, m, static_cast<unsigned>(-1), LCE_Promote> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    return static_cast<result_type>(lce_traits<a, c, m, static_cast<unsigned long long>(-1)>::next(x));
-  }
-};
-
-template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
-struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Schrage> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    const result_type a = static_cast<result_type>(Ap);
-    const result_type c = static_cast<result_type>(Cp);
-    const result_type m = static_cast<result_type>(Mp);
-    // Schrage's algorithm
-    const result_type q  = m / a;
-    const result_type r  = m % a;
-    const result_type t0 = a * (x % q);
-    const result_type t1 = r * (x / q);
-    x                    = t0 + (t0 < t1) * m - t1;
-    x += c - (x >= m - c) * m;
-    return x;
-  }
-};
-
-template <unsigned long long Ap, unsigned long long Mp>
-struct lce_traits<Ap, 0ull, Mp, static_cast<unsigned>(-1), LCE_Schrage> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    const result_type a = static_cast<result_type>(Ap);
-    const result_type m = static_cast<result_type>(Mp);
-    // Schrage's algorithm
-    const result_type q  = m / a;
-    const result_type r  = m % a;
-    const result_type t0 = a * (x % q);
-    const result_type t1 = r * (x / q);
-    x                    = t0 + (t0 < t1) * m - t1;
-    return x;
-  }
-};
-
-template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
-struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Part> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    const result_type a = static_cast<result_type>(Ap);
-    const result_type c = static_cast<result_type>(Cp);
-    const result_type m = static_cast<result_type>(Mp);
-    // Use (((a*x) % m) + c) % m
-    x = (a * x) % m;
-    x += c - (x >= m - c) * m;
-    return x;
-  }
-};
-
-template <unsigned long long Ap, unsigned long long Cp, unsigned long long Mp>
-struct lce_traits<Ap, Cp, Mp, static_cast<unsigned>(-1), LCE_Full> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    const result_type a = static_cast<result_type>(Ap);
-    const result_type c = static_cast<result_type>(Cp);
-    const result_type m = static_cast<result_type>(Mp);
-    return (a * x + c) % m;
-  }
-};
-
-template <unsigned long long Ap, unsigned long long Cp>
-struct lce_traits<Ap, Cp, 0ull, static_cast<unsigned>(-1), LCE_Full> {
-  typedef unsigned result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    const result_type a = static_cast<result_type>(Ap);
-    const result_type c = static_cast<result_type>(Cp);
-    return a * x + c;
-  }
-};
-
-// 16
-
-template <unsigned long long a, unsigned long long c, unsigned long long m, lce_alg_type mode>
-struct lce_traits<a, c, m, static_cast<unsigned short>(-1), mode> {
-  typedef unsigned short result_type;
-  static TEST_CONSTEXPR_CXX14 result_type next(result_type x) {
-    return static_cast<result_type>(lce_traits<a, c, m, static_cast<unsigned short>(-1)>::next(x));
-  }
-};
-
 template <class Engine, class UIntType>
 class independent_bits_engine {
 public:
@@ -404,12 +204,14 @@ class independent_bits_engine {
         mask1_() {
     round_count_all_ = width_ / rp_log2 + (width_ % rp_log2 != 0);
     wid0_            = width_ / round_count_all_;
-    if (rp == 0)
+    if TEST_CONSTEXPR_CXX17 (rp == 0) {
       y0_ = rp;
-    else if (wid0_ < w_digits)
-      y0_ = (rp >> wid0_) << wid0_;
-    else
-      y0_ = 0;
+    } else {
+      if (wid0_ < w_digits)
+        y0_ = (rp >> wid0_) << wid0_;
+      else
+        y0_ = 0;
+    }
     if (rp - y0_ > y0_ / round_count_all_) {
       ++round_count_all_;
       wid0_ = width_ / round_count_all_;
@@ -423,8 +225,10 @@ class independent_bits_engine {
       y1_ = (rp >> (wid0_ + 1)) << (wid0_ + 1);
     else
       y1_ = 0;
-    mask0_ = wid0_ > 0 ? engine_result_type(~0) >> (e_digits - wid0_) : engine_result_type(0);
-    mask1_ = wid0_ < e_digits - 1 ? engine_result_type(~0) >> (e_digits - (wid0_ + 1)) : engine_result_type(~0);
+    mask0_ = wid0_ > 0 ? static_cast<engine_result_type>(engine_result_type(~0) >> (e_digits - wid0_))
+                       : engine_result_type(0);
+    mask1_ = wid0_ < e_digits - 1 ? static_cast<engine_result_type>(engine_result_type(~0) >> (e_digits - (wid0_ + 1)))
+                                  : engine_result_type(~0);
   }
 
   // generating functions
@@ -439,7 +243,7 @@ class independent_bits_engine {
     for (std::size_t k = 0; k < round_count_regular_; ++k) {
       engine_result_type eng_result = 0;
       do {
-        eng_result = eng_() - Engine::min();
+        eng_result = static_cast<engine_result_type>(eng_() - Engine::min());
       } while (eng_result >= y0_);
       if (wid0_ < r_digits)
         result <<= wid0_;
@@ -450,7 +254,7 @@ class independent_bits_engine {
     for (std::size_t k = round_count_regular_; k < round_count_all_; ++k) {
       engine_result_type eng_result = 0;
       do {
-        eng_result = eng_() - Engine::min();
+        eng_result = static_cast<engine_result_type>(eng_() - Engine::min());
       } while (eng_result >= y1_);
       if (wid0_ < r_digits - 1)
         result <<= wid0_ + 1;
@@ -464,105 +268,6 @@ class independent_bits_engine {
 
 } // namespace detail
 
-template <class UIntType, UIntType a, UIntType c, UIntType m>
-class linear_congruential_engine {
-public:
-  // types
-  typedef UIntType result_type;
-
-private:
-  result_type result_;
-
-  static TEST_CONSTEXPR const result_type Mp = result_type(-1);
-
-  static_assert(m == 0 || a < m, "linear_congruential_engine invalid parameters");
-  static_assert(m == 0 || c < m, "linear_congruential_engine invalid parameters");
-  static_assert(std::is_unsigned<UIntType>::value, "UIntType must be unsigned type");
-
-public:
-  static TEST_CONSTEXPR const result_type min_value = c == 0u ? 1u : 0u;
-  static TEST_CONSTEXPR const result_type max_value = m - UIntType(1u);
-  static_assert(min_value < max_value, "linear_congruential_engine invalid parameters");
-
-  // engine characteristics
-  static TEST_CONSTEXPR const result_type multiplier = a;
-  static TEST_CONSTEXPR const result_type increment  = c;
-  static TEST_CONSTEXPR const result_type modulus    = m;
-  static TEST_CONSTEXPR result_type min() { return min_value; }
-  static TEST_CONSTEXPR result_type max() { return max_value; }
-  static TEST_CONSTEXPR const result_type default_seed = 1u;
-
-  // constructors and seeding functions
-#if TEST_STD_VER >= 11
-  TEST_CONSTEXPR_CXX14 linear_congruential_engine() : linear_congruential_engine(default_seed) {}
-#else
-  linear_congruential_engine() { seed(default_seed); }
-#endif
-  TEST_CONSTEXPR_CXX14 explicit linear_congruential_engine(result_type s) { seed(s); }
-  template < class Sseq,
-             typename std::enable_if<detail::is_seed_sequence<Sseq, linear_congruential_engine>::value, int>::type = 0>
-  TEST_CONSTEXPR_CXX14 explicit linear_congruential_engine(Sseq& q) {
-    seed(q);
-  }
-  TEST_CONSTEXPR_CXX14 void seed(result_type s = default_seed) {
-    seed(std::integral_constant< bool, m == 0 >(), std::integral_constant< bool, c == 0 >(), s);
-  }
-  template < class Sseq,
-             typename std::enable_if<detail::is_seed_sequence<Sseq, linear_congruential_engine>::value, int>::type = 0>
-  TEST_CONSTEXPR_CXX14 void seed(Sseq& q) {
-    seed_impl(
-        q,
-        std::integral_constant< unsigned,
-                                1 + (m == 0 ? (sizeof(result_type) * CHAR_BIT - 1) / 32 : (m > 0x100000000ull))>());
-  }
-
-  // generating functions
-  TEST_CONSTEXPR_CXX14 result_type operator()() {
-    return result_ = static_cast<result_type>(detail::lce_traits<a, c, m, Mp>::next(result_));
-  }
-  TEST_CONSTEXPR_CXX14 void discard(unsigned long long z) {
-    for (; z; --z)
-      operator()();
-  }
-
-#if TEST_STD_VER >= 20
-  friend bool operator==(const linear_congruential_engine&, const linear_congruential_engine&) = default;
-#else
-  friend bool operator==(const linear_congruential_engine& lhs, const linear_congruential_engine& rhs) {
-    return lhs.result_ == rhs.result_;
-  }
-  friend bool operator!=(const linear_congruential_engine& lhs, const linear_congruential_engine& rhs) {
-    return !(lhs == rhs);
-  }
-#endif
-
-private:
-  TEST_CONSTEXPR_CXX14 void seed(std::true_type, std::true_type, result_type s) { result_ = s == 0 ? 1 : s; }
-  TEST_CONSTEXPR_CXX14 void seed(std::true_type, std::false_type, result_type s) { result_ = s; }
-  TEST_CONSTEXPR_CXX14 void seed(std::false_type, std::true_type, result_type s) { result_ = s % m == 0 ? 1 : s % m; }
-  TEST_CONSTEXPR_CXX14 void seed(std::false_type, std::false_type, result_type s) { result_ = s % m; }
-
-  template <class Sseq>
-  TEST_CONSTEXPR_CXX14 void seed_impl(Sseq& q, std::integral_constant<unsigned, 1>) {
-    const unsigned k         = 1;
-    std::uint32_t arr[k + 3] = {};
-    q.generate(arr, arr + k + 3);
-    result_type s = static_cast<result_type>(arr[3] % m);
-    result_       = c == 0 && s == 0 ? result_type(1) : s;
-  }
-  template <class Sseq>
-  TEST_CONSTEXPR_CXX14 void seed_impl(Sseq& q, std::integral_constant<unsigned, 2>) {
-    const unsigned k         = 2;
-    std::uint32_t arr[k + 3] = {};
-    q.generate(arr, arr + k + 3);
-    result_type s = static_cast<result_type>((arr[3] + (static_cast<std::uint64_t>(arr[4]) << 32)) % m);
-    result_       = c == 0 && s == 0 ? result_type(1) : s;
-  }
-};
-
-typedef linear_congruential_engine<std::uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
-typedef linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647> minstd_rand;
-
 template <class IntType = int>
 class uniform_int_distribution {
   static_assert(detail::is_valid_integer_type_for_random<IntType>::value, "IntType must be a supported integer type");
@@ -674,6 +379,35 @@ class uniform_int_distribution {
 #endif
 };
 
+class simple_random_generator {
+private:
+  std::uint32_t status_;
+
+public:
+  typedef std::uint16_t result_type;
+
+#if TEST_STD_VER >= 11
+  static constexpr result_type min() noexcept { return 0; }
+  static constexpr result_type max() noexcept { return static_cast<result_type>(-1); }
+#else
+  static const result_type min_value = 0;
+  static const result_type max_value = static_cast<result_type>(-1);
+#endif
+  static TEST_CONSTEXPR const result_type default_seed = 19937;
+
+#if TEST_STD_VER >= 11
+  constexpr simple_random_generator() noexcept : simple_random_generator(default_seed) {}
+#else
+  simple_random_generator() throw() : status_(default_seed) {}
+#endif
+  TEST_CONSTEXPR explicit simple_random_generator(std::uint16_t s) TEST_NOEXCEPT : status_(s) {}
+
+  TEST_CONSTEXPR_CXX14 result_type operator()() TEST_NOEXCEPT {
+    status_ = status_ * 214013u + 2531011u;
+    return static_cast<result_type>(status_ >> 16);
+  }
+};
+
 template <class RandomAccessIterator, class UniformRandomNumberGenerator>
 TEST_CONSTEXPR_CXX14 void
 #if TEST_STD_VER >= 11



More information about the libcxx-commits mailing list