[libcxx-commits] [libcxx] [libc++][pstl] Default implementation of parallel std::find_first_of (PR #206328)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jul 6 22:51:10 PDT 2026


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

>From 80420b031a2664ffaaac079b74864f6f035d0810 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 28 Jun 2026 11:21:56 +0100
Subject: [PATCH 01/12] Added implementation of find_first_of on top of
 __find_if

---
 libcxx/include/__algorithm/pstl.h             | 22 +++++
 libcxx/include/__pstl/backend_fwd.h           |  7 ++
 libcxx/include/__pstl/backends/default.h      | 19 ++++
 .../pstl.find_first_of.pass.cpp               | 87 +++++++++++++++++++
 4 files changed, 135 insertions(+)
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 10625ea3f8e3d..7d5b20ad96c1d 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -679,6 +679,28 @@ is_sorted(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterato
       std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp));
 }
 
+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 _ForwardIterator1 find_first_of(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator1 __first1,
+    _ForwardIterator1 __last1,
+    _ForwardIterator2 __first2,
+    _ForwardIterator2 __last2) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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));
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a52e6db954d0c..cf64e190ad4ed 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -109,6 +109,13 @@ struct __is_partitioned;
 // optional<bool>
 // operator()(_Policy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) const noexcept;
 
+template <class _Backend, class _ExecutionPolicy>
+struct __find_first_of;
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+// optional<_ForwardIterator1>
+// operator()(_Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+//                       _ForwardIterator2 __first2, _ForwardIterator2 __last2) const noexcept;
+
 template <class _Backend, class _ExecutionPolicy>
 struct __for_each;
 // template <class _Policy, class _ForwardIterator, class _Function>
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index be90715af13b5..4fcd9b55e5066 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -12,6 +12,7 @@
 #include <__algorithm/copy_n.h>
 #include <__algorithm/equal.h>
 #include <__algorithm/fill_n.h>
+#include <__algorithm/find.h>
 #include <__algorithm/for_each_n.h>
 #include <__algorithm/is_sorted.h>
 #include <__config>
@@ -57,6 +58,7 @@ namespace __pstl {
 // - all_of
 // - none_of
 // - is_partitioned
+// - find_first_of
 //
 // for_each family
 // ---------------
@@ -181,6 +183,23 @@ struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
   }
 };
 
+template <class _ExecutionPolicy>
+struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+  operator()(_Policy&& __policy,
+             _ForwardIterator1 __first1,
+             _ForwardIterator1 __last1,
+             _ForwardIterator2 __first2,
+             _ForwardIterator2 __last2) const noexcept {
+    using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
+    using _Ref    = __iterator_reference<_ForwardIterator1>;
+    return _FindIf()(__policy, std::move(__first1), std::move(__last1), [&](_Ref __element) {
+      return std::find(__first2, __last2, __element) != __last2;
+    });
+  }
+};
+
 //////////////////////////////////////////////////////////////
 // for_each family
 //////////////////////////////////////////////////////////////
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
new file mode 100644
index 0000000000000..c4093daa71ba7
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//   ForwardIterator1 find_first_of(ExecutionPolicy&& exec,
+//                                  ForwardIterator1 first1,
+//                                  ForwardIterator1 last1,
+//                                  ForwardIterator2 first2,
+//                                  ForwardIterator2 last2);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <limits>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+template <class Iter>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      int a[]     = {0};
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      assert(std::find_first_of(policy, Iter(a), Iter(a), Iter(a), Iter(a)) == Iter(a));
+      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(a), Iter(a)) == Iter(a + sa));
+    }
+    {
+      int ia[]    = {0, 1, 2, 3, 0, 1, 2, 3};
+      unsigned sa = sizeof(ia) / sizeof(ia[0]);
+      int ib[]    = {1, 3, 5, 7};
+      unsigned sb = sizeof(ib) / sizeof(ib[0]);
+      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb)) == Iter(ia + 1));
+      int ic[] = {7};
+      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1)) == Iter(ia + sa));
+      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic)) == Iter(ia + sa));
+      assert(std::find_first_of(Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1)) == Iter(ia));
+    }
+    {
+      int a[8192];
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      std::iota(a, a + sa, 1);
+      a[1023]     = -1;
+      a[2048]     = -1;
+      a[3071]     = -1;
+      int b[]     = {-1, 999999};
+      unsigned sb = sizeof(b) / sizeof(b[0]);
+      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb)) == Iter(a + 1023));
+    }
+    {
+      int a[1073];
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      std::iota(a, a + sa, 0);
+      int b[]     = {1070, 1071, 1072, -1};
+      unsigned sb = sizeof(b) / sizeof(b[0]);
+      for (unsigned i = 0; i < sa; i = i <= 16 ? i + 1 : unsigned(3.1415 * i)) {
+        a[i] = -1;
+        assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb)) == Iter(a + i));
+        a[i] = i;
+      }
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
+                                       types::bidirectional_iterator_list<int*>,
+                                       types::random_access_iterator_list<int*>>{},
+                  TestIteratorWithPolicies<Test>{});
+
+  return 0;
+}

>From c4185be74a100792d2e08987b3991397446a39d1 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 28 Jun 2026 12:08:03 +0100
Subject: [PATCH 02/12] Added a predicate version of find_first_of

---
 libcxx/include/__algorithm/pstl.h             | 28 +++++-
 libcxx/include/__pstl/backend_fwd.h           |  4 +-
 libcxx/include/__pstl/backends/default.h      | 14 +--
 .../pstl.find_first_of_pred.pass.cpp          | 95 +++++++++++++++++++
 4 files changed, 132 insertions(+), 9 deletions(-)
 create mode 100644 libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 7d5b20ad96c1d..84418222def52 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -698,7 +698,33 @@ template <class _ExecutionPolicy,
       std::move(__first1),
       std::move(__last1),
       std::move(__first2),
-      std::move(__last2));
+      std::move(__last2),
+      std::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 _ForwardIterator1 find_first_of(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator1 __first1,
+    _ForwardIterator1 __last1,
+    _ForwardIterator2 __first2,
+    _ForwardIterator2 __last2,
+    _BinaryPredicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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));
 }
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index cf64e190ad4ed..1ea121367fbc7 100644
--- a/libcxx/include/__pstl/backend_fwd.h
+++ b/libcxx/include/__pstl/backend_fwd.h
@@ -111,10 +111,10 @@ struct __is_partitioned;
 
 template <class _Backend, class _ExecutionPolicy>
 struct __find_first_of;
-// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+// template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
 // optional<_ForwardIterator1>
 // operator()(_Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
-//                       _ForwardIterator2 __first2, _ForwardIterator2 __last2) const noexcept;
+//                       _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Predicate __pred) const noexcept;
 
 template <class _Backend, class _ExecutionPolicy>
 struct __for_each;
diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 4fcd9b55e5066..6306b051f9dc4 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -9,10 +9,10 @@
 #ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 
+#include <__algorithm/any_of.h>
 #include <__algorithm/copy_n.h>
 #include <__algorithm/equal.h>
 #include <__algorithm/fill_n.h>
-#include <__algorithm/find.h>
 #include <__algorithm/for_each_n.h>
 #include <__algorithm/is_sorted.h>
 #include <__config>
@@ -185,17 +185,19 @@ struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
 
 template <class _ExecutionPolicy>
 struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
-  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2>
+  template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
   operator()(_Policy&& __policy,
              _ForwardIterator1 __first1,
              _ForwardIterator1 __last1,
              _ForwardIterator2 __first2,
-             _ForwardIterator2 __last2) const noexcept {
+             _ForwardIterator2 __last2,
+             _Predicate&& __pred) const noexcept {
     using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
-    using _Ref    = __iterator_reference<_ForwardIterator1>;
-    return _FindIf()(__policy, std::move(__first1), std::move(__last1), [&](_Ref __element) {
-      return std::find(__first2, __last2, __element) != __last2;
+    using _Ref1   = __iterator_reference<_ForwardIterator1>;
+    using _Ref2   = __iterator_reference<_ForwardIterator2>;
+    return _FindIf()(__policy, std::move(__first1), std::move(__last1), [&](_Ref1 __element) {
+      return std::any_of(__first2, __last2, [&](_Ref2 __value) { return __pred(__element, __value); });
     });
   }
 };
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
new file mode 100644
index 0000000000000..00cb0f149a399
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//   ForwardIterator1 find_first_of(ExecutionPolicy&& exec,
+//                                  ForwardIterator1 first1,
+//                                  ForwardIterator1 last1,
+//                                  ForwardIterator2 first2,
+//                                  ForwardIterator2 last2,
+//                                  BinaryPredicate p);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <limits>
+#include <numeric>
+
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+
+struct Pred {
+  bool operator()(int l, int r) const {
+    return l + 1 == r; // ensures that the predicate is not equivalent to std::equal_to
+  }
+};
+
+template <class Iter>
+struct Test {
+  template <class ExecutionPolicy>
+  void operator()(ExecutionPolicy&& policy) {
+    {
+      int a[]     = {0};
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      assert(std::find_first_of(policy, Iter(a), Iter(a), Iter(a), Iter(a), Pred{}) == Iter(a));
+      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(a), Iter(a), Pred{}) == Iter(a + sa));
+    }
+    {
+      int ia[]    = {0, 1, 2, 3, 0, 1, 2, 3};
+      unsigned sa = sizeof(ia) / sizeof(ia[0]);
+      int ib[]    = {2, 4, 6, 8};
+      unsigned sb = sizeof(ib) / sizeof(ib[0]);
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb), Pred{}) == Iter(ia + 1));
+      int ic[] = {7};
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1), Pred{}) == Iter(ia + sa));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic), Pred{}) == Iter(ia + sa));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1), Pred{}) == Iter(ia));
+    }
+    {
+      int a[8192];
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      std::iota(a, a + sa, 1);
+      a[1023]     = -2;
+      a[2048]     = -2;
+      a[3071]     = -2;
+      int b[]     = {-1, 999999};
+      unsigned sb = sizeof(b) / sizeof(b[0]);
+      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb), Pred{}) == Iter(a + 1023));
+    }
+    {
+      int a[1073];
+      unsigned sa = sizeof(a) / sizeof(a[0]);
+      std::iota(a, a + sa, 0);
+      int b[]     = {1070, 1071, 1072, -1};
+      unsigned sb = sizeof(b) / sizeof(b[0]);
+      for (unsigned i = 0; i < sa; i = i <= 16 ? i + 1 : unsigned(3.1415 * i)) {
+        a[i] = -2;
+        assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb), Pred{}) == Iter(a + i));
+        a[i] = i;
+      }
+    }
+  }
+};
+
+int main(int, char**) {
+  types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
+                                       types::bidirectional_iterator_list<int*>,
+                                       types::random_access_iterator_list<int*>>{},
+                  TestIteratorWithPolicies<Test>{});
+
+  return 0;
+}

>From 92e67cdebae5293ae478ecc9d385585e1f9b8d55 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 28 Jun 2026 12:30:10 +0100
Subject: [PATCH 03/12] Added verification for iterator types, nodiscard and
 noexcept

---
 .../pstl.iterator-requirements.verify.cpp         |  7 +++++++
 .../libcxx/algorithms/pstl.nodiscard.verify.cpp   |  4 ++++
 .../algorithms/pstl.exception_handling.pass.cpp   | 15 +++++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index e5bd7e764c59b..1abaf5cc7b193 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -89,6 +89,13 @@ void f(non_forward_iterator non_fwd, non_output_iterator non_output, std::execut
     (void)std::find_if_not(pol, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: find_if_not}}
   }
 
+  {
+    (void)std::find_first_of(
+        pol, non_fwd, non_fwd, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: find_first_of}}
+    (void)std::find_first_of(
+        pol, non_fwd, non_fwd, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: find_first_of}}
+  }
+
   {
     (void)std::for_each(pol, non_fwd, non_fwd, func); // expected-error@*:* {{static assertion failed: for_each}}
     (void)std::for_each_n(pol, non_fwd, n, func);     // expected-error@*:* {{static assertion failed: for_each_n}}
diff --git a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
index b6554cef6f32a..747d62bc66837 100644
--- a/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
@@ -47,6 +47,10 @@ void test() {
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::find(std::execution::par, std::begin(a), std::end(a), 1);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::find_first_of(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::find_first_of(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::is_partitioned(std::execution::par, std::begin(a), std::end(a), pred);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::is_sorted(std::execution::par, std::begin(a), std::end(a));
diff --git a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
index a3db159289393..9e6c8f5b8ce40 100644
--- a/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
+++ b/libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
@@ -175,6 +175,21 @@ int main(int, char**) {
         });
       }
 
+      {
+        auto pred = maybe_throw(tokens[5], [](int x, int y) -> bool { return x == y; });
+
+        // find_first_of(first1, last1, first2, last2)
+        assert_non_throwing([=, &policy] {
+          (void)std::find_first_of(policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2));
+        });
+
+        // find_first_of(first1, last1, first2, last2, pred)
+        assert_non_throwing([=, &policy] {
+          (void)std::find_first_of(
+              policy, std::move(first1), std::move(last1), std::move(first2), std::move(last2), pred);
+        });
+      }
+
       {
         auto func = maybe_throw(tokens[5], [](int) {});
 

>From 65aa1ad5d9dd25a930e0cca5ba0c1d59fb3e8aa4 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Sun, 28 Jun 2026 13:09:11 +0100
Subject: [PATCH 04/12] Added a missing policy in the unit test

---
 .../alg.find.first.of/pstl.find_first_of.pass.cpp         | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
index c4093daa71ba7..5768a8cf1f3c0 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -45,11 +45,11 @@ struct Test {
       unsigned sa = sizeof(ia) / sizeof(ia[0]);
       int ib[]    = {1, 3, 5, 7};
       unsigned sb = sizeof(ib) / sizeof(ib[0]);
-      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb)) == Iter(ia + 1));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb)) == Iter(ia + 1));
       int ic[] = {7};
