[libcxx-commits] [libcxx] [libc++][pstl] Implementation of a parallel std::adjacent_find() based on std::mismatch() (PR #210604)

Michael G. Kazakov via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 19 08:32:26 PDT 2026


https://github.com/mikekazakov created https://github.com/llvm/llvm-project/pull/210604

(to be rebased once std::mismatch is merged)
Part of #99938.

>From 650ebeba6d9e4867856e679d475e8f50edcdadde Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 21:03:38 +0100
Subject: [PATCH 01/15] Added a basic implementation of parallel 4-legged
 mismatch() based on __parallel_find()

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__pstl/backend_fwd.h           |   8 +
 libcxx/include/__pstl/backends/libdispatch.h  |   7 +-
 libcxx/include/__pstl/backends/serial.h       |  20 +++
 libcxx/include/__pstl/backends/std_thread.h   |   5 +
 libcxx/include/__pstl/cpu_algos/mismatch.h    |  88 +++++++++++
 .../mismatch/pstl.mismatch.pass.cpp           | 139 ++++++++++++++++++
 7 files changed, 267 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/include/__pstl/cpu_algos/mismatch.h
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b40f586161e62..6b5dc87fbe76d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -677,6 +677,7 @@ set(files
   __pstl/cpu_algos/find_if.h
   __pstl/cpu_algos/for_each.h
   __pstl/cpu_algos/merge.h
+  __pstl/cpu_algos/mismatch.h  
   __pstl/cpu_algos/stable_sort.h
   __pstl/cpu_algos/transform.h
   __pstl/cpu_algos/transform_reduce.h
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a84a768cad570..1d64c6f47630f 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -317,6 +317,14 @@ struct __is_sorted;
 // optional<bool>
 // operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Comp&& __comp) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __mismatch;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+// optional<pair<_ForwardIterator1, _ForwardIterator2>>
+// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+//                                _ForwardIterator2 __first2, _ForwardIterator2 __last2,
+//                                _Comp __comp) const noexcept;
+
 } // namespace __pstl
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h
index 33fd5de66fbb1..710506585ca22 100644
--- a/libcxx/include/__pstl/backends/libdispatch.h
+++ b/libcxx/include/__pstl/backends/libdispatch.h
@@ -33,6 +33,7 @@
 #include <__pstl/cpu_algos/find_if.h>
 #include <__pstl/cpu_algos/for_each.h>
 #include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/mismatch.h>
 #include <__pstl/cpu_algos/stable_sort.h>
 #include <__pstl/cpu_algos/transform.h>
 #include <__pstl/cpu_algos/transform_reduce.h>
@@ -237,7 +238,7 @@ struct __cpu_traits<__libdispatch_backend_tag> {
       auto __this_chunk_size = __chunk == 0 ? __partitions.__first_chunk_size_ : __partitions.__chunk_size_;
       auto __index           = __chunk == 0 ? 0
                                             : (__chunk * __partitions.__chunk_size_) +
-                                        (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
+                                                  (__partitions.__first_chunk_size_ - __partitions.__chunk_size_);
       if (__this_chunk_size != 1) {
         std::__construct_at(
             __values.get() + __chunk,
@@ -364,6 +365,10 @@ template <class _ExecutionPolicy>
 struct __merge<__libdispatch_backend_tag, _ExecutionPolicy>
     : __cpu_parallel_merge<__libdispatch_backend_tag, _ExecutionPolicy> {};
 
+template <class _ExecutionPolicy>
+struct __mismatch<__libdispatch_backend_tag, _ExecutionPolicy>
+    : __cpu_parallel_mismatch<__libdispatch_backend_tag, _ExecutionPolicy> {};
+
 template <class _ExecutionPolicy>
 struct __stable_sort<__libdispatch_backend_tag, _ExecutionPolicy>
     : __cpu_parallel_stable_sort<__libdispatch_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/backends/serial.h b/libcxx/include/__pstl/backends/serial.h
index f4142016ccc79..d90022ee37145 100644
--- a/libcxx/include/__pstl/backends/serial.h
+++ b/libcxx/include/__pstl/backends/serial.h
@@ -13,6 +13,7 @@
 #include <__algorithm/find_if.h>
 #include <__algorithm/for_each.h>
 #include <__algorithm/merge.h>
+#include <__algorithm/mismatch.h>
 #include <__algorithm/stable_sort.h>
 #include <__algorithm/transform.h>
 #include <__config>
@@ -55,6 +56,25 @@ struct __find_if<__serial_backend_tag, _ExecutionPolicy> {
   }
 };
 
+template <class _ExecutionPolicy>
+struct __mismatch<__serial_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _Predicate&& __pred) const noexcept {
+    return std::mismatch(
+        std::move(__first1),
+        std::move(__last1),
+        std::move(__first2),
+        std::move(__last2),
+        std::forward<_Predicate>(__pred));
+  }
+};
+
 template <class _ExecutionPolicy>
 struct __for_each<__serial_backend_tag, _ExecutionPolicy> {
   template <class _Policy, class _ForwardIterator, class _Function>
diff --git a/libcxx/include/__pstl/backends/std_thread.h b/libcxx/include/__pstl/backends/std_thread.h
index dd2c3f15403e3..93935d22b9442 100644
--- a/libcxx/include/__pstl/backends/std_thread.h
+++ b/libcxx/include/__pstl/backends/std_thread.h
@@ -17,6 +17,7 @@
 #include <__pstl/cpu_algos/find_if.h>
 #include <__pstl/cpu_algos/for_each.h>
 #include <__pstl/cpu_algos/merge.h>
+#include <__pstl/cpu_algos/mismatch.h>
 #include <__pstl/cpu_algos/stable_sort.h>
 #include <__pstl/cpu_algos/transform.h>
 #include <__pstl/cpu_algos/transform_reduce.h>
@@ -100,6 +101,10 @@ template <class _ExecutionPolicy>
 struct __merge<__std_thread_backend_tag, _ExecutionPolicy>
     : __cpu_parallel_merge<__std_thread_backend_tag, _ExecutionPolicy> {};
 
+template <class _ExecutionPolicy>
+struct __mismatch<__std_thread_backend_tag, _ExecutionPolicy>
+    : __cpu_parallel_mismatch<__std_thread_backend_tag, _ExecutionPolicy> {};
+
 template <class _ExecutionPolicy>
 struct __stable_sort<__std_thread_backend_tag, _ExecutionPolicy>
     : __cpu_parallel_stable_sort<__std_thread_backend_tag, _ExecutionPolicy> {};
diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
new file mode 100644
index 0000000000000..11ffdc332d633
--- /dev/null
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
+#define _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
+
+#include <__algorithm/mismatch.h>
+#include <__config>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__pstl/backend_fwd.h>
+#include <__pstl/cpu_algos/cpu_traits.h>
+#include <__pstl/cpu_algos/find_if.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+#include <optional>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+namespace __pstl {
+
+template <class _Backend, class _RawExecutionPolicy>
+struct __cpu_parallel_mismatch {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
+  _LIBCPP_HIDE_FROM_ABI optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&&,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2,
+             _Predicate __pred) const noexcept {
+    if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      // Look for a mismatch only in the prefix of the two ranges.
+      auto __n = std::min(__last1 - __first1, __last2 - __first2);
+      // Find a position in the first range where the predicate is false against the corresponding position in the
+      // second range.
+      auto __res = __pstl::__parallel_find<_Backend>(
+          __first1,
+          __first1 + __n,
+          [&__pred, __first1, __first2](_ForwardIterator1 __brick_first1, _ForwardIterator1 __brick_last1) {
+            // Run the sequential mismatch algorithm on these ranges:
+            //   [__brick_first1, __brick_last1) and
+            //   [__first2 + (__brick_first1 - __first1), __first2 + (__brick_last1 - __first1))
+            auto __brick_first2 = __first2 + (__brick_first1 - __first1);
+            return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
+                .first;
+          },
+          less<>{},
+          true);
+      if (!__res) {
+        return std::nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      auto __idx = *__res - __first1;
+      return pair<_ForwardIterator1, _ForwardIterator2>{std::move(*__res), __first2 + __idx};
+    } else {
+      // Non-random access iterators cannot be processed in parallel, fall back to the sequential implementation.
+      // Unsequenced execution is also implicitly covered by the sequential implementation.
+      return std::mismatch(
+          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::move(__pred));
+    }
+  }
+};
+
+} // namespace __pstl
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
new file mode 100644
index 0000000000000..9cbadda428ad9
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -0,0 +1,139 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2>
+//   pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+//                                                     ForwardIterator1 first1,
+//                                                     ForwardIterator1 last1,
+//                                                     ForwardIterator2 first2,
+//                                                     ForwardIterator2 last2);
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+EXECUTION_POLICY_SFINAE_TEST(mismatch);
+
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*>);
+
+// TODO: switch with a shared implemented once it's merged into main
+template <class Callable>
+void runway_sample(size_t size, Callable callable) {
+  constexpr size_t affix = 16;
+  // 0, 1, 2, ..., 15, 16, 50, 157, 493, 1548, ...
+  for (size_t i = 0; i < size; i = i < affix ? i + 1 : size_t(3.1415 * i)) {
+    callable(i);
+  }
+  if (size <= affix)
+    return;
+  // size - 16, size - 15, ..., size - 1
+  for (size_t i = size - affix; i < size; ++i) {
+    callable(i);
+  }
+}
+
+template <class Iter1, class Iter2>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // empty ranges
+      std::array<int, 1> lhs = {0};
+      std::array<int, 1> rhs = {0};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
+    }
+    {
+      // single element only
+      std::array<int, 1> lhs = {0};
+      std::array<int, 1> rhs = {0};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same range without mismatch
+      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same range with mismatch
+      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
+      std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
+    }
+    { // second range is smaller
+      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
+      std::array<int, 2> rhs = {0, 1};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+    { // first range is smaller
+      std::array<int, 2> lhs = {0, 1};
+      std::array<int, 8> rhs = {0, 1, 2, 2, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+    { // same size, mismatching at various positions
+      std::array<int, 1073> lhs;
+      std::array<int, 1073> rhs;
+      std::iota(std::begin(lhs), std::end(lhs), 0);
+      rhs = lhs;
+      runway_sample(lhs.size(), [&](size_t i) {
+        lhs[i] = -1;
+        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        lhs[i] = i;
+      });
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same values, different lengths
+      std::array<int, 739> lhs;
+      std::array<int, 739> rhs;
+      lhs.fill(42);
+      rhs.fill(42);
+      runway_sample(lhs.size(), [&](size_t i) {
+        // lhs is shorter
+        assert(
+            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin() + i), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        // rhs is shorter
+        assert(
+            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.begin() + i)) ==
+            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+      });
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const int*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
+  return 0;
+}

>From e96f0aa34d1b212b123d4c9917928e17d26270f3 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 21:05:01 +0100
Subject: [PATCH 02/15] Added a definition of a parallel 4-legged
 std::mismatch()

---
 libcxx/include/__algorithm/pstl.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 2bf9b4276baab..ab35b1a3e537b 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -138,6 +138,29 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
       std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+         _ForwardIterator1 __first1,
+         _ForwardIterator1 __last1,
+         _ForwardIterator2 __first2,
+         _ForwardIterator2 __last2) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__mismatch, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy),
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      std::move(__last2),
+      equal_to{});
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,

