[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