-      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1)) == Iter(ia + sa));
-      assert(std::find_first_of(Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic)) == Iter(ia + sa));
-      assert(std::find_first_of(Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1)) == Iter(ia));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1)) == Iter(ia + sa));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic)) == Iter(ia + sa));
+      assert(std::find_first_of(policy, Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1)) == Iter(ia));
     }
     {
       int a[8192];

>From 18881aea45556d321505c64ef3ebcbab78c331ec Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 30 Jun 2026 22:10:58 +0100
Subject: [PATCH 05/12] Addressed the feedback

---
 libcxx/include/__algorithm/pstl.h             | 96 +++++++++----------
 .../pstl.iterator-requirements.verify.cpp     |  8 +-
 .../pstl.find_first_of.pass.cpp               | 89 ++++++++++-------
 .../pstl.find_first_of_pred.pass.cpp          | 89 ++++++++++-------
 4 files changed, 168 insertions(+), 114 deletions(-)

diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 84418222def52..3530b3207f59e 100644
--- a/libcxx/include/__algorithm/pstl.h
+++ b/libcxx/include/__algorithm/pstl.h
@@ -293,6 +293,54 @@ find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __l
       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 _ForwardIterator1 find_first_of(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator1 __first1,
+    _ForwardIterator1 __last1,
+    _ForwardIterator2 __first2,
+    _ForwardIterator2 __last2) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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::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 _ForwardIterator1 find_first_of(
+    _ExecutionPolicy&& __policy,
+    _ForwardIterator1 __first1,
+    _ForwardIterator1 __last1,
+    _ForwardIterator2 __first2,
+    _ForwardIterator2 __last2,
+    _BinaryPredicate __pred) {
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
+  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
+  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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 _ForwardIterator,
           class _Function,
@@ -679,54 +727,6 @@ is_sorted(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterato
       std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), std::move(__comp));
 }
 
-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 _ForwardIterator1 find_first_of(
-    _ExecutionPolicy&& __policy,
-    _ForwardIterator1 __first1,
-    _ForwardIterator1 __last1,
-    _ForwardIterator2 __first2,
-    _ForwardIterator2 __last2) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
-  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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::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 _ForwardIterator1 find_first_of(
-    _ExecutionPolicy&& __policy,
-    _ForwardIterator1 __first1,
-    _ForwardIterator1 __last1,
-    _ForwardIterator2 __first2,
-    _ForwardIterator2 __last2,
-    _BinaryPredicate __pred) {
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "find_first_of requires ForwardIterators");
-  _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "find_first_of requires ForwardIterators");
-  using _Implementation = __pstl::__dispatch<__pstl::__find_first_of, __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));
-}
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_HAS_EXPERIMENTAL_PSTL && _LIBCPP_STD_VER >= 17
diff --git a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
index 1abaf5cc7b193..aee3f97019071 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -91,9 +91,13 @@ void f(non_forward_iterator non_fwd, non_output_iterator non_output, std::execut
 
   {
     (void)std::find_first_of(
-        pol, non_fwd, non_fwd, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: find_first_of}}
+        pol, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: find_first_of}}
     (void)std::find_first_of(
-        pol, non_fwd, non_fwd, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: find_first_of}}
+        pol, it, it, non_fwd, non_fwd, pred); // expected-error@*:* {{static assertion failed: find_first_of}}
+    (void)std::find_first_of(
+        pol, non_fwd, non_fwd, it, it); // expected-error@*:* {{static assertion failed: find_first_of}}
+    (void)std::find_first_of(
+        pol, non_fwd, non_fwd, it, it, pred); // expected-error@*:* {{static assertion failed: find_first_of}}
   }
 
   {
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
index 5768a8cf1f3c0..ea2fdc6eebdef 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -30,58 +30,83 @@
 #include "test_macros.h"
 #include "type_algorithms.h"
 
-template <class Iter>
+EXECUTION_POLICY_SFINAE_TEST(find_first_of);
+
+static_assert(sfinae_test_find_first_of<int, int*, int*, int*, int*>);
+static_assert(!sfinae_test_find_first_of<std::execution::parallel_policy, int*, int*, int*, int*>);
+
+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) {
+    using std::begin;
+    using std::end;
     {
-      int a[]     = {0};
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      assert(std::find_first_of(policy, Iter(a), Iter(a), Iter(a), Iter(a)) == Iter(a));
-      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(a), Iter(a)) == Iter(a + sa));
+      int a[] = {0};
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(begin(a)), Iter2(begin(a)), Iter2(begin(a))) ==
+             Iter1(begin(a)));
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(a)), Iter2(begin(a))) ==
+             Iter1(end(a)));
     }
     {
-      int ia[]    = {0, 1, 2, 3, 0, 1, 2, 3};
-      unsigned sa = sizeof(ia) / sizeof(ia[0]);
-      int ib[]    = {1, 3, 5, 7};
-      unsigned sb = sizeof(ib) / sizeof(ib[0]);
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb)) == Iter(ia + 1));
+      int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
+      int ib[] = {1, 3, 5, 7};
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ib)), Iter2(end(ib))) ==
+             Iter1(begin(ia) + 1));
       int ic[] = {7};
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1)) == Iter(ia + sa));
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic)) == Iter(ia + sa));
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1)) == Iter(ia));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(end(ic))) ==
+             Iter1(end(ia)));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(begin(ic))) ==
+             Iter1(end(ia)));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(begin(ia)), Iter2(begin(ic)), Iter2(end(ic))) ==
+             Iter1(begin(ia)));
     }
     {
       int a[8192];
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      std::iota(a, a + sa, 1);
-      a[1023]     = -1;
-      a[2048]     = -1;
-      a[3071]     = -1;
-      int b[]     = {-1, 999999};
-      unsigned sb = sizeof(b) / sizeof(b[0]);
-      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb)) == Iter(a + 1023));
+      std::iota(begin(a), end(a), 1);
+      a[1023] = -1;
+      a[2048] = -1;
+      a[3071] = -1;
+      int b[] = {-1, 999999};
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b))) ==
+             Iter1(begin(a) + 1023));
     }
     {
       int a[1073];
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      std::iota(a, a + sa, 0);
-      int b[]     = {1070, 1071, 1072, -1};
-      unsigned sb = sizeof(b) / sizeof(b[0]);
-      for (unsigned i = 0; i < sa; i = i <= 16 ? i + 1 : unsigned(3.1415 * i)) {
+      std::iota(begin(a), end(a), 0);
+      int b[] = {1073, 1074, 1075, -1};
+      runway_sample(std::size(a), [&](size_t i) {
         a[i] = -1;
-        assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb)) == Iter(a + i));
+        assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b))) ==
+               Iter1(begin(a) + i));
         a[i] = i;