>From 472174e7343fc86a77bf314c7d088331dab6bae5 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 21:41:51 +0100
Subject: [PATCH 03/15] Added a default implementation of __mismatch_3leg based
 on __mismatch

---
 libcxx/include/__algorithm/pstl.h             | 18 ++++++++++
 libcxx/include/__pstl/backend_fwd.h           |  7 ++++
 libcxx/include/__pstl/backends/default.h      | 36 +++++++++++++++++++
 libcxx/include/module.modulemap.in            |  3 ++
 .../mismatch/pstl.mismatch.pass.cpp           | 20 +++++++++++
 5 files changed, 84 insertions(+)

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index ab35b1a3e537b..01c61fb00f4d5 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -161,6 +161,24 @@ mismatch(_ExecutionPolicy&& __policy,
       equal_to{});
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2> mismatch(
+    _ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__mismatch_3leg, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy),
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      equal_to{});
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index 1d64c6f47630f..d800e60916efc 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -325,6 +325,13 @@ struct __mismatch;
 //                                _ForwardIterator2 __first2, _ForwardIterator2 __last2,
 //                                _Comp __comp) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __mismatch_3leg;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+// optional<pair<_ForwardIterator1, _ForwardIterator2>>
+// operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+//                                _ForwardIterator2 __first2, _Comp __comp) const noexcept;
+
 } // namespace __pstl
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 5c78d4efa412b..05b328beae80f 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -63,6 +63,10 @@ namespace __pstl {
 // - is_partitioned
 // - find_first_of
 //
+// mismatch family
+// ---------------
+// - mismatch_3leg
+//
 // for_each family
 // ---------------
 // - for_each_n
@@ -211,6 +215,38 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
   }
 };
 
