[libcxx-commits] [libcxx] 3e7a2ec - [libc++][pstl] Default implementation of parallel std::find_first_of (#206328)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 8 08:19:01 PDT 2026
Author: Michael G. Kazakov
Date: 2026-07-08T11:18:56-04:00
New Revision: 3e7a2ec74cd8f8e0e32037d0192a1378789e9af7
URL: https://github.com/llvm/llvm-project/commit/3e7a2ec74cd8f8e0e32037d0192a1378789e9af7
DIFF: https://github.com/llvm/llvm-project/commit/3e7a2ec74cd8f8e0e32037d0192a1378789e9af7.diff
LOG: [libc++][pstl] Default implementation of parallel std::find_first_of (#206328)
This PR adds a default "one-liner" implementation of parallel
`std::find_first_of` expressed as a call to `__find_if`.
The implementation is based on find_if and any_of.
Part of #99938
Added:
libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
Modified:
libcxx/include/__algorithm/pstl.h
libcxx/include/__pstl/backend_fwd.h
libcxx/include/__pstl/backends/default.h
libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
libcxx/test/libcxx/algorithms/pstl.nodiscard.verify.cpp
libcxx/test/libcxx/transitive_includes/cxx23.csv
libcxx/test/libcxx/transitive_includes/cxx26.csv
libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/find_first_of_pred.pass.cpp
libcxx/test/std/algorithms/pstl.exception_handling.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__algorithm/pstl.h b/libcxx/include/__algorithm/pstl.h
index 10625ea3f8e3d..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,
diff --git a/libcxx/include/__pstl/backend_fwd.h b/libcxx/include/__pstl/backend_fwd.h
index a52e6db954d0c..1ea121367fbc7 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, class _Predicate>
+// optional<_ForwardIterator1>
+// operator()(_Policy&&, _ForwardIterator1 __first1, _ForwardIterator1 __last1,
+// _ForwardIterator2 __first2, _ForwardIterator2 __last2, _Predicate __pred) 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..cb963a130f743 100644
--- a/libcxx/include/__pstl/backends/default.h
+++ b/libcxx/include/__pstl/backends/default.h
@@ -12,6 +12,8 @@
#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>
@@ -23,6 +25,7 @@
#include <__iterator/next.h>
#include <__pstl/backend_fwd.h>
#include <__pstl/dispatch.h>
+#include <__type_traits/desugars_to.h>
#include <__utility/empty.h>
#include <__utility/forward.h>
#include <__utility/move.h>
@@ -57,6 +60,7 @@ namespace __pstl {
// - all_of
// - none_of
// - is_partitioned
+// - find_first_of
//
// for_each family
// ---------------
@@ -181,6 +185,30 @@ 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, class _Predicate>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator1>
+ operator()(_Policy&& __policy,
+ _ForwardIterator1 __first1,
+ _ForwardIterator1 __last1,
+ _ForwardIterator2 __first2,
+ _ForwardIterator2 __last2,
+ _Predicate&& __pred) const noexcept {
+ using _FindIf = __dispatch<__find_if, __current_configuration, _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, _Ref1, _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;
+ }
+ });
+ }
+};
+
//////////////////////////////////////////////////////////////
// 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 e5bd7e764c59b..aee3f97019071 100644
--- a/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/pstl.iterator-requirements.verify.cpp
@@ -89,6 +89,17 @@ 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, it, it, non_fwd, non_fwd); // expected-error@*:* {{static assertion failed: find_first_of}}
+ (void)std::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}}
+ }
+
{
(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/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 6abceca182a95..f712f36caa9fc 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -655,11 +655,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
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..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
@@ -16,59 +16,82 @@
#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};
- typedef forward_iterator<int*> FI;
- typedef bidirectional_iterator<int*> BI;
- typedef random_access_iterator<int*> RI;
+ 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;
- 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
-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..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
@@ -18,63 +18,96 @@
#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};
- 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)))
- ;
- }
+ 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{};
+ 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
-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;
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..118b34da0cb6c
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of.pass.cpp
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <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(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) {
+ {
+ int a[] = {0};
+ 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(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(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(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(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(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(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b))) ==
+ Iter1(std::begin(a) + i));
+ a[i] = i;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ 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
new file mode 100644
index 0000000000000..1033b52e4621f
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/pstl.find_first_of_pred.pass.cpp
@@ -0,0 +1,140 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <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(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 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) {
+ {
+ int a[] = {0};
+ 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(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(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(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(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(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(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), Pred{}) ==
+ Iter1(std::begin(a) + i));
+ a[i] = i;
+ });
+ }
+ }
+};
+
+int main(int, char**) {
+ 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/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) {});
More information about the libcxx-commits
mailing list