-      }
+      });
     }
   }
 };
 
 int main(int, char**) {
-  types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
-                                       types::bidirectional_iterator_list<int*>,
-                                       types::random_access_iterator_list<int*>>{},
-                  TestIteratorWithPolicies<Test>{});
+  types::for_each(types::forward_iterator_list<int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<int*>{},
+                        TestIteratorWithPolicies< types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
 
   return 0;
 }
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
index 00cb0f149a399..770d0109c4f4a 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
@@ -32,64 +32,89 @@
 #include "test_macros.h"
 #include "type_algorithms.h"
 
+EXECUTION_POLICY_SFINAE_TEST(find_first_of);
+
+static_assert(sfinae_test_find_first_of<int, int*, int*, int*, int*, bool (*)(int, int)>);
+static_assert(!sfinae_test_find_first_of<std::execution::parallel_policy, int*, int*, int*, int*, bool (*)(int, int)>);
+
 struct Pred {
   bool operator()(int l, int r) const {
     return l + 1 == r; // ensures that the predicate is not equivalent to std::equal_to
   }
 };
 
-template <class Iter>
+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) {
+    using std::begin;
+    using std::end;
     {
-      int a[]     = {0};
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      assert(std::find_first_of(policy, Iter(a), Iter(a), Iter(a), Iter(a), Pred{}) == Iter(a));
-      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(a), Iter(a), Pred{}) == Iter(a + sa));
+      int a[] = {0};
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(begin(a)), Iter2(begin(a)), Iter2(begin(a)), Pred{}) ==
+             Iter1(begin(a)));
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(a)), Iter2(begin(a)), Pred{}) ==
+             Iter1(end(a)));
     }
     {
-      int ia[]    = {0, 1, 2, 3, 0, 1, 2, 3};
-      unsigned sa = sizeof(ia) / sizeof(ia[0]);
-      int ib[]    = {2, 4, 6, 8};
-      unsigned sb = sizeof(ib) / sizeof(ib[0]);
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ib), Iter(ib + sb), Pred{}) == Iter(ia + 1));
+      int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
+      int ib[] = {2, 4, 6, 8};
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ib)), Iter2(end(ib)), Pred{}) ==
+             Iter1(begin(ia) + 1));
       int ic[] = {7};
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic + 1), Pred{}) == Iter(ia + sa));
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia + sa), Iter(ic), Iter(ic), Pred{}) == Iter(ia + sa));
-      assert(std::find_first_of(policy, Iter(ia), Iter(ia), Iter(ic), Iter(ic + 1), Pred{}) == Iter(ia));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(end(ic)), Pred{}) ==
+             Iter1(end(ia)));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(begin(ic)), Pred{}) ==
+             Iter1(end(ia)));
+      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(begin(ia)), Iter2(begin(ic)), Iter2(end(ic)), Pred{}) ==
+             Iter1(begin(ia)));
     }
     {
       int a[8192];
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      std::iota(a, a + sa, 1);
-      a[1023]     = -2;
-      a[2048]     = -2;
-      a[3071]     = -2;
-      int b[]     = {-1, 999999};
-      unsigned sb = sizeof(b) / sizeof(b[0]);
-      assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb), Pred{}) == Iter(a + 1023));
+      std::iota(begin(a), end(a), 1);
+      a[1023] = -2;
+      a[2048] = -2;
+      a[3071] = -2;
+      int b[] = {-1, 999999};
+      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b)), Pred{}) ==
+             Iter1(begin(a) + 1023));
     }
     {
       int a[1073];
-      unsigned sa = sizeof(a) / sizeof(a[0]);
-      std::iota(a, a + sa, 0);
-      int b[]     = {1070, 1071, 1072, -1};
-      unsigned sb = sizeof(b) / sizeof(b[0]);
-      for (unsigned i = 0; i < sa; i = i <= 16 ? i + 1 : unsigned(3.1415 * i)) {
+      std::iota(begin(a), end(a), 0);
+      int b[] = {1074, 1075, 1076, -1};
+      runway_sample(std::size(a), [&](size_t i) {
         a[i] = -2;
-        assert(std::find_first_of(policy, Iter(a), Iter(a + sa), Iter(b), Iter(b + sb), Pred{}) == Iter(a + i));
+        assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b)), Pred{}) ==
+               Iter1(begin(a) + i));
         a[i] = i;
-      }
+      });
     }
   }
 };
 
 int main(int, char**) {
-  types::for_each(types::concatenate_t<types::forward_iterator_list<int*>,
-                                       types::bidirectional_iterator_list<int*>,
-                                       types::random_access_iterator_list<int*>>{},
-                  TestIteratorWithPolicies<Test>{});
+  types::for_each(types::forward_iterator_list<int*>{}, types::apply_type_identity{[](auto v) {
+                    using Iter = typename decltype(v)::type;
+                    types::for_each(
+                        types::forward_iterator_list<int*>{},
+                        TestIteratorWithPolicies< types::partial_instantiation<Test, Iter>::template apply>{});
+                  }});
 
   return 0;
 }

>From fa3700e14b9c5f311df716d57f018a94a3438b2e Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Tue, 30 Jun 2026 22:42:34 +0100
Subject: [PATCH 06/12] Missing include