+//////////////////////////////////////////////////////////////
+// mismatch family
+//////////////////////////////////////////////////////////////
+
+template <class _ExecutionPolicy>
+struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Comp>
+  optional<pair<_ForwardIterator1, _ForwardIterator2>>
+  operator()(_Policy&& __policy,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _Comp __comp) const noexcept {
+    if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
+                  __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) {
+      // Forward to the 4-legged version of mismatch.
+      using _Mismatch           = __dispatch<__mismatch, __current_configuration, _ExecutionPolicy>;
+      _ForwardIterator2 __last2 = __first2 + (__last1 - __first1);
+      return _Mismatch()(
+          __policy,
+          std::move(__first1),
+          std::move(__last1),
+          std::move(__first2),
+          std::move(__last2),
+          std::move(__comp));
+    } else {
+      // Currently only random access iterators are supported for parallel mismatch_3leg.
+      return std::mismatch(std::move(__first1), std::move(__last1), std::move(__first2), std::move(__comp));
+    }
+  }
+};
+
 //////////////////////////////////////////////////////////////
 // for_each family
 //////////////////////////////////////////////////////////////
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 39b4e0bb986c6..752aa35643e2b 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2384,6 +2384,9 @@ module std {
       module merge {
         header "__pstl/cpu_algos/merge.h"
       }
+      module mismatch {
+        header "__pstl/cpu_algos/mismatch.h"
+      }
       module stable_sort {
         header "__pstl/cpu_algos/stable_sort.h"
         export std_core.utility_core.empty
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 9cbadda428ad9..0cb5c7632eed8 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -10,6 +10,14 @@
 
 // UNSUPPORTED: libcpp-has-no-incomplete-pstl
 
+// template <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2>
+//   pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+//                                                     ForwardIterator1 first1,
+//                                                     ForwardIterator1 last1,
+//                                                     ForwardIterator2 first2);
+//
 // template <class ExecutionPolicy,
 //           class ForwardIterator1,
 //           class ForwardIterator2>
@@ -61,6 +69,8 @@ struct Test {
       // empty ranges
       std::array<int, 1> lhs = {0};
       std::array<int, 1> rhs = {0};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
       assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Iter2(rhs.begin())) ==
              std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
     }
@@ -68,18 +78,24 @@ struct Test {
       // single element only
       std::array<int, 1> lhs = {0};
       std::array<int, 1> rhs = {0};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
       assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
              std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
     }
     { // same range without mismatch
       std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
       std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
       assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
              std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
     }
     { // same range with mismatch
       std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
       std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
       assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
              std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
     }
@@ -102,10 +118,14 @@ struct Test {
       rhs = lhs;
       runway_sample(lhs.size(), [&](size_t i) {
         lhs[i] = -1;
+        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
         assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
                std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
         lhs[i] = i;
       });
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
       assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
              std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
     }

>From 4aab10d6cc54f3abd475bd3aae03ac7d4103eb45 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 22:20:42 +0100
Subject: [PATCH 04/15] Added predicated versions

---
 libcxx/include/__algorithm/pstl.h             |  49 +++++
 .../mismatch/pstl.mismatch.pass.cpp           |   2 +
 .../mismatch/pstl.mismatch_pred.pass.cpp      | 178 ++++++++++++++++++
 3 files changed, 229 insertions(+)
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 01c61fb00f4d5..bc48fd9f48d7f 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -31,6 +31,7 @@ _LIBCPP_PUSH_MACROS
 #  include <__type_traits/remove_cvref.h>
 #  include <__utility/forward.h>
 #  include <__utility/move.h>
+#  include <__utility/pair.h>
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -138,6 +139,31 @@ count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __
       std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), __value);
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _BinaryPredicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+         _ForwardIterator1 __first1,
+         _ForwardIterator1 __last1,
+         _ForwardIterator2 __first2,
+         _ForwardIterator2 __last2,
+         _BinaryPredicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__mismatch, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy),
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      std::move(__last2),
+      std::move(__pred));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,
@@ -161,6 +187,29 @@ mismatch(_ExecutionPolicy&& __policy,
       equal_to{});
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator1,
+          class _ForwardIterator2,
+          class _BinaryPredicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<_ForwardIterator1, _ForwardIterator2>
+mismatch(_ExecutionPolicy&& __policy,
+         _ForwardIterator1 __first1,
+         _ForwardIterator1 __last1,
+         _ForwardIterator2 __first2,
+         _BinaryPredicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "mismatch requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "mismatch requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__mismatch_3leg, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy),
+      std::move(__first1),
+      std::move(__last1),
+      std::move(__first2),
+      std::move(__pred));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 0cb5c7632eed8..8584f2779927f 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -42,6 +42,8 @@
 
 EXECUTION_POLICY_SFINAE_TEST(mismatch);
 
+static_assert(sfinae_test_mismatch<int, int*, int*, int*>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*>);
 static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*>);
 static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*>);
 
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
new file mode 100644
index 0000000000000..39e952cbc38f6
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2,
+//           class BinaryPredicate>
+//   pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+//                                                     ForwardIterator1 first1,
+//                                                     ForwardIterator1 last1,
+//                                                     ForwardIterator2 first2,
+//                                                     BinaryPredicate pred);
+//
+// template <class ExecutionPolicy,
+//           class ForwardIterator1,
+//           class ForwardIterator2,
+//           class BinaryPredicate>
+//   pair<ForwardIterator1, ForwardIterator2> mismatch(ExecutionPolicy&& exec,
+//                                                     ForwardIterator1 first1,
+//                                                     ForwardIterator1 last1,
+//                                                     ForwardIterator2 first2,
+//                                                     ForwardIterator2 last2,
+//                                                     BinaryPredicate pred);
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+EXECUTION_POLICY_SFINAE_TEST(mismatch);
+
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, bool (*)(int, int)>);
+static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
+
+// TODO: switch with a shared implemented once it's merged into main
+template <class Callable>
+void runway_sample(size_t size, Callable callable) {
+  constexpr size_t affix = 16;
+  // 0, 1, 2, ..., 15, 16, 50, 157, 493, 1548, ...
+  for (size_t i = 0; i < size; i = i < affix ? i + 1 : size_t(3.1415 * i)) {
+    callable(i);
+  }
+  if (size <= affix)
+    return;
+  // size - 16, size - 15, ..., size - 1
+  for (size_t i = size - affix; i < size; ++i) {
+    callable(i);
+  }
+}
+
+struct Pred {
+  bool operator()(int a, int b) const { return a * 2 == b; }
+};
+
+template <class Iter1, class Iter2>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      // empty ranges
+      std::array<int, 1> lhs = {0};
+      std::array<int, 1> rhs = {0};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
+      assert(std::mismatch(
+                 policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
+    }
+    {
+      // single element only
+      std::array<int, 1> lhs = {1};
+      std::array<int, 1> rhs = {2};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same range without mismatch
+      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      std::array<int, 8> rhs = {0, 2, 4, 6, 0, 2, 4, 6};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same range with mismatch
+      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
+      std::array<int, 8> rhs = {0, 2, 4, 7, 0, 2, 4, 6};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
+    }
+    { // second range is smaller
+      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
+      std::array<int, 2> rhs = {0, 2};
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+    { // first range is smaller
+      std::array<int, 2> lhs = {0, 1};
+      std::array<int, 8> rhs = {0, 2, 2, 2, 0, 1, 2, 3};
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+    { // same size, mismatching at various positions
+      std::array<int, 1073> lhs;
+      std::array<int, 1073> rhs;
+      std::iota(std::begin(lhs), std::end(lhs), 0);
+      rhs = lhs;
+      std::for_each(std::begin(rhs), std::end(rhs), [](int& x) { x *= 2; });
+      runway_sample(lhs.size(), [&](size_t i) {
+        lhs[i] = -1;
+        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(
+            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        lhs[i] = i;
+      });
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // same values, different lengths
+      std::array<int, 739> lhs;
+      std::array<int, 739> rhs;
+      lhs.fill(42);
+      rhs.fill(84);
+      runway_sample(lhs.size(), [&](size_t i) {
+        // lhs is shorter
+        assert(std::mismatch(
+                   policy, Iter1(lhs.begin()), Iter1(lhs.begin() + i), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        // rhs is shorter
+        assert(std::mismatch(
+                   policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.begin() + i), Pred{}) ==
+               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+      });
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const int*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
+  return 0;
+}

>From 2da95a5c532de58960651a18c9a93c9435577a89 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 22:39:47 +0100
Subject: [PATCH 05/15] Added tests against custom types

---
 libcxx/include/__pstl/backends/default.h      |  1 +
 .../mismatch/pstl.mismatch.pass.cpp           | 53 ++++++++++++++++++
 .../mismatch/pstl.mismatch_pred.pass.cpp      | 56 ++++++++++++++++++-
 3 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 05b328beae80f..f4f73e81ed90b 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -16,6 +16,7 @@
 #include <__algorithm/find_if.h>
 #include <__algorithm/for_each_n.h>
 #include <__algorithm/is_sorted.h>
+#include <__algorithm/mismatch.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__functional/not_fn.h>
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 8584f2779927f..5e46831539c30 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -63,6 +63,30 @@ void runway_sample(size_t size, Callable callable) {
   }
 }
 
+// The types X and Y are provided to test that the mismatch algorithm can be used with heterogeneous custom types.
+
+struct X {
+  X() = delete;
+  X(int i) : i(i) {}
+  X(const X&) = delete;
+  int value() const { return i; }
+
+private:
+  int i;
+};
+
+struct Y {
+  Y() = delete;
+  Y(int i) : i(i) {}
+  Y(const Y&) = delete;
+  int value() const { return i; }
+
+private:
+  int i;
+};
+
+bool operator==(const X& lhs, const Y& rhs) { return lhs.value() == rhs.value(); }
+
 template <class Iter1, class Iter2>
 struct Test {
   template <class ExecutionPolicy>
@@ -150,6 +174,29 @@ struct Test {
   }
 };
 
+template <class Iter1, class Iter2>
+struct TestXY {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    { // same ranges
+      std::array<X, 3> lhs = {X(1), X(5), X(7)};
+      std::array<Y, 3> rhs = {Y(1), Y(5), Y(7)};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // one element mismatch
+      std::array<X, 3> lhs = {X(1), X(5), X(7)};
+      std::array<Y, 3> rhs = {Y(1), Y(5), Y(8)};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
+             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
+             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+  }
+};
+
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
                     using Iter = typename decltype(v)::type;
@@ -157,5 +204,11 @@ int main(int, char**) {
                         types::forward_iterator_list<const int*>{},
                         TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
                   }});
+  types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const Y*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::template apply>{});
+                  }});
   return 0;
 }
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
index 39e952cbc38f6..9c0dfc6c0c127 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -67,8 +67,31 @@ void runway_sample(size_t size, Callable callable) {
   }
 }
 
