[libcxx-commits] [libcxx] 8243916 - [libc++][PSTL] Implement std::find{, _if, _if_not}
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon May 1 09:04:36 PDT 2023
Author: Nikolas Klauser
Date: 2023-05-01T09:04:29-07:00
New Revision: 824391693cbbd4cf93310ac25edd354c8e74a522
URL: https://github.com/llvm/llvm-project/commit/824391693cbbd4cf93310ac25edd354c8e74a522
DIFF: https://github.com/llvm/llvm-project/commit/824391693cbbd4cf93310ac25edd354c8e74a522.diff
LOG: [libc++][PSTL] Implement std::find{,_if,_if_not}
Reviewed By: ldionne, #libc
Spies: libcxx-commits
Differential Revision: https://reviews.llvm.org/D149539
Added:
libcxx/include/__algorithm/pstl_find.h
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__pstl/internal/algorithm_fwd.h
libcxx/include/__pstl/internal/algorithm_impl.h
libcxx/include/__pstl/internal/glue_algorithm_defs.h
libcxx/include/__pstl/internal/glue_algorithm_impl.h
libcxx/include/algorithm
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 61b914130fa60..fa64cec327e6c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -70,6 +70,7 @@ set(files
__algorithm/pop_heap.h
__algorithm/prev_permutation.h
__algorithm/pstl_any_all_none_of.h
+ __algorithm/pstl_find.h
__algorithm/pstl_for_each.h
__algorithm/push_heap.h
__algorithm/ranges_adjacent_find.h
diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h
new file mode 100644
index 0000000000000..d3c886d2c4bc9
--- /dev/null
+++ b/libcxx/include/__algorithm/pstl_find.h
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_PSTL_FIND_H
+#define _LIBCPP___ALGORITHM_PSTL_FIND_H
+
+#include <__algorithm/comp.h>
+#include <__algorithm/find.h>
+#include <__config>
+#include <__functional/not_fn.h>
+#include <__pstl/internal/parallel_impl.h>
+#include <__pstl/internal/unseq_backend_simd.h>
+#include <__type_traits/is_execution_policy.h>
+#include <__utility/terminate_on_exception.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Tp,
+ enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+ if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+ __is_cpp17_random_access_iterator<_ForwardIterator>::value) {
+ return std::__terminate_on_exception([&] {
+ return __pstl::__internal::__parallel_find(
+ __pstl::__internal::__par_backend_tag{},
+ __policy,
+ __first,
+ __last,
+ [&__policy, &__value](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+ return std::find(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __value);
+ },
+ less<>{},
+ true);
+ });
+ } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+ __is_cpp17_random_access_iterator<_ForwardIterator>::value) {
+ using __
diff _t = __iter_
diff _t<_ForwardIterator>;
+ return __pstl::__unseq_backend::__simd_first(
+ __first, __
diff _t(0), __last - __first, [&__value](_ForwardIterator __iter, __
diff _t __i) {
+ return __iter[__i] == __value;
+ });
+ } else {
+ return std::find(__first, __last, __value);
+ }
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+ if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
+ __is_cpp17_random_access_iterator<_ForwardIterator>::value) {
+ return std::__terminate_on_exception([&] {
+ return __pstl::__internal::__parallel_find(
+ __pstl::__internal::__par_backend_tag{},
+ __policy,
+ __first,
+ __last,
+ [&__policy, &__pred](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
+ return std::find_if(std::__remove_parallel_policy(__policy), __brick_first, __brick_last, __pred);
+ },
+ less<>{},
+ true);
+ });
+ } else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
+ __is_cpp17_random_access_iterator<_ForwardIterator>::value) {
+ using __
diff _t = __iter_
diff _t<_ForwardIterator>;
+ return __pstl::__unseq_backend::__simd_first(
+ __first, __
diff _t(0), __last - __first, [&__pred](_ForwardIterator __iter, __
diff _t __i) {
+ return __pred(__iter[__i]);
+ });
+ } else {
+ return std::find_if(__first, __last, __pred);
+ }
+}
+
+template <class _ExecutionPolicy,
+ class _ForwardIterator,
+ class _Predicate,
+ enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _ForwardIterator
+find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
+ return std::find_if(__policy, __first, __last, std::not_fn(std::move(__pred)));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ALGORITHM_PSTL_FIND_H
diff --git a/libcxx/include/__pstl/internal/algorithm_fwd.h b/libcxx/include/__pstl/internal/algorithm_fwd.h
index 798f0fe23bb5d..8dccab13fe4e1 100644
--- a/libcxx/include/__pstl/internal/algorithm_fwd.h
+++ b/libcxx/include/__pstl/internal/algorithm_fwd.h
@@ -322,31 +322,6 @@ bool __pattern_equal(
_RandomAccessIterator2,
_BinaryPredicate);
-//------------------------------------------------------------------------
-// find_if
-//------------------------------------------------------------------------
-
-template <class _ForwardIterator, class _Predicate>
-_ForwardIterator __brick_find_if(
- _ForwardIterator,
- _ForwardIterator,
- _Predicate,
- /*is_vector=*/std::false_type) noexcept;
-
-template <class _RandomAccessIterator, class _Predicate>
-_RandomAccessIterator __brick_find_if(
- _RandomAccessIterator,
- _RandomAccessIterator,
- _Predicate,
- /*is_vector=*/std::true_type) noexcept;
-
-template <class _Tag, class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_ForwardIterator __pattern_find_if(_Tag, _ExecutionPolicy&&, _ForwardIterator, _ForwardIterator, _Predicate) noexcept;
-
-template <class _IsVector, class _ExecutionPolicy, class _RandomAccessIterator, class _Predicate>
-_RandomAccessIterator __pattern_find_if(
- __parallel_tag<_IsVector>, _ExecutionPolicy&&, _RandomAccessIterator, _RandomAccessIterator, _Predicate);
-
//------------------------------------------------------------------------
// find_end
//------------------------------------------------------------------------
diff --git a/libcxx/include/__pstl/internal/algorithm_impl.h b/libcxx/include/__pstl/internal/algorithm_impl.h
index da2e7ecbe944c..f380825812332 100644
--- a/libcxx/include/__pstl/internal/algorithm_impl.h
+++ b/libcxx/include/__pstl/internal/algorithm_impl.h
@@ -579,60 +579,6 @@ bool __pattern_equal(
});
}
-//------------------------------------------------------------------------
-// find_if
-//------------------------------------------------------------------------
-template <class _ForwardIterator, class _Predicate>
-_ForwardIterator
-__brick_find_if(_ForwardIterator __first,
- _ForwardIterator __last,
- _Predicate __pred,
- /*is_vector=*/std::false_type) noexcept {
- return std::find_if(__first, __last, __pred);
-}
-
-template <class _RandomAccessIterator, class _Predicate>
-_RandomAccessIterator
-__brick_find_if(_RandomAccessIterator __first,
- _RandomAccessIterator __last,
- _Predicate __pred,
- /*is_vector=*/std::true_type) noexcept {
- typedef typename std::iterator_traits<_RandomAccessIterator>::
diff erence_type _SizeType;
- return __unseq_backend::__simd_first(
- __first, _SizeType(0), __last - __first, [&__pred](_RandomAccessIterator __it, _SizeType __i) {
- return __pred(__it[__i]);
- });
-}
-
-template <class _Tag, class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-_ForwardIterator __pattern_find_if(
- _Tag, _ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) noexcept {
- return __internal::__brick_find_if(__first, __last, __pred, typename _Tag::__is_vector{});
-}
-
-template <class _IsVector, class _ExecutionPolicy, class _RandomAccessIterator, class _Predicate>
-_RandomAccessIterator __pattern_find_if(
- __parallel_tag<_IsVector> __tag,
- _ExecutionPolicy&& __exec,
- _RandomAccessIterator __first,
- _RandomAccessIterator __last,
- _Predicate __pred) {
- using __backend_tag = typename decltype(__tag)::__backend_tag;
-
- return __internal::__except_handler([&]() {
- return __internal::__parallel_find(
- __backend_tag{},
- std::forward<_ExecutionPolicy>(__exec),
- __first,
- __last,
- [__pred](_RandomAccessIterator __i, _RandomAccessIterator __j) {
- return __internal::__brick_find_if(__i, __j, __pred, _IsVector{});
- },
- std::less<typename std::iterator_traits<_RandomAccessIterator>::
diff erence_type>(),
- /*is_first=*/true);
- });
-}
-
//------------------------------------------------------------------------
// find_end
//------------------------------------------------------------------------
diff --git a/libcxx/include/__pstl/internal/glue_algorithm_defs.h b/libcxx/include/__pstl/internal/glue_algorithm_defs.h
index 06453c0bd9d30..cd404f0db5c6e 100644
--- a/libcxx/include/__pstl/internal/glue_algorithm_defs.h
+++ b/libcxx/include/__pstl/internal/glue_algorithm_defs.h
@@ -20,20 +20,6 @@ _PSTL_HIDE_FROM_ABI_PUSH
namespace std {
-// [alg.find]
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find_if_not(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred);
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value);
-
// [alg.find.end]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
diff --git a/libcxx/include/__pstl/internal/glue_algorithm_impl.h b/libcxx/include/__pstl/internal/glue_algorithm_impl.h
index e3aa2b4b30c4f..ec11c8b4940f5 100644
--- a/libcxx/include/__pstl/internal/glue_algorithm_impl.h
+++ b/libcxx/include/__pstl/internal/glue_algorithm_impl.h
@@ -25,30 +25,6 @@ _PSTL_HIDE_FROM_ABI_PUSH
namespace std {
-// [alg.find]
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find_if(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
- auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first);
-
- return __pstl::__internal::__pattern_find_if(
- __dispatch_tag, std::forward<_ExecutionPolicy>(__exec), __first, __last, __pred);
-}
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Predicate>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find_if_not(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) {
- return std::find_if(std::forward<_ExecutionPolicy>(__exec), __first, __last, std::not_fn(__pred));
-}
-
-template <class _ExecutionPolicy, class _ForwardIterator, class _Tp>
-__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
-find(_ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
- return std::find_if(
- std::forward<_ExecutionPolicy>(__exec), __first, __last, __pstl::__internal::__equal_value<_Tp>(__value));
-}
-
// [alg.find.end]
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator1>
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 611c639c3b6c2..ed3bc05c8932b 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1910,6 +1910,7 @@ template <class BidirectionalIterator, class Compare>
#ifdef _LIBCPP_HAS_PARALLEL_ALGORITHMS
# include <__algorithm/pstl_any_all_none_of.h>
+# include <__algorithm/pstl_find.h>
# include <__algorithm/pstl_for_each.h>
#endif
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
new file mode 100644
index 0000000000000..004f6d6d8f900
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// REQUIRES: with-pstl
+
+// <algorithm>
+
+// template<class ExecutionPolicy, class ForwardIterator, class T>
+// ForwardIterator find(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last,
+// const T& value);
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+EXECUTION_POLICY_SFINAE_TEST(find);
+
+static_assert(sfinae_test_find<int, int*, int*, bool (*)(int)>);
+static_assert(!sfinae_test_find<std::execution::parallel_policy, int*, int*, int>);
+
+template <class Iter>
+struct Test {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // simple test
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::end(a)), 3)) == a + 2);
+
+ // check that last is returned if no element matches
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::end(a)), 0)) == std::end(a));
+
+ // check that the first element is returned
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::end(a)), 1)) == std::begin(a));
+
+ // check that an empty range works
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::begin(a)), 1)) == std::begin(a));
+
+ // check that a one-element range works
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::begin(a) + 1), 1)) == std::begin(a));
+
+ // check that a two-element range works
+ assert(base(std::find(policy, Iter(std::begin(a)), Iter(std::begin(a) + 2), 2)) == std::begin(a) + 1);
+
+ // check that a large number of elements works
+ std::vector<int> vec(200, 4);
+ vec[176] = 5;
+ assert(base(std::find(policy, Iter(std::data(vec)), Iter(std::data(vec) + std::size(vec)), 5)) ==
+ std::data(vec) + 176);
+ }
+};
+
+struct ThrowOnCompare {};
+
+bool operator==(ThrowOnCompare, ThrowOnCompare) { throw int{}; }
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ std::set_terminate(terminate_successful);
+ ThrowOnCompare a[2];
+ try {
+ (void)std::find(std::execution::par, std::begin(a), std::end(a), ThrowOnCompare{});
+ } catch (int) {
+ assert(false);
+ }
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
new file mode 100644
index 0000000000000..bff446bc079ee
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// REQUIRES: with-pstl
+
+// <algorithm>
+
+// template<class ExecutionPolicy, class ForwardIterator, class Predicate>
+// ForwardIterator find_if(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last,
+// Predicate pred);
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+EXECUTION_POLICY_SFINAE_TEST(find_if);
+
+static_assert(sfinae_test_find_if<int, int*, int*, bool (*)(int)>);
+static_assert(!sfinae_test_find_if<std::execution::parallel_policy, int*, int*, int>);
+
+template <class Iter>
+struct Test {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // simple test
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 3; })) == a + 2);
+
+ // check that last is returned if no element matches
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 0; })) ==
+ std::end(a));
+
+ // check that the first element is returned
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 1; })) ==
+ std::begin(a));
+
+ // check that an empty range works
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::begin(a)), [](int i) { return i == 1; })) ==
+ std::begin(a));
+
+ // check that a one-element range works
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::begin(a) + 1), [](int i) { return i == 1; })) ==
+ std::begin(a));
+
+ // check that a two-element range works
+ assert(base(std::find_if(policy, Iter(std::begin(a)), Iter(std::begin(a) + 2), [](int i) { return i == 2; })) ==
+ std::begin(a) + 1);
+
+ // check that a large number of elements works
+ std::vector<int> vec(200, 4);
+ vec[176] = 5;
+ assert(base(std::find_if(policy, Iter(std::data(vec)), Iter(std::data(vec) + std::size(vec)), [](int i) {
+ return i == 5;
+ })) == std::data(vec) + 176);
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ std::set_terminate(terminate_successful);
+ int a[] = {1, 2};
+ try {
+ (void)std::find_if(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
+ } catch (int) {
+ assert(false);
+ }
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
new file mode 100644
index 0000000000000..2cf123e4f9516
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/pstl.find_if_not.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// REQUIRES: with-pstl
+
+// <algorithm>
+
+// template<class ExecutionPolicy, class ForwardIterator, class Predicate>
+// ForwardIterator find_if_not(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last,
+// Predicate pred);
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+#include "test_macros.h"
+#include "test_execution_policies.h"
+#include "test_iterators.h"
+
+EXECUTION_POLICY_SFINAE_TEST(find_if_not);
+
+static_assert(sfinae_test_find_if_not<int, int*, int*, bool (*)(int)>);
+static_assert(!sfinae_test_find_if_not<std::execution::parallel_policy, int*, int*, int>);
+
+template <class Iter>
+struct Test {
+ template <class Policy>
+ void operator()(Policy&& policy) {
+ int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // simple test
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i != 3; })) ==
+ a + 2);
+
+ // check that last is returned if no element matches
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i != 0; })) ==
+ std::end(a));
+
+ // check that the first element is returned
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i != 1; })) ==
+ std::begin(a));
+
+ // check that an empty range works
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::begin(a)), [](int i) { return i != 1; })) ==
+ std::begin(a));
+
+ // check that a one-element range works
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::begin(a) + 1), [](int i) { return i != 1; })) ==
+ std::begin(a));
+
+ // check that a two-element range works
+ assert(base(std::find_if_not(policy, Iter(std::begin(a)), Iter(std::begin(a) + 2), [](int i) { return i != 2; })) ==
+ std::begin(a) + 1);
+
+ // check that a large number of elements works
+ std::vector<int> vec(200, 4);
+ vec[176] = 5;
+ assert(base(std::find_if_not(policy, Iter(std::data(vec)), Iter(std::data(vec) + std::size(vec)), [](int i) {
+ return i != 5;
+ })) == std::data(vec) + 176);
+ }
+};
+
+int main(int, char**) {
+ types::for_each(types::forward_iterator_list<int*>{}, TestIteratorWithPolicies<Test>{});
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ std::set_terminate(terminate_successful);
+ int a[] = {1, 2};
+ try {
+ (void)std::find_if_not(std::execution::par, std::begin(a), std::end(a), [](int) -> bool { throw int{}; });
+ } catch (int) {
+ assert(false);
+ }
+#endif
+
+ return 0;
+}
More information about the libcxx-commits
mailing list