---
 .../alg.find.first.of/pstl.find_first_of.pass.cpp                | 1 +
 .../alg.find.first.of/pstl.find_first_of_pred.pass.cpp           | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
index ea2fdc6eebdef..0ad0bbfdd700a 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -22,6 +22,7 @@
 #include <algorithm>
 #include <cassert>
 #include <functional>
+#include <iterator>
 #include <limits>
 #include <numeric>
 
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
index 770d0109c4f4a..5532ed2f8e075 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
@@ -24,6 +24,7 @@
 #include <algorithm>
 #include <cassert>
 #include <functional>
+#include <iterator>
 #include <limits>
 #include <numeric>
 

>From 8dd415ea0a27cb125486a9b32f4350d5b45c18f1 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 1 Jul 2026 21:21:11 +0100
Subject: [PATCH 07/12] Branch off to std::find() if the predicate is equality,
 call into more general std::find_if() otherwise.

---
 libcxx/include/__pstl/backends/default.h      | 12 +++-
 .../pstl.find_first_of.pass.cpp               | 48 ++++++++-------
 .../pstl.find_first_of_pred.pass.cpp          | 61 ++++++++++++-------
 3 files changed, 77 insertions(+), 44 deletions(-)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 6306b051f9dc4..a5cd1d1b09912 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -9,10 +9,11 @@
 #ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H
 
-#include <__algorithm/any_of.h>
 #include <__algorithm/copy_n.h>
 #include <__algorithm/equal.h>
 #include <__algorithm/fill_n.h>
+#include <__algorithm/find.h>
+#include <__algorithm/find_if.h>
 #include <__algorithm/for_each_n.h>
 #include <__algorithm/is_sorted.h>
 #include <__config>
@@ -24,6 +25,8 @@
 #include <__iterator/next.h>
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
+#include <__type_traits/desugars_to.h>
+#include <__type_traits/remove_cvref.h>
 #include <__utility/empty.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
@@ -197,7 +200,12 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
     using _Ref1   = __iterator_reference<_ForwardIterator1>;
     using _Ref2   = __iterator_reference<_ForwardIterator2>;
     return _FindIf()(__policy, std::move(__first1), std::move(__last1), [&](_Ref1 __element) {
-      return std::any_of(__first2, __last2, [&](_Ref2 __value) { return __pred(__element, __value); });
+      if constexpr (__desugars_to_v<__equal_tag, _Predicate, __remove_cvref_t<_Ref1>, __remove_cvref_t<_Ref2>>) {
+        // bypass an equality predicate and call directly to std::find() to allow more vectorization
+        return std::find(__first2, __last2, __element) != __last2;
+      } else {
+        return std::find_if(__first2, __last2, [&](_Ref2 __value) { return __pred(__element, __value); }) != __last2;
+      }
     });
   }
 };
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
index 0ad0bbfdd700a..118b34da0cb6c 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -37,7 +37,7 @@ static_assert(sfinae_test_find_first_of<int, int*, int*, int*, int*>);
 static_assert(!sfinae_test_find_first_of<std::execution::parallel_policy, int*, int*, int*, int*>);
 
 template <class Callable>
-void runway_sample(size_t size, Callable&& 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)) {
@@ -55,46 +55,52 @@ template <class Iter1, class Iter2>
 struct Test {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
-    using std::begin;
-    using std::end;
     {
       int a[] = {0};
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(begin(a)), Iter2(begin(a)), Iter2(begin(a))) ==
-             Iter1(begin(a)));
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(a)), Iter2(begin(a))) ==
-             Iter1(end(a)));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(a)), Iter1(std::begin(a)), Iter2(std::begin(a)), Iter2(std::begin(a))) ==
+             Iter1(std::begin(a)));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(a)), Iter2(std::begin(a))) ==
+             Iter1(std::end(a)));
     }
     {
       int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
       int ib[] = {1, 3, 5, 7};
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ib)), Iter2(end(ib))) ==
-             Iter1(begin(ia) + 1));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(ia)), Iter1(std::end(ia)), Iter2(std::begin(ib)), Iter2(std::end(ib))) ==
+             Iter1(std::begin(ia) + 1));
       int ic[] = {7};
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(end(ic))) ==
-             Iter1(end(ia)));
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(begin(ic))) ==
-             Iter1(end(ia)));
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(begin(ia)), Iter2(begin(ic)), Iter2(end(ic))) ==
-             Iter1(begin(ia)));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(ia)), Iter1(std::end(ia)), Iter2(std::begin(ic)), Iter2(std::end(ic))) ==
+             Iter1(std::end(ia)));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(ia)), Iter1(std::end(ia)), Iter2(std::begin(ic)), Iter2(std::begin(ic))) ==
+             Iter1(std::end(ia)));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(ia)), Iter1(std::begin(ia)), Iter2(std::begin(ic)), Iter2(std::end(ic))) ==
+             Iter1(std::begin(ia)));
     }
     {
       int a[8192];
-      std::iota(begin(a), end(a), 1);
+      std::iota(std::begin(a), std::end(a), 1);
       a[1023] = -1;
       a[2048] = -1;
       a[3071] = -1;
       int b[] = {-1, 999999};
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b))) ==
-             Iter1(begin(a) + 1023));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b))) ==
+             Iter1(std::begin(a) + 1023));
     }
     {
       int a[1073];
-      std::iota(begin(a), end(a), 0);
+      std::iota(std::begin(a), std::end(a), 0);
       int b[] = {1073, 1074, 1075, -1};
       runway_sample(std::size(a), [&](size_t i) {
         a[i] = -1;
-        assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b))) ==
-               Iter1(begin(a) + i));
+        assert(std::find_first_of(
+                   policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b))) ==
+               Iter1(std::begin(a) + i));
         a[i] = i;
       });
     }
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
index 5532ed2f8e075..1033b52e4621f 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
@@ -45,7 +45,7 @@ struct Pred {
 };
 
 template <class Callable>