+// The types X and Y are provided to test that the mismatch algorithm can be used with heterogeneous custom types.
+
+struct X {
+  X() = delete;
+  X(int i) : i(i) {}
+  X(const X&) = delete;
+  int value() const { return i; }
+
+private:
+  int i;
+};
+
+struct Y {
+  Y() = delete;
+  Y(int i) : i(i) {}
+  Y(const Y&) = delete;
+  int value() const { return i; }
+
+private:
+  int i;
+};
+
 struct Pred {
-  bool operator()(int a, int b) const { return a * 2 == b; }
+  bool operator()(int lhs, int rhs) const { return lhs * 2 == rhs; }
+  bool operator()(const X& lhs, const Y& rhs) const { return lhs.value() * 2 == rhs.value(); }
 };
 
 template <class Iter1, class Iter2>
@@ -167,6 +190,31 @@ struct Test {
   }
 };
 
+template <class Iter1, class Iter2>
+struct TestXY {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    { // same ranges
+      std::array<X, 3> lhs = {X(1), X(5), X(7)};
+      std::array<Y, 3> rhs = {Y(2), Y(10), Y(14)};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+    }
+    { // one element mismatch
+      std::array<X, 3> lhs = {X(1), X(5), X(7)};
+      std::array<Y, 3> rhs = {Y(2), Y(10), Y(13)};
+      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
+             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      assert(
+          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
+          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+    }
+  }
+};
+
 int main(int, char**) {
   types::for_each(types::forward_iterator_list<const int*>{}, types::apply_type_identity{[](auto v) {
                     using Iter = typename decltype(v)::type;
@@ -174,5 +222,11 @@ int main(int, char**) {
                         types::forward_iterator_list<const int*>{},
                         TestIteratorWithPolicies<types::partial_instantiation<Test, Iter>::template apply>{});
                   }});
+  types::for_each(types::forward_iterator_list<const X*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<const Y*>{},
+                        TestIteratorWithPolicies<types::partial_instantiation<TestXY, Iter>::template apply>{});
+                  }});
   return 0;
 }

>From 2fb2bb1a154212dc1cbf3a1ea9e3e1cf5a00db48 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 22:52:50 +0100
Subject: [PATCH 06/15] Added a nodiscard test

---
 libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index 049c8dc88c2da..c538d7841dce6 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -58,4 +58,12 @@ void test() {
   std::is_sorted(std::execution::par, std::begin(a), std::end(a), pred2);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::reverse_copy(std::execution::par, std::begin(a), std::end(a), std::begin(b));
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b));
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b));
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), pred2);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
 }

>From 8c35d0cac6fc6a3daf494de08ac0a2fd365d50f1 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 22:57:47 +0100
Subject: [PATCH 07/15] Added an iterator requirement test

---
 .../pstl.iterator-requirements.verify.cpp        | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index fbe3460b67f17..4526cad0615b0 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -135,6 +135,22 @@ void f(non_forward_iterator non_fwd,
     (void)std::merge(pol, it, it, it, it, non_output, pred);    // expected-error@*:* {{static assertion failed: merge}}
   }
 
+  {
+    (void)std::mismatch(pol, non_fwd, non_fwd, it); // expected-error@*:* {{static assertion failed: mismatch}}
+    (void)std::mismatch(pol, it, it, non_fwd);      // expected-error@*:* {{static assertion failed: mismatch}}
+
+    (void)std::mismatch(pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: mismatch}}
+    (void)std::mismatch(pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: mismatch}}
+
+    (void)std::mismatch(pol, non_fwd, non_fwd, it, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+    (void)std::mismatch(pol, it, it, non_fwd, pred);      // expected-error@*:* {{static assertion failed: mismatch}}
+
+    (void)std::mismatch(
+        pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+    (void)std::mismatch(
+        pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: mismatch}}
+  }
+
   {
     (void)std::move(pol, non_fwd, non_fwd, out); // expected-error@*:* {{static assertion failed: move}}
     (void)std::move(pol, it, it, non_fwd);       // expected-error@*:* {{static assertion failed: move}}

>From a8b984852860283d06ab06bbdf05a28f01965326 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 23:00:09 +0100
Subject: [PATCH 08/15] Added an include of <__algorithm/min.h>

---
 libcxx/include/__pstl/cpu_algos/mismatch.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
index 11ffdc332d633..8361731e78cfc 100644
--- a/libcxx/include/__pstl/cpu_algos/mismatch.h
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -9,8 +9,9 @@
 #ifndef _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
 #define _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
 
-#include <__algorithm/mismatch.h>
 #include <__config>
+#include <__algorithm/mismatch.h>
+#include <__algorithm/min.h>
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>

>From 3845b7e0e242d455f0fcc68a814ed625544c3d8c Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Mon, 13 Jul 2026 23:05:29 +0100
Subject: [PATCH 09/15] Added an exception handling test

---
 libcxx/include/__pstl/cpu_algos/mismatch.h    |  4 +--
 .../pstl.exception_handling.pass.cpp          | 25 +++++++++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
index 8361731e78cfc..597a47fb185c8 100644
--- a/libcxx/include/__pstl/cpu_algos/mismatch.h
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -9,9 +9,9 @@
 #ifndef _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
 #define _LIBCPP___PSTL_CPU_ALGOS_MISMATCH_H
 
-#include <__config>
-#include <__algorithm/mismatch.h>
 #include <__algorithm/min.h>
+#include <__algorithm/mismatch.h>
+#include <__config>
 #include <__functional/operations.h>
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index 8af2a0a15fd5c..820a5d92c19e0 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -248,6 +248,31 @@ int main(int, char**) {
         });
       }
 
