1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef _LIBCPP___CXX03___PSTL_CPU_ALGOS_ANY_OF_H
10 #define _LIBCPP___CXX03___PSTL_CPU_ALGOS_ANY_OF_H
12 #include <__cxx03/__algorithm/any_of.h>
13 #include <__cxx03/__assert>
14 #include <__cxx03/__atomic/atomic.h>
15 #include <__cxx03/__atomic/memory_order.h>
16 #include <__cxx03/__config>
17 #include <__cxx03/__iterator/concepts.h>
18 #include <__cxx03/__pstl/backend_fwd.h>
19 #include <__cxx03/__pstl/cpu_algos/cpu_traits.h>
20 #include <__cxx03/__type_traits/is_execution_policy.h>
21 #include <__cxx03/__utility/move.h>
22 #include <__cxx03/__utility/pair.h>
23 #include <__cxx03/cstdint>
24 #include <__cxx03/optional>
27 #include <__cxx03/__undef_macros>
29 _LIBCPP_BEGIN_NAMESPACE_STD
32 template <class _Backend
, class _Index
, class _Brick
>
33 _LIBCPP_HIDE_FROM_ABI optional
<bool> __parallel_or(_Index __first
, _Index __last
, _Brick __f
) {
34 std::atomic
<bool> __found(false);
35 auto __ret
= __cpu_traits
<_Backend
>::__for_each(__first
, __last
, [__f
, &__found
](_Index __i
, _Index __j
) {
36 if (!__found
.load(std::memory_order_relaxed
) && __f(__i
, __j
)) {
37 __found
.store(true, std::memory_order_relaxed
);
38 __cpu_traits
<_Backend
>::__cancel_execution();
43 return static_cast<bool>(__found
);
46 // TODO: check whether __simd_first() can be used here
47 template <class _Index
, class _DifferenceType
, class _Pred
>
48 _LIBCPP_HIDE_FROM_ABI
bool __simd_or(_Index __first
, _DifferenceType __n
, _Pred __pred
) noexcept
{
49 _DifferenceType __block_size
= 4 < __n
? 4 : __n
;
50 const _Index __last
= __first
+ __n
;
51 while (__last
!= __first
) {
53 _PSTL_PRAGMA_SIMD_REDUCTION(& : __flag
)
54 for (_DifferenceType __i
= 0; __i
< __block_size
; ++__i
)
55 if (__pred(*(__first
+ __i
)))
60 __first
+= __block_size
;
61 if (__last
- __first
>= __block_size
<< 1) {
62 // Double the block _Size. Any unnecessary iterations can be amortized against work done so far.
65 __block_size
= __last
- __first
;
71 template <class _Backend
, class _RawExecutionPolicy
>
72 struct __cpu_parallel_any_of
{
73 template <class _Policy
, class _ForwardIterator
, class _Predicate
>
74 _LIBCPP_HIDE_FROM_ABI optional
<bool>
75 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Predicate __pred
) const noexcept
{
76 if constexpr (__is_parallel_execution_policy_v
<_RawExecutionPolicy
> &&
77 __has_random_access_iterator_category_or_concept
<_ForwardIterator
>::value
) {
78 return __pstl::__parallel_or
<_Backend
>(
79 __first
, __last
, [&__policy
, &__pred
](_ForwardIterator __brick_first
, _ForwardIterator __brick_last
) {
80 using _AnyOfUnseq
= __pstl::__any_of
<_Backend
, __remove_parallel_policy_t
<_RawExecutionPolicy
>>;
81 auto __res
= _AnyOfUnseq()(std::__remove_parallel_policy(__policy
), __brick_first
, __brick_last
, __pred
);
82 _LIBCPP_ASSERT_INTERNAL(__res
, "unseq/seq should never try to allocate!");
83 return *std::move(__res
);
85 } else if constexpr (__is_unsequenced_execution_policy_v
<_RawExecutionPolicy
> &&
86 __has_random_access_iterator_category_or_concept
<_ForwardIterator
>::value
) {
87 return __pstl::__simd_or(__first
, __last
- __first
, __pred
);
89 return std::any_of(__first
, __last
, __pred
);
95 _LIBCPP_END_NAMESPACE_STD
99 #endif // _LIBCPP___CXX03___PSTL_CPU_ALGOS_ANY_OF_H