-void runway_sample(size_t size, Callable&& 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)) {
@@ -63,46 +63,65 @@ template <class Iter1, class Iter2>
 struct Test {
   template <class ExecutionPolicy>
   void operator()(ExecutionPolicy&& policy) {
-    using std::begin;
-    using std::end;
     {
       int a[] = {0};
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(begin(a)), Iter2(begin(a)), Iter2(begin(a)), Pred{}) ==
-             Iter1(begin(a)));
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(a)), Iter2(begin(a)), Pred{}) ==
-             Iter1(end(a)));
+      assert(
+          std::find_first_of(
+              policy, Iter1(std::begin(a)), Iter1(std::begin(a)), Iter2(std::begin(a)), Iter2(std::begin(a)), Pred{}) ==
+          Iter1(std::begin(a)));
+      assert(
+          std::find_first_of(
+              policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(a)), Iter2(std::begin(a)), Pred{}) ==
+          Iter1(std::end(a)));
     }
     {
       int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
       int ib[] = {2, 4, 6, 8};
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ib)), Iter2(end(ib)), Pred{}) ==
-             Iter1(begin(ia) + 1));
+      assert(
+          std::find_first_of(
+              policy, Iter1(std::begin(ia)), Iter1(std::end(ia)), Iter2(std::begin(ib)), Iter2(std::end(ib)), Pred{}) ==
+          Iter1(std::begin(ia) + 1));
       int ic[] = {7};
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(end(ic)), Pred{}) ==
-             Iter1(end(ia)));
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(end(ia)), Iter2(begin(ic)), Iter2(begin(ic)), Pred{}) ==
-             Iter1(end(ia)));
-      assert(std::find_first_of(policy, Iter1(begin(ia)), Iter1(begin(ia)), Iter2(begin(ic)), Iter2(end(ic)), Pred{}) ==
-             Iter1(begin(ia)));
+      assert(
+          std::find_first_of(
+              policy, Iter1(std::begin(ia)), Iter1(std::end(ia)), Iter2(std::begin(ic)), Iter2(std::end(ic)), Pred{}) ==
+          Iter1(std::end(ia)));
+      assert(std::find_first_of(
+                 policy,
+                 Iter1(std::begin(ia)),
+                 Iter1(std::end(ia)),
+                 Iter2(std::begin(ic)),
+                 Iter2(std::begin(ic)),
+                 Pred{}) == Iter1(std::end(ia)));
+      assert(std::find_first_of(
+                 policy,
+                 Iter1(std::begin(ia)),
+                 Iter1(std::begin(ia)),
+                 Iter2(std::begin(ic)),
+                 Iter2(std::end(ic)),
+                 Pred{}) == Iter1(std::begin(ia)));
     }
     {
       int a[8192];
-      std::iota(begin(a), end(a), 1);
+      std::iota(std::begin(a), std::end(a), 1);
       a[1023] = -2;
       a[2048] = -2;
       a[3071] = -2;
       int b[] = {-1, 999999};
-      assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b)), Pred{}) ==
-             Iter1(begin(a) + 1023));
+      assert(std::find_first_of(
+                 policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), Pred{}) ==
+             Iter1(std::begin(a) + 1023));
     }
     {
       int a[1073];
-      std::iota(begin(a), end(a), 0);
+      std::iota(std::begin(a), std::end(a), 0);
       int b[] = {1074, 1075, 1076, -1};
       runway_sample(std::size(a), [&](size_t i) {
         a[i] = -2;
-        assert(std::find_first_of(policy, Iter1(begin(a)), Iter1(end(a)), Iter2(begin(b)), Iter2(end(b)), Pred{}) ==
-               Iter1(begin(a) + i));
+        assert(
+            std::find_first_of(
+                policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), Pred{}) ==
+            Iter1(std::begin(a) + i));
         a[i] = i;
       });
     }

>From f850d3d6b613a8ed59102a4fb3add7863766412f Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 1 Jul 2026 22:55:54 +0100
Subject: [PATCH 08/12] <numeric> pulls in more headers via
 <__algorithm/find.h>

---
 libcxx/test/libcxx/transitive_includes/cxx23.csv | 3 +++
 libcxx/test/libcxx/transitive_includes/cxx26.csv | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 8385b37c07822..53ae6c9b4e591 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -704,11 +704,14 @@ mutex typeinfo
 mutex version
 new version
 numbers version
+numeric cctype
 numeric climits
 numeric compare
 numeric cstdint
 numeric cstring
 numeric ctime
+numeric cwchar
+numeric cwctype
 numeric initializer_list
 numeric limits
 numeric optional
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index cf1154a251f23..849c9b0ce932b 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -664,11 +664,14 @@ mutex tuple
 mutex version
 new version
 numbers version
+numeric cctype
 numeric climits
 numeric compare
 numeric cstdint
 numeric cstring
 numeric ctime
+numeric cwchar
+numeric cwctype
 numeric initializer_list
 numeric limits
 numeric optional

>From 645820c13db62c99a27d253902acd441488156e0 Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 1 Jul 2026 23:09:04 +0100
Subject: [PATCH 09/12] Expanded tests cases of the serial versions a bit,
 supporting down to C++03

---
 .../alg.find.first.of/find_first_of.pass.cpp  |  60 ++++++----
 .../find_first_of_pred.pass.cpp               | 104 +++++++++++-------
 2 files changed, 105 insertions(+), 59 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
index efa54bbc8fd66..4740029d4c22b 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
@@ -16,18 +16,19 @@
 #include <algorithm>
 #include <cassert>
 #include <iterator>
+#include <numeric>
 
 #include "test_macros.h"
 #include "test_iterators.h"
 
 #if TEST_STD_VER > 17
 TEST_CONSTEXPR bool test_constexpr() {
-    int ia[] = {1, 2, 3};
-    int ib[] = {7, 8, 9};
-    int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
+  int ia[] = {1, 2, 3};
+  int ib[] = {7, 8, 9};
+  int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
     typedef forward_iterator<int*>       FI;
-    typedef bidirectional_iterator<int*> BI;
-    typedef random_access_iterator<int*> RI;
+  typedef bidirectional_iterator<int*> BI;
+  typedef random_access_iterator<int*> RI;
 
     return    (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia))) == FI(ic+1))
            && (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib))) == FI(std::end(ic)))
@@ -36,39 +37,56 @@ TEST_CONSTEXPR bool test_constexpr() {
            && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia))) == RI(ic+1))
            && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib))) == RI(std::end(ic)))
            ;
-    }
+}
 #endif
 
-int main(int, char**)
-{
-    int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
-    const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-    int ib[] = {1, 3, 5, 7};
-    const unsigned sb = sizeof(ib)/sizeof(ib[0]);
+int main(int, char**) {
+  {
+    int ia[]          = {0, 1, 2, 3, 0, 1, 2, 3};
+    const unsigned sa = sizeof(ia) / sizeof(ia[0]);
+    int ib[]          = {1, 3, 5, 7};
+    const unsigned sb = sizeof(ib) / sizeof(ib[0]);
     assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
                               cpp17_input_iterator<const int*>(ia + sa),
                               forward_iterator<const int*>(ib),
-                              forward_iterator<const int*>(ib + sb)) ==
-                              cpp17_input_iterator<const int*>(ia+1));
+                              forward_iterator<const int*>(ib + sb)) == cpp17_input_iterator<const int*>(ia + 1));
     int ic[] = {7};
     assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
                               cpp17_input_iterator<const int*>(ia + sa),
                               forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic + 1)) ==