+      {
+        auto compare = maybe_throw(tokens[5], [](int x, int y) -> bool { return x < y; });
+
+        // mismatch(first1, last1, first2)
+        assert_non_throwing([=, &policy] {
+          (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2));
+        });
+
+        // mismatch(first1, last1, first2, last2)
+        assert_non_throwing([=, &policy] {
+          (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2));
+        });
+
+        // mismatch(first1, last1, first2, pred)
+        assert_non_throwing([=, &policy] {
+          (void)std::mismatch(policy, std::move(first1), std::move(last1), std::move(first2), compare);
+        });
+
+        // mismatch(first1, last1, first2, last2, pred)
+        assert_non_throwing([=, &policy] {
+          (void)std::mismatch(
+              policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), compare);
+        });
+      }
+
       {
         // move(first, last, dest)
         assert_non_throwing([=, &policy] {

>From fbc073f5742c81ae78d12058ecf4618213afb6f0 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 14 Jul 2026 09:43:45 +0100
Subject: [PATCH 10/15] Changed the variable name to avoid shadowing

---
 .../alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp | 12 ++++++------
 .../mismatch/pstl.mismatch_pred.pass.cpp             | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 5e46831539c30..941fe07b58327 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -67,22 +67,22 @@ void runway_sample(size_t size, Callable callable) {
 
 struct X {
   X() = delete;
-  X(int i) : i(i) {}
+  X(int i) : i_(i) {}
   X(const X&) = delete;
-  int value() const { return i; }
+  int value() const { return i_; }
 
 private:
-  int i;
+  int i_;
 };
 
 struct Y {
   Y() = delete;
-  Y(int i) : i(i) {}
+  Y(int i) : i_(i) {}
   Y(const Y&) = delete;
-  int value() const { return i; }
+  int value() const { return i_; }
 
 private:
-  int i;
+  int i_;
 };
 
 bool operator==(const X& lhs, const Y& rhs) { return lhs.value() == rhs.value(); }
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
index 9c0dfc6c0c127..a4b15a56bd071 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -71,22 +71,22 @@ void runway_sample(size_t size, Callable callable) {
 
 struct X {
   X() = delete;
-  X(int i) : i(i) {}
+  X(int i) : i_(i) {}
   X(const X&) = delete;
-  int value() const { return i; }
+  int value() const { return i_; }
 
 private:
-  int i;
+  int i_;
 };
 
 struct Y {
   Y() = delete;
-  Y(int i) : i(i) {}
+  Y(int i) : i_(i) {}
   Y(const Y&) = delete;
-  int value() const { return i; }
+  int value() const { return i_; }
 
 private:
-  int i;
+  int i_;
 };
 
 struct Pred {

>From baaa82257b3d2f94d4bf9d02f6761e7cf3ee9df6 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 14 Jul 2026 20:27:14 +0100
Subject: [PATCH 11/15] Use raw C array in the tests

---
 .../mismatch/pstl.mismatch.pass.cpp           | 153 +++++++-------
 .../mismatch/pstl.mismatch_pred.pass.cpp      | 192 +++++++++++-------
 2 files changed, 198 insertions(+), 147 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 941fe07b58327..17edf34ee7832 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -28,7 +28,6 @@
 //                                                     ForwardIterator2 last2);
 
 #include <algorithm>
-#include <array>
 #include <cassert>
 #include <functional>
 #include <iterator>
@@ -93,82 +92,98 @@ struct Test {
   void operator()(ExecutionPolicy&& policy) {
     {
       // empty ranges
-      std::array<int, 1> lhs = {0};
-      std::array<int, 1> rhs = {0};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
+      int lhs[1] = {0};
+      int rhs[1] = {0};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+      assert(
+          std::mismatch(
+              policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs))) ==
+          std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
     }
     {
       // single element only
-      std::array<int, 1> lhs = {0};
-      std::array<int, 1> rhs = {0};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      int lhs[1] = {0};
+      int rhs[1] = {0};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same range without mismatch
-      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
-      std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+      int rhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same range with mismatch
-      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
-      std::array<int, 8> rhs = {0, 1, 2, 3, 0, 1, 2, 3};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
+      int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+      int rhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
     }
     { // second range is smaller
-      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
-      std::array<int, 2> rhs = {0, 1};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+      int rhs[2] = {0, 1};
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
     { // first range is smaller
-      std::array<int, 2> lhs = {0, 1};
-      std::array<int, 8> rhs = {0, 1, 2, 2, 0, 1, 2, 3};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      int lhs[2] = {0, 1};
+      int rhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
     { // same size, mismatching at various positions
-      std::array<int, 1073> lhs;
-      std::array<int, 1073> rhs;
+      int lhs[1073];
+      int rhs[1073];
       std::iota(std::begin(lhs), std::end(lhs), 0);
-      rhs = lhs;
-      runway_sample(lhs.size(), [&](size_t i) {
+      std::copy(std::begin(lhs), std::end(lhs), std::begin(rhs));
+      runway_sample(std::size(lhs), [&](size_t i) {
         lhs[i] = -1;
-        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
-        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+               std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+        assert(
+            std::mismatch(
+                policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+            std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
         lhs[i] = i;
       });
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same values, different lengths
-      std::array<int, 739> lhs;
-      std::array<int, 739> rhs;
-      lhs.fill(42);
-      rhs.fill(42);
-      runway_sample(lhs.size(), [&](size_t i) {
+      int lhs[739];
+      int rhs[739];
+      std::fill(std::begin(lhs), std::end(lhs), 42);
+      std::fill(std::begin(rhs), std::end(rhs), 42);
+      runway_sample(std::size(lhs), [&](size_t i) {
         // lhs is shorter
-        assert(
-            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin() + i), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(
+                   policy,
+                   Iter1(std::begin(lhs)),
+                   Iter1(std::begin(lhs) + i),
+                   Iter2(std::begin(rhs)),
+                   Iter2(std::end(rhs))) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
         // rhs is shorter
-        assert(
-            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.begin() + i)) ==
-            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(policy,
+                             Iter1(std::begin(lhs)),
+                             Iter1(std::end(lhs)),
+                             Iter2(std::begin(rhs)),
+                             Iter2(std::begin(rhs) + i)) ==
+               std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
       });
     }
   }
@@ -179,20 +194,22 @@ struct TestXY {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
     { // same ranges
-      std::array<X, 3> lhs = {X(1), X(5), X(7)};
-      std::array<Y, 3> rhs = {Y(1), Y(5), Y(7)};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      X lhs[3] = {X(1), X(5), X(7)};
+      Y rhs[3] = {Y(1), Y(5), Y(7)};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // one element mismatch
-      std::array<X, 3> lhs = {X(1), X(5), X(7)};
-      std::array<Y, 3> rhs = {Y(1), Y(5), Y(8)};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin())) ==
-             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end())) ==
-             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      X lhs[3] = {X(1), X(5), X(7)};
+      Y rhs[3] = {Y(1), Y(5), Y(8)};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+      assert(std::mismatch(
+                 policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Iter2(std::end(rhs))) ==
+             std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
   }
 };
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
index a4b15a56bd071..18c4fe1abad0c 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -32,7 +32,6 @@
 //                                                     BinaryPredicate pred);
 
 #include <algorithm>
-#include <array>
 #include <cassert>
 #include <functional>
 #include <iterator>
@@ -100,91 +99,120 @@ struct Test {
   void operator()(ExecutionPolicy&& policy) {
     {
       // empty ranges
-      std::array<int, 1> lhs = {0};
-      std::array<int, 1> rhs = {0};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
-      assert(std::mismatch(
-                 policy, Iter1(lhs.begin()), Iter1(lhs.begin()), Iter2(rhs.begin()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.begin()), Iter2(rhs.begin())));
+      int lhs[1] = {0};
+      int rhs[1] = {0};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::begin(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::begin(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::begin(lhs)), Iter2(std::begin(rhs))));
     }
     {
       // single element only
-      std::array<int, 1> lhs = {1};
-      std::array<int, 1> rhs = {2};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      int lhs[1] = {1};
+      int rhs[1] = {2};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same range without mismatch
-      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
-      std::array<int, 8> rhs = {0, 2, 4, 6, 0, 2, 4, 6};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+      int rhs[8] = {0, 2, 4, 6, 0, 2, 4, 6};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same range with mismatch
-      std::array<int, 8> lhs = {0, 1, 2, 3, 0, 1, 2, 3};
-      std::array<int, 8> rhs = {0, 2, 4, 7, 0, 2, 4, 6};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.begin() + 3), Iter2(rhs.begin() + 3)));
+      int lhs[8] = {0, 1, 2, 3, 0, 1, 2, 3};
+      int rhs[8] = {0, 2, 4, 7, 0, 2, 4, 6};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 3), Iter2(std::begin(rhs) + 3)));
     }
     { // second range is smaller
-      std::array<int, 8> lhs = {0, 1, 2, 2, 0, 1, 2, 3};
-      std::array<int, 2> rhs = {0, 2};
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      int lhs[8] = {0, 1, 2, 2, 0, 1, 2, 3};
+      int rhs[2] = {0, 2};
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
     { // first range is smaller
-      std::array<int, 2> lhs = {0, 1};
-      std::array<int, 8> rhs = {0, 2, 2, 2, 0, 1, 2, 3};
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      int lhs[2] = {0, 1};
+      int rhs[8] = {0, 2, 2, 2, 0, 1, 2, 3};
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
     { // same size, mismatching at various positions
-      std::array<int, 1073> lhs;
-      std::array<int, 1073> rhs;
+      int lhs[1073];
+      int rhs[1073];
       std::iota(std::begin(lhs), std::end(lhs), 0);
-      rhs = lhs;
-      std::for_each(std::begin(rhs), std::end(rhs), [](int& x) { x *= 2; });
-      runway_sample(lhs.size(), [&](size_t i) {
+      std::transform(std::begin(lhs), std::end(lhs), std::begin(rhs), [](int x) { return x * 2; });
+      runway_sample(std::size(lhs), [&](size_t i) {
         lhs[i] = -1;
-        assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
-        assert(
-            std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-            std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+               std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
+        assert(std::mismatch(policy,
+                             Iter1(std::begin(lhs)),
+                             Iter1(std::end(lhs)),
+                             Iter2(std::begin(rhs)),
+                             Iter2(std::end(rhs)),
+                             Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
         lhs[i] = i;
       });
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // same values, different lengths
-      std::array<int, 739> lhs;
-      std::array<int, 739> rhs;
-      lhs.fill(42);
-      rhs.fill(84);
-      runway_sample(lhs.size(), [&](size_t i) {
+      int lhs[739];
+      int rhs[739];
+      std::fill(std::begin(lhs), std::end(lhs), 42);
+      std::fill(std::begin(rhs), std::end(rhs), 84);
+      runway_sample(std::size(lhs), [&](size_t i) {
         // lhs is shorter
-        assert(std::mismatch(
-                   policy, Iter1(lhs.begin()), Iter1(lhs.begin() + i), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(policy,
+                             Iter1(std::begin(lhs)),
+                             Iter1(std::begin(lhs) + i),
+                             Iter2(std::begin(rhs)),
+                             Iter2(std::end(rhs)),
+                             Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
         // rhs is shorter
-        assert(std::mismatch(
-                   policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.begin() + i), Pred{}) ==
-               std::make_pair(Iter1(lhs.begin() + i), Iter2(rhs.begin() + i)));
+        assert(std::mismatch(policy,
+                             Iter1(std::begin(lhs)),
+                             Iter1(std::end(lhs)),
+                             Iter2(std::begin(rhs)),
+                             Iter2(std::begin(rhs) + i),
+                             Pred{}) == std::make_pair(Iter1(std::begin(lhs) + i), Iter2(std::begin(rhs) + i)));
       });
     }
   }
@@ -195,22 +223,28 @@ struct TestXY {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
     { // same ranges
-      std::array<X, 3> lhs = {X(1), X(5), X(7)};
-      std::array<Y, 3> rhs = {Y(2), Y(10), Y(14)};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.end()), Iter2(rhs.end())));
+      X lhs[3] = {X(1), X(5), X(7)};
+      Y rhs[3] = {Y(2), Y(10), Y(14)};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::end(lhs)), Iter2(std::end(rhs))));
     }
     { // one element mismatch
-      std::array<X, 3> lhs = {X(1), X(5), X(7)};
-      std::array<Y, 3> rhs = {Y(2), Y(10), Y(13)};
-      assert(std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Pred{}) ==
-             std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
-      assert(
-          std::mismatch(policy, Iter1(lhs.begin()), Iter1(lhs.end()), Iter2(rhs.begin()), Iter2(rhs.end()), Pred{}) ==
-          std::make_pair(Iter1(lhs.begin() + 2), Iter2(rhs.begin() + 2)));
+      X lhs[3] = {X(1), X(5), X(7)};
+      Y rhs[3] = {Y(2), Y(10), Y(13)};
+      assert(std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::end(lhs)), Iter2(std::begin(rhs)), Pred{}) ==
+             std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
+      assert(std::mismatch(policy,
+                           Iter1(std::begin(lhs)),
+                           Iter1(std::end(lhs)),
+                           Iter2(std::begin(rhs)),
+                           Iter2(std::end(rhs)),
+                           Pred{}) == std::make_pair(Iter1(std::begin(lhs) + 2), Iter2(std::begin(rhs) + 2)));
     }
   }
 };

>From 212e25406377a6a5da7fc7679015000a4086e4a1 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 14 Jul 2026 21:08:55 +0100
Subject: [PATCH 12/15] Fixed typos in the comment

---
 .../algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp | 2 +-
 .../alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index 17edf34ee7832..ed59fa9eca669 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -46,7 +46,7 @@ static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*,
 static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*>);
 static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*>);
 
-// TODO: switch with a shared implemented once it's merged into main
+// TODO: switch to the shared implementation once it's merged into main
 template <class Callable>
 void runway_sample(size_t size, Callable callable) {
   constexpr size_t affix = 16;
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
index 18c4fe1abad0c..338503d784a31 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -50,7 +50,7 @@ static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*,
 static_assert(sfinae_test_mismatch<int, int*, int*, int*, int*, bool (*)(int, int)>);
 static_assert(!sfinae_test_mismatch<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
 
-// TODO: switch with a shared implemented once it's merged into main
+// TODO: switch to the shared implementation once it's merged into main
 template <class Callable>
 void runway_sample(size_t size, Callable callable) {
   constexpr size_t affix = 16;

>From b80675016128dbeb1db5a3084edee9bb6ab89fea Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 15 Jul 2026 21:43:20 +0100
Subject: [PATCH 13/15] Added comments explaining what the parameters mean

---
 libcxx/include/__pstl/cpu_algos/mismatch.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__pstl/cpu_algos/mismatch.h b/libcxx/include/__pstl/cpu_algos/mismatch.h
index 597a47fb185c8..3d702b03d3afe 100644
--- a/libcxx/include/__pstl/cpu_algos/mismatch.h
+++ b/libcxx/include/__pstl/cpu_algos/mismatch.h
@@ -63,8 +63,9 @@ struct __cpu_parallel_mismatch {
             return std::mismatch(std::move(__brick_first1), std::move(__brick_last1), std::move(__brick_first2), __pred)
                 .first;
           },
-          less<>{},
-          true);
+          less<>{}, // `less` here means the lowest index among the mismatches
+          true      // `true` here means we want the first mismatch, not the last
+      );
       if (!__res) {
         return std::nullopt; // Failed to run the algorithm, propagate the error.
       }

>From 12ac822e8571b5d944ffea6d4f62396a954f4672 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 15 Jul 2026 21:50:51 +0100
Subject: [PATCH 14/15] Added tests of the return types

---
 .../mismatch/pstl.mismatch.pass.cpp              | 10 ++++++++++
 .../mismatch/pstl.mismatch_pred.pass.cpp         | 16 ++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
index ed59fa9eca669..cc7ef6feb2356 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch.pass.cpp
@@ -90,6 +90,16 @@ template <class Iter1, class Iter2>
 struct Test {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
+    {
+      // check the return types
+      int lhs[1]       = {0};
+      int rhs[1]       = {0};
+      auto res_3legged = std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)));
+      auto res_4legged = std::mismatch(
+          policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Iter2(std::begin(rhs)));
+      static_assert(std::is_same_v<decltype(res_3legged), std::pair<Iter1, Iter2>>);
+      static_assert(std::is_same_v<decltype(res_4legged), std::pair<Iter1, Iter2>>);
+    }
     {
       // empty ranges
       int lhs[1] = {0};
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
index 338503d784a31..d80da0cf0b542 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/mismatch/pstl.mismatch_pred.pass.cpp
@@ -97,6 +97,22 @@ template <class Iter1, class Iter2>
 struct Test {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
+    {
+      // check the return types
+      int lhs[1] = {0};
+      int rhs[1] = {0};
+      auto res_3legged =
+          std::mismatch(policy, Iter1(std::begin(lhs)), Iter1(std::begin(lhs)), Iter2(std::begin(rhs)), Pred{});
+      auto res_4legged = std::mismatch(
+          policy,
+          Iter1(std::begin(lhs)),
+          Iter1(std::begin(lhs)),
+          Iter2(std::begin(rhs)),
+          Iter2(std::begin(rhs)),
+          Pred{});
+      static_assert(std::is_same_v<decltype(res_3legged), std::pair<Iter1, Iter2>>);
+      static_assert(std::is_same_v<decltype(res_4legged), std::pair<Iter1, Iter2>>);
+    }
     {
       // empty ranges
       int lhs[1] = {0};

>From 01513beffed6c7812b59d62ab4cdae683c9e0c10 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 19 Jul 2026 16:27:43 +0100
Subject: [PATCH 15/15] Added an implementation of adjacent_find() based on
 mismatch()

---
 libcxx/include/__algorithm/pstl.h             |  25 +++
 libcxx/include/__pstl/backend_fwd.h           |   7 +
 libcxx/include/__pstl/backends/default.h      |  45 +++++
 .../pstl.iterator-requirements.verify.cpp     |   6 +
 .../algorithms/pstl.nodiscard.verify.cpp      |   4 +
 .../pstl.adjacent_find.pass.cpp               | 164 +++++++++++++++++
 .../pstl.adjacent_find_pred.pass.cpp          | 173 ++++++++++++++++++
 .../pstl.exception_handling.pass.cpp          |  12 ++
 8 files changed, 436 insertions(+)
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find.pass.cpp
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find_pred.pass.cpp

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index bc48fd9f48d7f..0447691c3b86b 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -228,6 +228,31 @@ template <class _ExecutionPolicy,
       equal_to{});
 }
 
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator
+adjacent_find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "adjacent_find requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__adjacent_find, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), equal_to{});
+}
+
+template <class _ExecutionPolicy,
+          class _ForwardIterator,
+          class _BinaryPredicate,
+          class _RawPolicy                                    = __remove_cvref_t<_ExecutionPolicy>,
+          enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator adjacent_find(
+    _ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __predicate) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "adjacent_find requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__adjacent_find, __pstl::__current_configuration, _RawPolicy>;
+  return __pstl::__handle_exception<_Implementation>(
+      std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__predicate));
+}
+
 template <class _ExecutionPolicy,
           class _ForwardIterator1,
           class _ForwardIterator2,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index d800e60916efc..1981883d2292e 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -332,6 +332,13 @@ struct __mismatch_3leg;
 // operator()(_Policy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
 //                                _ForwardIterator2 __first2, _Comp __comp) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __adjacent_find;
+// template <class _Policy, class _ForwardIterator, class _BinaryPredicate>
+// optional<_ForwardIterator>
+// operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last,
+//                                _BinaryPredicate __predicate) const noexcept;
+
 } // namespace __pstl
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index f4f73e81ed90b..c37d57858f46d 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 
+#include <__algorithm/adjacent_find.h>
 #include <__algorithm/copy_n.h>
 #include <__algorithm/equal.h>
 #include <__algorithm/fill_n.h>
@@ -24,6 +25,7 @@
 #include <__iterator/concepts.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/next.h>
+#include <__iterator/prev.h>
 #include <__iterator/reverse_iterator.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
@@ -66,6 +68,7 @@ namespace __pstl {
 //
 // mismatch family
 // ---------------
+// - adjacent_find
 // - mismatch_3leg
 //
 // for_each family
@@ -248,6 +251,48 @@ struct __mismatch_3leg<__default_backend_tag, _ExecutionPolicy> {
   }
 };
 
+template <class _ExecutionPolicy>
+struct __adjacent_find<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator, class _BinaryPredicate>
+  optional<_ForwardIterator>
+  operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __predicate)
+      const noexcept {
+    if constexpr (__has_bidirectional_iterator_category<_ForwardIterator>::value) {
+      using _Mismatch = __dispatch<__mismatch, __current_configuration, _ExecutionPolicy>;
+      if (__first == __last) {
+        return __last; // Empty range, return __last.
+      }
+      _ForwardIterator __first2 = std::next(__first);
+      if (__first2 == __last) {
+        return __last; // Single element range, no adjacent elements, return __last.
+      }
+      _ForwardIterator __last2 = std::prev(__last);
+      // Find the first match within two overlapping ranges, expressed as a double negation of the predicate:
+      //   [first, __last - 1)
+      //   [first + 1, __last)
+      auto __res = _Mismatch()(
+          __policy,
+          std::move(__first),
+          std::move(__last2),
+          std::move(__first2),
+          __last,
+          [&](__iterator_reference<_ForwardIterator> __lhs, __iterator_reference<_ForwardIterator> __rhs) {
+            return !__predicate(__lhs, __rhs);
+          });
+      if (!__res) {
+        return nullopt; // Failed to run the algorithm, propagate the error.
+      }
+      if (__res->second == __last) {
+        return __last; // No adjacent elements found, return __last.
+      }
+      return __res->first; // Return the first iterator of the pair of mismatched elements.
+    } else {
+      // Currently anything outside bidirectional iterators has to be processed serially
+      return std::adjacent_find(std::move(__first), std::move(__last), std::move(__predicate));
+    }
+  }
+};
+
 //////////////////////////////////////////////////////////////
 // for_each family
 //////////////////////////////////////////////////////////////
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 4526cad0615b0..741bef52c1638 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -151,6 +151,12 @@ void f(non_forward_iterator non_fwd,
         pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: mismatch}}
   }
 