-                              cpp17_input_iterator<const int*>(ia+sa));
+                              forward_iterator<const int*>(ic + 1)) == cpp17_input_iterator<const int*>(ia + sa));
     assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
                               cpp17_input_iterator<const int*>(ia + sa),
                               forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic)) ==
-                              cpp17_input_iterator<const int*>(ia+sa));
+                              forward_iterator<const int*>(ic)) == cpp17_input_iterator<const int*>(ia + sa));
     assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
                               cpp17_input_iterator<const int*>(ia),
                               forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic+1)) ==
-                              cpp17_input_iterator<const int*>(ia));
+                              forward_iterator<const int*>(ic + 1)) == cpp17_input_iterator<const int*>(ia));
+  }
+  {
+    int a[8192];
+    std::iota(std::begin(a), std::end(a), 1);
+    a[1023] = -1;
+    a[2048] = -1;
+    a[3071] = -1;
+    int b[] = {-1, 999999};
+    assert(std::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b)) == std::begin(a) + 1023);
+  }
+  {
+    int a[1073];
+    const unsigned sa = sizeof(a) / sizeof(a[0]);
+    std::iota(std::begin(a), std::end(a), 0);
+    int b[] = {1073, 1074, 1075, -1};
+    for (unsigned i = 0; i < sa; i = i < 16 ? i + 1 : unsigned(3.1415 * i)) {
+      a[i] = -1;
+      assert(std::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b)) == std::begin(a) + i);
+      a[i] = i;
+    }
+  }
 
 #if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+  static_assert(test_constexpr());
 #endif
 
   return 0;
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
index fd2e4d426fbf9..25699f4b5c216 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
@@ -18,19 +18,26 @@
 #include <cassert>
 #include <functional>
 #include <iterator>
+#include <numeric>
 
 #include "test_macros.h"
 #include "test_iterators.h"
 
+struct Pred {
+  bool operator()(int l, int r) const {
+    return l + 1 == r; // ensures that the predicate is not equivalent to std::equal_to
+  }
+};
+
 #if TEST_STD_VER > 17
 constexpr bool test_constexpr() {
-    int ia[] = {1, 2, 3};
-    int ib[] = {7, 8, 9};
-    int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
+  int ia[] = {1, 2, 3};
+  int ib[] = {7, 8, 9};
+  int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
     typedef forward_iterator<int*>       FI;
-    typedef bidirectional_iterator<int*> BI;
-    typedef random_access_iterator<int*> RI;
-    std::equal_to<int> eq{};
+  typedef bidirectional_iterator<int*> BI;
+  typedef random_access_iterator<int*> RI;
+  std::equal_to<int> eq{};
     return    (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia)), eq) == FI(ic+1))
            && (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib)), eq) == FI(std::end(ic)))
            && (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ia)), BI(std::end(ia)), eq) == BI(ic+1))
@@ -38,43 +45,64 @@ constexpr bool test_constexpr() {
            && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia)), eq) == RI(ic+1))
            && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib)), eq) == RI(std::end(ic)))
            ;
-    }
+}
 #endif
 
-int main(int, char**)
-{
-    int ia[] = {0, 1, 2, 3, 0, 1, 2, 3};
-    const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-    int ib[] = {1, 3, 5, 7};
-    const unsigned sb = sizeof(ib)/sizeof(ib[0]);
-    assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
-                              cpp17_input_iterator<const int*>(ia + sa),
-                              forward_iterator<const int*>(ib),
-                              forward_iterator<const int*>(ib + sb),
-                              std::equal_to<int>()) ==
-                              cpp17_input_iterator<const int*>(ia+1));
+int main(int, char**) {
+  {
+    int ia[]          = {0, 1, 2, 3, 0, 1, 2, 3};
+    const unsigned sa = sizeof(ia) / sizeof(ia[0]);
+    int ib[]          = {1, 3, 5, 7};
+    const unsigned sb = sizeof(ib) / sizeof(ib[0]);
+    assert(std::find_first_of(
+               cpp17_input_iterator<const int*>(ia),
+               cpp17_input_iterator<const int*>(ia + sa),
+               forward_iterator<const int*>(ib),
+               forward_iterator<const int*>(ib + sb),
+               std::equal_to<int>()) == cpp17_input_iterator<const int*>(ia + 1));
     int ic[] = {7};
-    assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
-                              cpp17_input_iterator<const int*>(ia + sa),
-                              forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic + 1),
-                              std::equal_to<int>()) ==
-                              cpp17_input_iterator<const int*>(ia+sa));
-    assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
-                              cpp17_input_iterator<const int*>(ia + sa),
-                              forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic),
-                              std::equal_to<int>()) ==
-                              cpp17_input_iterator<const int*>(ia+sa));
-    assert(std::find_first_of(cpp17_input_iterator<const int*>(ia),
-                              cpp17_input_iterator<const int*>(ia),
-                              forward_iterator<const int*>(ic),
-                              forward_iterator<const int*>(ic+1),
-                              std::equal_to<int>()) ==
-                              cpp17_input_iterator<const int*>(ia));
+    assert(std::find_first_of(
+               cpp17_input_iterator<const int*>(ia),
+               cpp17_input_iterator<const int*>(ia + sa),
+               forward_iterator<const int*>(ic),
+               forward_iterator<const int*>(ic + 1),
+               std::equal_to<int>()) == cpp17_input_iterator<const int*>(ia + sa));
+    assert(std::find_first_of(
+               cpp17_input_iterator<const int*>(ia),
+               cpp17_input_iterator<const int*>(ia + sa),
+               forward_iterator<const int*>(ic),
+               forward_iterator<const int*>(ic),
+               std::equal_to<int>()) == cpp17_input_iterator<const int*>(ia + sa));
+    assert(std::find_first_of(
+               cpp17_input_iterator<const int*>(ia),
+               cpp17_input_iterator<const int*>(ia),
+               forward_iterator<const int*>(ic),
+               forward_iterator<const int*>(ic + 1),
+               std::equal_to<int>()) == cpp17_input_iterator<const int*>(ia));
+  }
+  {
+    int a[8192];
+    std::iota(std::begin(a), std::end(a), 1);
+    a[1023] = -2;
+    a[2048] = -2;
+    a[3071] = -2;
+    int b[] = {-1, 999999};
+    assert(std::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), Pred()) == std::begin(a) + 1023);
+  }
+  {
+    int a[1073];
+    const unsigned sa = sizeof(a) / sizeof(a[0]);
+    std::iota(std::begin(a), std::end(a), 0);
+    int b[] = {1074, 1075, 1076, -1};
+    for (unsigned i = 0; i < sa; i = i < 16 ? i + 1 : unsigned(3.1415 * i)) {
+      a[i] = -2;
+      assert(std::find_first_of(std::begin(a), std::end(a), std::begin(b), std::end(b), Pred()) == std::begin(a) + i);
+      a[i] = i;
+    };
+  }
 
 #if TEST_STD_VER > 17
-    static_assert(test_constexpr());
+  static_assert(test_constexpr());
 #endif
 
   return 0;

>From 12ba4c956bfba72044d2423496800660da679a0f Mon Sep 17 00:00:00 2001
From: Michael Kazakov <mike.kazakov at gmail.com>
Date: Wed, 1 Jul 2026 23:12:37 +0100
Subject: [PATCH 10/12] clang-format the serial tests fully

---
 .../alg.find.first.of/find_first_of.pass.cpp  | 21 ++++++++++++-------
 .../find_first_of_pred.pass.cpp               | 21 ++++++++++++-------
 2 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
index 4740029d4c22b..25a223e274706 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
@@ -26,17 +26,22 @@ TEST_CONSTEXPR bool test_constexpr() {
   int ia[] = {1, 2, 3};
   int ib[] = {7, 8, 9};
   int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
-    typedef forward_iterator<int*>       FI;
+  typedef forward_iterator<int*> FI;
   typedef bidirectional_iterator<int*> BI;
   typedef random_access_iterator<int*> RI;
 
-    return    (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia))) == FI(ic+1))
-           && (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib))) == FI(std::end(ic)))
-           && (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ia)), BI(std::end(ia))) == BI(ic+1))
-           && (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ib)), BI(std::end(ib))) == BI(std::end(ic)))
-           && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia))) == RI(ic+1))
-           && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib))) == RI(std::end(ic)))
-           ;
+  return (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia))) ==
+          FI(ic + 1)) &&
+         (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib))) ==
+          FI(std::end(ic))) &&
+         (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ia)), BI(std::end(ia))) ==
+          BI(ic + 1)) &&
+         (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ib)), BI(std::end(ib))) ==
+          BI(std::end(ic))) &&
+         (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia))) ==
+          RI(ic + 1)) &&
+         (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib))) ==
+          RI(std::end(ic)));
 }
 #endif
 
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
index 25699f4b5c216..9fdc4081b0141 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
@@ -34,17 +34,22 @@ constexpr bool test_constexpr() {
   int ia[] = {1, 2, 3};
   int ib[] = {7, 8, 9};
   int ic[] = {0, 1, 2, 3, 4, 5, 0, 1, 2, 3};
-    typedef forward_iterator<int*>       FI;
+  typedef forward_iterator<int*> FI;
   typedef bidirectional_iterator<int*> BI;
   typedef random_access_iterator<int*> RI;
   std::equal_to<int> eq{};
-    return    (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia)), eq) == FI(ic+1))
-           && (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib)), eq) == FI(std::end(ic)))
-           && (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ia)), BI(std::end(ia)), eq) == BI(ic+1))
-           && (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ib)), BI(std::end(ib)), eq) == BI(std::end(ic)))
-           && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia)), eq) == RI(ic+1))
-           && (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib)), eq) == RI(std::end(ic)))
-           ;
+  return (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ia)), FI(std::end(ia)), eq) ==
+          FI(ic + 1)) &&
+         (std::find_first_of(FI(std::begin(ic)), FI(std::end(ic)), FI(std::begin(ib)), FI(std::end(ib)), eq) ==
+          FI(std::end(ic))) &&
+         (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ia)), BI(std::end(ia)), eq) ==
+          BI(ic + 1)) &&
+         (std::find_first_of(BI(std::begin(ic)), BI(std::end(ic)), BI(std::begin(ib)), BI(std::end(ib)), eq) ==
+          BI(std::end(ic))) &&
+         (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ia)), RI(std::end(ia)), eq) ==
+          RI(ic + 1)) &&
+         (std::find_first_of(RI(std::begin(ic)), RI(std::end(ic)), RI(std::begin(ib)), RI(std::end(ib)), eq) ==
+          RI(std::end(ic)));
 }
 #endif
 

>From 12be042391977e8ba12419b3371e5650d90b2a9e Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 2 Jul 2026 16:15:40 -0400
Subject: [PATCH 11/12] Update libcxx/include/__pstl/backends/default.h

---
 libcxx/include/__pstl/backends/default.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index a5cd1d1b09912..86f3899dc8ab1 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -200,7 +200,7 @@ struct __find_first_of<__default_backend_tag, _ExecutionPolicy> {
     using _Ref1   = __iterator_reference<_ForwardIterator1>;
     using _Ref2   = __iterator_reference<_ForwardIterator2>;
     return _FindIf()(__policy, std::move(__first1), std::move(__last1), [&](_Ref1 __element) {
-      if constexpr (__desugars_to_v<__equal_tag, _Predicate, __remove_cvref_t<_Ref1>, __remove_cvref_t<_Ref2>>) {
+      if constexpr (__desugars_to_v<__equal_tag, _Predicate, _Ref1, _Ref2>) {
         // bypass an equality predicate and call directly to std::find() to allow more vectorization
         return std::find(__first2, __last2, __element) != __last2;
       } else {

>From de6f3e6097065c937b4b2aa6f8efc417e11d6a8d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 2 Jul 2026 16:47:28 -0400
Subject: [PATCH 12/12] Update libcxx/include/__pstl/backends/default.h

---
 libcxx/include/__pstl/backends/default.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxx/include/__pstl/backends/default.h b/libcxx/include/__pstl/backends/default.h
index 86f3899dc8ab1..cb963a130f743 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -26,7 +26,6 @@
 #include <__pstl/backend_fwd.h>
 #include <__pstl/dispatch.h>
 #include <__type_traits/desugars_to.h>
-#include <__type_traits/remove_cvref.h>
 #include <__utility/empty.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>



More information about the libcxx-commits mailing list