+  {
+    (void)std::adjacent_find(pol, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: adjacent_find}}
+    (void)std::adjacent_find(
+        pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: adjacent_find}}
+  }
+
   {
     (void)std::move(pol, non_fwd, non_fwd, out); // expected-error@*:* {{static assertion failed: move}}
     (void)std::move(pol, it, it, non_fwd);       // expected-error@*:* {{static assertion failed: move}}
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index c538d7841dce6..e00dccdafd459 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -66,4 +66,8 @@ void test() {
   std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), pred2);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::mismatch(std::execution::par, std::begin(a), std::end(a), std::begin(b), std::end(b), pred2);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::adjacent_find(std::execution::par, std::begin(a), std::end(a));
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::adjacent_find(std::execution::par, std::begin(a), std::end(a), pred2);
 }
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find.pass.cpp
new file mode 100644
index 0000000000000..ff0b5c05bd364
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find.pass.cpp
@@ -0,0 +1,164 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template<class ExecutionPolicy, class ForwardIterator>
+// ForwardIterator adjacent_find(ExecutionPolicy&& exec,
+//                               ForwardIterator first, ForwardIterator last);
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// TODO: switch to the shared implementation once it's merged into main
+template <class Callable>
+void runway_sample(size_t size, Callable callable) {
+  constexpr size_t affix = 16;
+  // 0, 1, 2, ..., 15, 16, 50, 157, 493, 1548, ...
+  for (size_t i = 0; i < size; i = i < affix ? i + 1 : size_t(3.1415 * i)) {
+    callable(i);
+  }
+  if (size <= affix)
+    return;
+  // size - 16, size - 15, ..., size - 1
+  for (size_t i = size - affix; i < size; ++i) {
+    callable(i);
+  }
+}
+
+// The type X is provided to test that the adjacent_find algorithm can be used with custom non-movable/non-copyable types.
+struct X {
+  X() = delete;
+  explicit X(int i) : i_(i) {}
+  X(const X&)            = delete;
+  X(X&&)                 = delete;
+  X& operator=(const X&) = delete;
+  X& operator=(X&&)      = delete;
+  bool operator==(const X& other) const { return i_ == other.i_; }
+
+private:
+  int i_;
+};
+
+template <class Iter>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      int a[]  = {42};
+      auto res = std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a)));
+      static_assert(std::is_same_v<decltype(res), Iter>);
+    }
+    {
+      int a[] = {42};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a))) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {42, 42};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a) + 1)) == Iter(std::begin(a) + 1));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 1), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 0, 0};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+    }
+    {
+      int a[] = {0, 1, 0};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 0, 0};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+    }
+    {
+      int a[] = {0, 1, 0, 1};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 1, 1};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+    }
+    {
+      int a[] = {0, 1, 2, 2, 0, 1, 2, 3};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 2), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a))) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 3), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 2, 7, 0, 1, 2, 3};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 2));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+    }
+    {
+      int a[1073];
+      std::iota(std::begin(a), std::end(a), 0);
+      runway_sample(std::size(a), [&](std::size_t i) {
+        if (i == 0)
+          return; // skip the first element to avoid out-of-bounds access
+        a[i] = a[i - 1];
+        assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + i - 1));
+        a[i] = i;
+      });
+    }
+  }
+};
+
+template <class Iter>
+struct TestX {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    X a[] = {X(0), X(1), X(1), X(2)};
+    assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+    assert(std::adjacent_find(policy, Iter(std::begin(a) + 1), Iter(std::end(a))) == Iter(std::begin(a) + 1));
+    assert(std::adjacent_find(policy, Iter(std::begin(a) + 2), Iter(std::end(a))) == Iter(std::end(a)));
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+  types::for_each(types::forward_iterator_list<const X*>{}, TestIteratorWithPolicies<TestX>{});
+  return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find_pred.pass.cpp
new file mode 100644
index 0000000000000..795632b0db4db
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/pstl.adjacent_find_pred.pass.cpp
@@ -0,0 +1,173 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++17
+
+// UNSUPPORTED: libcpp-has-no-incomplete-pstl
+
+// template<class ExecutionPolicy, class ForwardIterator, class BinaryPredicate>
+// ForwardIterator adjacent_find(ExecutionPolicy&& exec,
+//                               ForwardIterator first, ForwardIterator last,
+//                               BinaryPredicate pred);
+
+#include <algorithm>
+#include <cassert>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// TODO: switch to the shared implementation once it's merged into main
+template <class Callable>
+void runway_sample(size_t size, Callable callable) {
+  constexpr size_t affix = 16;
+  // 0, 1, 2, ..., 15, 16, 50, 157, 493, 1548, ...
+  for (size_t i = 0; i < size; i = i < affix ? i + 1 : size_t(3.1415 * i)) {
+    callable(i);
+  }
+  if (size <= affix)
+    return;
+  // size - 16, size - 15, ..., size - 1
+  for (size_t i = size - affix; i < size; ++i) {
+    callable(i);
+  }
+}
+
+// The type X is provided to test that the adjacent_find algorithm can be used with custom non-movable/non-copyable types.
+struct X {
+  X() = delete;
+  explicit X(int i) : i_(i) {}
+  X(const X&)            = delete;
+  X(X&&)                 = delete;
+  X& operator=(const X&) = delete;
+  X& operator=(X&&)      = delete;
+  int get_value() const { return i_; }
+
+private:
+  int i_;
+};
+
+struct Pred {
+  bool operator()(const X& a, const X& b) const {
+    return static_cast<long long>(b.get_value()) - static_cast<long long>(a.get_value()) == 42;
+  }
+  bool operator()(int a, int b) const { return static_cast<long long>(b) - static_cast<long long>(a) == 42; }
+};
+
+template <class Iter>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      int a[]  = {42};
+      auto res = std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a)), Pred{});
+      static_assert(std::is_same_v<decltype(res), Iter>);
+    }
+    {
+      int a[] = {42};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a)), Pred{}) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {42, 84};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a) + 1), Pred{}) ==
+             Iter(std::begin(a) + 1));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 1), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 42, 84};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a)));
+    }
+    {
+      int a[] = {0, 41, 0};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 0, 42};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 2));
+    }
+    {
+      int a[] = {0, 41, 0, 41};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 43, 85};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 1));
+    }
+    {
+      int a[] = {0, 1, 2, 44, 0, 1, 2, 3};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 2));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 2), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 2));
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::begin(a)), Pred{}) == Iter(std::begin(a)));
+      assert(std::adjacent_find(policy, Iter(std::begin(a) + 3), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {0, 1, 2, 45, 0, 1, 2, 3};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::min() + 42,
+                 std::numeric_limits<int>::max() - 42,
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max() - 42,
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 2));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+    }
+    {
+      int a[] = {std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::min(),
+                 std::numeric_limits<int>::min() + 42,
+                 std::numeric_limits<int>::max()};
+      assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 1));
+    }
+    {
+      int a[1073];
+      std::iota(std::begin(a), std::end(a), 0);
+      runway_sample(std::size(a), [&](std::size_t i) {
+        if (i == 0)
+          return; // skip the first element to avoid out-of-bounds access
+        a[i] = a[i - 1] + 42;
+        assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) ==
+               Iter(std::begin(a) + i - 1));
+        a[i] = i;
+      });
+    }
+  }
+};
+
+template <class Iter>
+struct TestX {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    X a[] = {X(0), X(40), X(82), X(100)};
+    assert(std::adjacent_find(policy, Iter(std::begin(a)), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 1));
+    assert(std::adjacent_find(policy, Iter(std::begin(a) + 1), Iter(std::end(a)), Pred{}) == Iter(std::begin(a) + 1));
+    assert(std::adjacent_find(policy, Iter(std::begin(a) + 2), Iter(std::end(a)), Pred{}) == Iter(std::end(a)));
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::forward_iterator_list<const int*>{}, TestIteratorWithPolicies<Test>{});
+  types::for_each(types::forward_iterator_list<const X*>{}, TestIteratorWithPolicies<TestX>{});
+  return 0;
+}
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index 820a5d92c19e0..c03d27cea5df1 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -273,6 +273,18 @@ int main(int, char**) {
         });
       }
 
+      {
+        auto pred = maybe_throw(tokens[5], [](int a, int b) -> bool { return a == b; });
+
+        // adjacent_find(first, last)
+        assert_non_throwing([=, &policy] { (void)std::adjacent_find(policy, std::move(first1), std::move(last1)); });
+
+        // adjacent_find(first, last, pred)
+        assert_non_throwing([=, &policy] {
+          (void)std::adjacent_find(policy, std::move(first1), std::move(last1), pred);
+        });
+      }
+
       {
         // move(first, last, dest)
         assert_non_throwing([=, &policy] {



More information about the libcxx-commits mailing list