xref: /freebsd-src/contrib/llvm-project/libcxx/include/__pstl/backends/default.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric 
9*0fca6ea1SDimitry Andric #ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H
10*0fca6ea1SDimitry Andric #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #include <__algorithm/copy_n.h>
13*0fca6ea1SDimitry Andric #include <__algorithm/equal.h>
14*0fca6ea1SDimitry Andric #include <__algorithm/fill_n.h>
15*0fca6ea1SDimitry Andric #include <__algorithm/for_each_n.h>
16*0fca6ea1SDimitry Andric #include <__config>
17*0fca6ea1SDimitry Andric #include <__functional/identity.h>
18*0fca6ea1SDimitry Andric #include <__functional/not_fn.h>
19*0fca6ea1SDimitry Andric #include <__functional/operations.h>
20*0fca6ea1SDimitry Andric #include <__iterator/concepts.h>
21*0fca6ea1SDimitry Andric #include <__iterator/iterator_traits.h>
22*0fca6ea1SDimitry Andric #include <__pstl/backend_fwd.h>
23*0fca6ea1SDimitry Andric #include <__pstl/dispatch.h>
24*0fca6ea1SDimitry Andric #include <__utility/empty.h>
25*0fca6ea1SDimitry Andric #include <__utility/forward.h>
26*0fca6ea1SDimitry Andric #include <__utility/move.h>
27*0fca6ea1SDimitry Andric #include <optional>
28*0fca6ea1SDimitry Andric 
29*0fca6ea1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30*0fca6ea1SDimitry Andric #  pragma GCC system_header
31*0fca6ea1SDimitry Andric #endif
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS
34*0fca6ea1SDimitry Andric #include <__undef_macros>
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
37*0fca6ea1SDimitry Andric namespace __pstl {
38*0fca6ea1SDimitry Andric 
39*0fca6ea1SDimitry Andric //
40*0fca6ea1SDimitry Andric // This file provides an incomplete PSTL backend that implements all of the PSTL algorithms
41*0fca6ea1SDimitry Andric // based on a smaller set of basis operations.
42*0fca6ea1SDimitry Andric //
43*0fca6ea1SDimitry Andric // It is intended as a building block for other PSTL backends that implement some operations more
44*0fca6ea1SDimitry Andric // efficiently but may not want to define the full set of PSTL algorithms.
45*0fca6ea1SDimitry Andric //
46*0fca6ea1SDimitry Andric // This backend implements all the PSTL algorithms based on the following basis operations:
47*0fca6ea1SDimitry Andric //
48*0fca6ea1SDimitry Andric // find_if family
49*0fca6ea1SDimitry Andric // --------------
50*0fca6ea1SDimitry Andric // - find
51*0fca6ea1SDimitry Andric // - find_if_not
52*0fca6ea1SDimitry Andric // - any_of
53*0fca6ea1SDimitry Andric // - all_of
54*0fca6ea1SDimitry Andric // - none_of
55*0fca6ea1SDimitry Andric // - is_partitioned
56*0fca6ea1SDimitry Andric //
57*0fca6ea1SDimitry Andric // for_each family
58*0fca6ea1SDimitry Andric // ---------------
59*0fca6ea1SDimitry Andric // - for_each_n
60*0fca6ea1SDimitry Andric // - fill
61*0fca6ea1SDimitry Andric // - fill_n
62*0fca6ea1SDimitry Andric // - replace
63*0fca6ea1SDimitry Andric // - replace_if
64*0fca6ea1SDimitry Andric // - generate
65*0fca6ea1SDimitry Andric // - generate_n
66*0fca6ea1SDimitry Andric //
67*0fca6ea1SDimitry Andric // merge family
68*0fca6ea1SDimitry Andric // ------------
69*0fca6ea1SDimitry Andric // No other algorithms based on merge
70*0fca6ea1SDimitry Andric //
71*0fca6ea1SDimitry Andric // stable_sort family
72*0fca6ea1SDimitry Andric // ------------------
73*0fca6ea1SDimitry Andric // - sort
74*0fca6ea1SDimitry Andric //
75*0fca6ea1SDimitry Andric // transform_reduce and transform_reduce_binary family
76*0fca6ea1SDimitry Andric // ---------------------------------------------------
77*0fca6ea1SDimitry Andric // - count_if
78*0fca6ea1SDimitry Andric // - count
79*0fca6ea1SDimitry Andric // - equal(3 legs)
80*0fca6ea1SDimitry Andric // - equal
81*0fca6ea1SDimitry Andric // - reduce
82*0fca6ea1SDimitry Andric //
83*0fca6ea1SDimitry Andric // transform and transform_binary family
84*0fca6ea1SDimitry Andric // -------------------------------------
85*0fca6ea1SDimitry Andric // - replace_copy_if
86*0fca6ea1SDimitry Andric // - replace_copy
87*0fca6ea1SDimitry Andric // - move
88*0fca6ea1SDimitry Andric // - copy
89*0fca6ea1SDimitry Andric // - copy_n
90*0fca6ea1SDimitry Andric // - rotate_copy
91*0fca6ea1SDimitry Andric //
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
94*0fca6ea1SDimitry Andric // find_if family
95*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
96*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
97*0fca6ea1SDimitry Andric struct __find<__default_backend_tag, _ExecutionPolicy> {
98*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Tp>
99*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
100*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept {
101*0fca6ea1SDimitry Andric     using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
102*0fca6ea1SDimitry Andric     return _FindIf()(
103*0fca6ea1SDimitry Andric         __policy, std::move(__first), std::move(__last), [&](__iter_reference<_ForwardIterator> __element) {
104*0fca6ea1SDimitry Andric           return __element == __value;
105*0fca6ea1SDimitry Andric         });
106*0fca6ea1SDimitry Andric   }
107*0fca6ea1SDimitry Andric };
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
110*0fca6ea1SDimitry Andric struct __find_if_not<__default_backend_tag, _ExecutionPolicy> {
111*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred>
112*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardIterator>
113*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
114*0fca6ea1SDimitry Andric     using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
115*0fca6ea1SDimitry Andric     return _FindIf()(__policy, __first, __last, std::not_fn(std::forward<_Pred>(__pred)));
116*0fca6ea1SDimitry Andric   }
117*0fca6ea1SDimitry Andric };
118*0fca6ea1SDimitry Andric 
119*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
120*0fca6ea1SDimitry Andric struct __any_of<__default_backend_tag, _ExecutionPolicy> {
121*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred>
122*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
123*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
124*0fca6ea1SDimitry Andric     using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>;
125*0fca6ea1SDimitry Andric     auto __res    = _FindIf()(__policy, __first, __last, std::forward<_Pred>(__pred));
126*0fca6ea1SDimitry Andric     if (!__res)
127*0fca6ea1SDimitry Andric       return nullopt;
128*0fca6ea1SDimitry Andric     return *__res != __last;
129*0fca6ea1SDimitry Andric   }
130*0fca6ea1SDimitry Andric };
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
133*0fca6ea1SDimitry Andric struct __all_of<__default_backend_tag, _ExecutionPolicy> {
134*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred>
135*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
136*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
137*0fca6ea1SDimitry Andric     using _AnyOf = __dispatch<__any_of, __current_configuration, _ExecutionPolicy>;
138*0fca6ea1SDimitry Andric     auto __res   = _AnyOf()(__policy, __first, __last, [&](__iter_reference<_ForwardIterator> __value) {
139*0fca6ea1SDimitry Andric       return !__pred(__value);
140*0fca6ea1SDimitry Andric     });
141*0fca6ea1SDimitry Andric     if (!__res)
142*0fca6ea1SDimitry Andric       return nullopt;
143*0fca6ea1SDimitry Andric     return !*__res;
144*0fca6ea1SDimitry Andric   }
145*0fca6ea1SDimitry Andric };
146*0fca6ea1SDimitry Andric 
147*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
148*0fca6ea1SDimitry Andric struct __none_of<__default_backend_tag, _ExecutionPolicy> {
149*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred>
150*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
151*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
152*0fca6ea1SDimitry Andric     using _AnyOf = __dispatch<__any_of, __current_configuration, _ExecutionPolicy>;
153*0fca6ea1SDimitry Andric     auto __res   = _AnyOf()(__policy, __first, __last, std::forward<_Pred>(__pred));
154*0fca6ea1SDimitry Andric     if (!__res)
155*0fca6ea1SDimitry Andric       return nullopt;
156*0fca6ea1SDimitry Andric     return !*__res;
157*0fca6ea1SDimitry Andric   }
158*0fca6ea1SDimitry Andric };
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
161*0fca6ea1SDimitry Andric struct __is_partitioned<__default_backend_tag, _ExecutionPolicy> {
162*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred>
163*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
164*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept {
165*0fca6ea1SDimitry Andric     using _FindIfNot   = __dispatch<__find_if_not, __current_configuration, _ExecutionPolicy>;
166*0fca6ea1SDimitry Andric     auto __maybe_first = _FindIfNot()(__policy, std::move(__first), std::move(__last), __pred);
167*0fca6ea1SDimitry Andric     if (__maybe_first == nullopt)
168*0fca6ea1SDimitry Andric       return nullopt;
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric     __first = *__maybe_first;
171*0fca6ea1SDimitry Andric     if (__first == __last)
172*0fca6ea1SDimitry Andric       return true;
173*0fca6ea1SDimitry Andric     ++__first;
174*0fca6ea1SDimitry Andric     using _NoneOf = __dispatch<__none_of, __current_configuration, _ExecutionPolicy>;
175*0fca6ea1SDimitry Andric     return _NoneOf()(__policy, std::move(__first), std::move(__last), __pred);
176*0fca6ea1SDimitry Andric   }
177*0fca6ea1SDimitry Andric };
178*0fca6ea1SDimitry Andric 
179*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
180*0fca6ea1SDimitry Andric // for_each family
181*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
182*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
183*0fca6ea1SDimitry Andric struct __for_each_n<__default_backend_tag, _ExecutionPolicy> {
184*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Size, class _Function>
185*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
186*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) const noexcept {
187*0fca6ea1SDimitry Andric     if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
188*0fca6ea1SDimitry Andric       using _ForEach          = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
189*0fca6ea1SDimitry Andric       _ForwardIterator __last = __first + __size;
190*0fca6ea1SDimitry Andric       return _ForEach()(__policy, std::move(__first), std::move(__last), std::move(__func));
191*0fca6ea1SDimitry Andric     } else {
192*0fca6ea1SDimitry Andric       // Otherwise, use the serial algorithm to avoid doing two passes over the input
193*0fca6ea1SDimitry Andric       std::for_each_n(std::move(__first), __size, std::move(__func));
194*0fca6ea1SDimitry Andric       return __empty{};
195*0fca6ea1SDimitry Andric     }
196*0fca6ea1SDimitry Andric   }
197*0fca6ea1SDimitry Andric };
198*0fca6ea1SDimitry Andric 
199*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
200*0fca6ea1SDimitry Andric struct __fill<__default_backend_tag, _ExecutionPolicy> {
201*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Tp>
202*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
203*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept {
204*0fca6ea1SDimitry Andric     using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
205*0fca6ea1SDimitry Andric     using _Ref     = __iter_reference<_ForwardIterator>;
206*0fca6ea1SDimitry Andric     return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __value; });
207*0fca6ea1SDimitry Andric   }
208*0fca6ea1SDimitry Andric };
209*0fca6ea1SDimitry Andric 
210*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
211*0fca6ea1SDimitry Andric struct __fill_n<__default_backend_tag, _ExecutionPolicy> {
212*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Size, class _Tp>
213*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
214*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _Tp const& __value) const noexcept {
215*0fca6ea1SDimitry Andric     if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
216*0fca6ea1SDimitry Andric       using _Fill             = __dispatch<__fill, __current_configuration, _ExecutionPolicy>;
217*0fca6ea1SDimitry Andric       _ForwardIterator __last = __first + __n;
218*0fca6ea1SDimitry Andric       return _Fill()(__policy, std::move(__first), std::move(__last), __value);
219*0fca6ea1SDimitry Andric     } else {
220*0fca6ea1SDimitry Andric       // Otherwise, use the serial algorithm to avoid doing two passes over the input
221*0fca6ea1SDimitry Andric       std::fill_n(std::move(__first), __n, __value);
222*0fca6ea1SDimitry Andric       return optional<__empty>{__empty{}};
223*0fca6ea1SDimitry Andric     }
224*0fca6ea1SDimitry Andric   }
225*0fca6ea1SDimitry Andric };
226*0fca6ea1SDimitry Andric 
227*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
228*0fca6ea1SDimitry Andric struct __replace<__default_backend_tag, _ExecutionPolicy> {
229*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Tp>
230*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
231*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __old, _Tp const& __new)
232*0fca6ea1SDimitry Andric       const noexcept {
233*0fca6ea1SDimitry Andric     using _ReplaceIf = __dispatch<__replace_if, __current_configuration, _ExecutionPolicy>;
234*0fca6ea1SDimitry Andric     using _Ref       = __iter_reference<_ForwardIterator>;
235*0fca6ea1SDimitry Andric     return _ReplaceIf()(
236*0fca6ea1SDimitry Andric         __policy, std::move(__first), std::move(__last), [&](_Ref __element) { return __element == __old; }, __new);
237*0fca6ea1SDimitry Andric   }
238*0fca6ea1SDimitry Andric };
239*0fca6ea1SDimitry Andric 
240*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
241*0fca6ea1SDimitry Andric struct __replace_if<__default_backend_tag, _ExecutionPolicy> {
242*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Pred, class _Tp>
243*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(
244*0fca6ea1SDimitry Andric       _Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred, _Tp const& __new_value)
245*0fca6ea1SDimitry Andric       const noexcept {
246*0fca6ea1SDimitry Andric     using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
247*0fca6ea1SDimitry Andric     using _Ref     = __iter_reference<_ForwardIterator>;
248*0fca6ea1SDimitry Andric     return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) {
249*0fca6ea1SDimitry Andric       if (__pred(__element))
250*0fca6ea1SDimitry Andric         __element = __new_value;
251*0fca6ea1SDimitry Andric     });
252*0fca6ea1SDimitry Andric   }
253*0fca6ea1SDimitry Andric };
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
256*0fca6ea1SDimitry Andric struct __generate<__default_backend_tag, _ExecutionPolicy> {
257*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Generator>
258*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
259*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator&& __gen) const noexcept {
260*0fca6ea1SDimitry Andric     using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>;
261*0fca6ea1SDimitry Andric     using _Ref     = __iter_reference<_ForwardIterator>;
262*0fca6ea1SDimitry Andric     return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __gen(); });
263*0fca6ea1SDimitry Andric   }
264*0fca6ea1SDimitry Andric };
265*0fca6ea1SDimitry Andric 
266*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
267*0fca6ea1SDimitry Andric struct __generate_n<__default_backend_tag, _ExecutionPolicy> {
268*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Size, class _Generator>
269*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
270*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _Generator&& __gen) const noexcept {
271*0fca6ea1SDimitry Andric     using _ForEachN = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>;
272*0fca6ea1SDimitry Andric     using _Ref      = __iter_reference<_ForwardIterator>;
273*0fca6ea1SDimitry Andric     return _ForEachN()(__policy, std::move(__first), __n, [&](_Ref __element) { __element = __gen(); });
274*0fca6ea1SDimitry Andric   }
275*0fca6ea1SDimitry Andric };
276*0fca6ea1SDimitry Andric 
277*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
278*0fca6ea1SDimitry Andric // stable_sort family
279*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
280*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
281*0fca6ea1SDimitry Andric struct __sort<__default_backend_tag, _ExecutionPolicy> {
282*0fca6ea1SDimitry Andric   template <class _Policy, class _RandomAccessIterator, class _Comp>
283*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(
284*0fca6ea1SDimitry Andric       _Policy&& __policy, _RandomAccessIterator __first, _RandomAccessIterator __last, _Comp&& __comp) const noexcept {
285*0fca6ea1SDimitry Andric     using _StableSort = __dispatch<__stable_sort, __current_configuration, _ExecutionPolicy>;
286*0fca6ea1SDimitry Andric     return _StableSort()(__policy, std::move(__first), std::move(__last), std::forward<_Comp>(__comp));
287*0fca6ea1SDimitry Andric   }
288*0fca6ea1SDimitry Andric };
289*0fca6ea1SDimitry Andric 
290*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
291*0fca6ea1SDimitry Andric // transform_reduce family
292*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
293*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
294*0fca6ea1SDimitry Andric struct __count_if<__default_backend_tag, _ExecutionPolicy> {
295*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Predicate>
296*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> operator()(
297*0fca6ea1SDimitry Andric       _Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred) const noexcept {
298*0fca6ea1SDimitry Andric     using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>;
299*0fca6ea1SDimitry Andric     using _DiffT           = __iter_diff_t<_ForwardIterator>;
300*0fca6ea1SDimitry Andric     using _Ref             = __iter_reference<_ForwardIterator>;
301*0fca6ea1SDimitry Andric     return _TransformReduce()(
302*0fca6ea1SDimitry Andric         __policy, std::move(__first), std::move(__last), _DiffT{}, std::plus{}, [&](_Ref __element) -> _DiffT {
303*0fca6ea1SDimitry Andric           return __pred(__element) ? _DiffT(1) : _DiffT(0);
304*0fca6ea1SDimitry Andric         });
305*0fca6ea1SDimitry Andric   }
306*0fca6ea1SDimitry Andric };
307*0fca6ea1SDimitry Andric 
308*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
309*0fca6ea1SDimitry Andric struct __count<__default_backend_tag, _ExecutionPolicy> {
310*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Tp>
311*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>>
312*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept {
313*0fca6ea1SDimitry Andric     using _CountIf = __dispatch<__count_if, __current_configuration, _ExecutionPolicy>;
314*0fca6ea1SDimitry Andric     using _Ref     = __iter_reference<_ForwardIterator>;
315*0fca6ea1SDimitry Andric     return _CountIf()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) -> bool {
316*0fca6ea1SDimitry Andric       return __element == __value;
317*0fca6ea1SDimitry Andric     });
318*0fca6ea1SDimitry Andric   }
319*0fca6ea1SDimitry Andric };
320*0fca6ea1SDimitry Andric 
321*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
322*0fca6ea1SDimitry Andric struct __equal_3leg<__default_backend_tag, _ExecutionPolicy> {
323*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
324*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
325*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
326*0fca6ea1SDimitry Andric              _ForwardIterator1 __first1,
327*0fca6ea1SDimitry Andric              _ForwardIterator1 __last1,
328*0fca6ea1SDimitry Andric              _ForwardIterator2 __first2,
329*0fca6ea1SDimitry Andric              _Predicate&& __pred) const noexcept {
330*0fca6ea1SDimitry Andric     using _TransformReduce = __dispatch<__transform_reduce_binary, __current_configuration, _ExecutionPolicy>;
331*0fca6ea1SDimitry Andric     return _TransformReduce()(
332*0fca6ea1SDimitry Andric         __policy,
333*0fca6ea1SDimitry Andric         std::move(__first1),
334*0fca6ea1SDimitry Andric         std::move(__last1),
335*0fca6ea1SDimitry Andric         std::move(__first2),
336*0fca6ea1SDimitry Andric         true,
337*0fca6ea1SDimitry Andric         std::logical_and{},
338*0fca6ea1SDimitry Andric         std::forward<_Predicate>(__pred));
339*0fca6ea1SDimitry Andric   }
340*0fca6ea1SDimitry Andric };
341*0fca6ea1SDimitry Andric 
342*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
343*0fca6ea1SDimitry Andric struct __equal<__default_backend_tag, _ExecutionPolicy> {
344*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator1, class _ForwardIterator2, class _Predicate>
345*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool>
346*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
347*0fca6ea1SDimitry Andric              _ForwardIterator1 __first1,
348*0fca6ea1SDimitry Andric              _ForwardIterator1 __last1,
349*0fca6ea1SDimitry Andric              _ForwardIterator2 __first2,
350*0fca6ea1SDimitry Andric              _ForwardIterator2 __last2,
351*0fca6ea1SDimitry Andric              _Predicate&& __pred) const noexcept {
352*0fca6ea1SDimitry Andric     if constexpr (__has_random_access_iterator_category<_ForwardIterator1>::value &&
353*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category<_ForwardIterator2>::value) {
354*0fca6ea1SDimitry Andric       if (__last1 - __first1 != __last2 - __first2)
355*0fca6ea1SDimitry Andric         return false;
356*0fca6ea1SDimitry Andric       // Fall back to the 3 legged algorithm
357*0fca6ea1SDimitry Andric       using _Equal3Leg = __dispatch<__equal_3leg, __current_configuration, _ExecutionPolicy>;
358*0fca6ea1SDimitry Andric       return _Equal3Leg()(
359*0fca6ea1SDimitry Andric           __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::forward<_Predicate>(__pred));
360*0fca6ea1SDimitry Andric     } else {
361*0fca6ea1SDimitry Andric       // If we don't have random access, fall back to the serial algorithm cause we can't do much
362*0fca6ea1SDimitry Andric       return std::equal(
363*0fca6ea1SDimitry Andric           std::move(__first1),
364*0fca6ea1SDimitry Andric           std::move(__last1),
365*0fca6ea1SDimitry Andric           std::move(__first2),
366*0fca6ea1SDimitry Andric           std::move(__last2),
367*0fca6ea1SDimitry Andric           std::forward<_Predicate>(__pred));
368*0fca6ea1SDimitry Andric     }
369*0fca6ea1SDimitry Andric   }
370*0fca6ea1SDimitry Andric };
371*0fca6ea1SDimitry Andric 
372*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
373*0fca6ea1SDimitry Andric struct __reduce<__default_backend_tag, _ExecutionPolicy> {
374*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Tp, class _BinaryOperation>
375*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_Tp>
376*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp __init, _BinaryOperation&& __op)
377*0fca6ea1SDimitry Andric       const noexcept {
378*0fca6ea1SDimitry Andric     using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>;
379*0fca6ea1SDimitry Andric     return _TransformReduce()(
380*0fca6ea1SDimitry Andric         __policy,
381*0fca6ea1SDimitry Andric         std::move(__first),
382*0fca6ea1SDimitry Andric         std::move(__last),
383*0fca6ea1SDimitry Andric         std::move(__init),
384*0fca6ea1SDimitry Andric         std::forward<_BinaryOperation>(__op),
385*0fca6ea1SDimitry Andric         __identity{});
386*0fca6ea1SDimitry Andric   }
387*0fca6ea1SDimitry Andric };
388*0fca6ea1SDimitry Andric 
389*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
390*0fca6ea1SDimitry Andric // transform family
391*0fca6ea1SDimitry Andric //////////////////////////////////////////////////////////////
392*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
393*0fca6ea1SDimitry Andric struct __replace_copy_if<__default_backend_tag, _ExecutionPolicy> {
394*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _Pred, class _Tp>
395*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
396*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
397*0fca6ea1SDimitry Andric              _ForwardIterator __first,
398*0fca6ea1SDimitry Andric              _ForwardIterator __last,
399*0fca6ea1SDimitry Andric              _ForwardOutIterator __out_it,
400*0fca6ea1SDimitry Andric              _Pred&& __pred,
401*0fca6ea1SDimitry Andric              _Tp const& __new_value) const noexcept {
402*0fca6ea1SDimitry Andric     using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;
403*0fca6ea1SDimitry Andric     using _Ref       = __iter_reference<_ForwardIterator>;
404*0fca6ea1SDimitry Andric     auto __res =
405*0fca6ea1SDimitry Andric         _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](_Ref __element) {
406*0fca6ea1SDimitry Andric           return __pred(__element) ? __new_value : __element;
407*0fca6ea1SDimitry Andric         });
408*0fca6ea1SDimitry Andric     if (__res == nullopt)
409*0fca6ea1SDimitry Andric       return nullopt;
410*0fca6ea1SDimitry Andric     return __empty{};
411*0fca6ea1SDimitry Andric   }
412*0fca6ea1SDimitry Andric };
413*0fca6ea1SDimitry Andric 
414*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
415*0fca6ea1SDimitry Andric struct __replace_copy<__default_backend_tag, _ExecutionPolicy> {
416*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _Tp>
417*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty>
418*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
419*0fca6ea1SDimitry Andric              _ForwardIterator __first,
420*0fca6ea1SDimitry Andric              _ForwardIterator __last,
421*0fca6ea1SDimitry Andric              _ForwardOutIterator __out_it,
422*0fca6ea1SDimitry Andric              _Tp const& __old_value,
423*0fca6ea1SDimitry Andric              _Tp const& __new_value) const noexcept {
424*0fca6ea1SDimitry Andric     using _ReplaceCopyIf = __dispatch<__replace_copy_if, __current_configuration, _ExecutionPolicy>;
425*0fca6ea1SDimitry Andric     using _Ref           = __iter_reference<_ForwardIterator>;
426*0fca6ea1SDimitry Andric     return _ReplaceCopyIf()(
427*0fca6ea1SDimitry Andric         __policy,
428*0fca6ea1SDimitry Andric         std::move(__first),
429*0fca6ea1SDimitry Andric         std::move(__last),
430*0fca6ea1SDimitry Andric         std::move(__out_it),
431*0fca6ea1SDimitry Andric         [&](_Ref __element) { return __element == __old_value; },
432*0fca6ea1SDimitry Andric         __new_value);
433*0fca6ea1SDimitry Andric   }
434*0fca6ea1SDimitry Andric };
435*0fca6ea1SDimitry Andric 
436*0fca6ea1SDimitry Andric // TODO: Use the std::copy/move shenanigans to forward to std::memmove
437*0fca6ea1SDimitry Andric //       Investigate whether we want to still forward to std::transform(policy)
438*0fca6ea1SDimitry Andric //       in that case for the execution::par part, or whether we actually want
439*0fca6ea1SDimitry Andric //       to run everything serially in that case.
440*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
441*0fca6ea1SDimitry Andric struct __move<__default_backend_tag, _ExecutionPolicy> {
442*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>
443*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
444*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it)
445*0fca6ea1SDimitry Andric       const noexcept {
446*0fca6ea1SDimitry Andric     using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;
447*0fca6ea1SDimitry Andric     return _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](auto&& __element) {
448*0fca6ea1SDimitry Andric       return std::move(__element);
449*0fca6ea1SDimitry Andric     });
450*0fca6ea1SDimitry Andric   }
451*0fca6ea1SDimitry Andric };
452*0fca6ea1SDimitry Andric 
453*0fca6ea1SDimitry Andric // TODO: Use the std::copy/move shenanigans to forward to std::memmove
454*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
455*0fca6ea1SDimitry Andric struct __copy<__default_backend_tag, _ExecutionPolicy> {
456*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>
457*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
458*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _ForwardOutIterator __out_it)
459*0fca6ea1SDimitry Andric       const noexcept {
460*0fca6ea1SDimitry Andric     using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>;
461*0fca6ea1SDimitry Andric     return _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), __identity());
462*0fca6ea1SDimitry Andric   }
463*0fca6ea1SDimitry Andric };
464*0fca6ea1SDimitry Andric 
465*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
466*0fca6ea1SDimitry Andric struct __copy_n<__default_backend_tag, _ExecutionPolicy> {
467*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _Size, class _ForwardOutIterator>
468*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
469*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _ForwardOutIterator __out_it) const noexcept {
470*0fca6ea1SDimitry Andric     if constexpr (__has_random_access_iterator_category_or_concept<_ForwardIterator>::value) {
471*0fca6ea1SDimitry Andric       using _Copy             = __dispatch<__copy, __current_configuration, _ExecutionPolicy>;
472*0fca6ea1SDimitry Andric       _ForwardIterator __last = __first + __n;
473*0fca6ea1SDimitry Andric       return _Copy()(__policy, std::move(__first), std::move(__last), std::move(__out_it));
474*0fca6ea1SDimitry Andric     } else {
475*0fca6ea1SDimitry Andric       // Otherwise, use the serial algorithm to avoid doing two passes over the input
476*0fca6ea1SDimitry Andric       return std::copy_n(std::move(__first), __n, std::move(__out_it));
477*0fca6ea1SDimitry Andric     }
478*0fca6ea1SDimitry Andric   }
479*0fca6ea1SDimitry Andric };
480*0fca6ea1SDimitry Andric 
481*0fca6ea1SDimitry Andric template <class _ExecutionPolicy>
482*0fca6ea1SDimitry Andric struct __rotate_copy<__default_backend_tag, _ExecutionPolicy> {
483*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator>
484*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
485*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
486*0fca6ea1SDimitry Andric              _ForwardIterator __first,
487*0fca6ea1SDimitry Andric              _ForwardIterator __middle,
488*0fca6ea1SDimitry Andric              _ForwardIterator __last,
489*0fca6ea1SDimitry Andric              _ForwardOutIterator __out_it) const noexcept {
490*0fca6ea1SDimitry Andric     using _Copy       = __dispatch<__copy, __current_configuration, _ExecutionPolicy>;
491*0fca6ea1SDimitry Andric     auto __result_mid = _Copy()(__policy, __middle, std::move(__last), std::move(__out_it));
492*0fca6ea1SDimitry Andric     if (__result_mid == nullopt)
493*0fca6ea1SDimitry Andric       return nullopt;
494*0fca6ea1SDimitry Andric     return _Copy()(__policy, std::move(__first), std::move(__middle), *std::move(__result_mid));
495*0fca6ea1SDimitry Andric   }
496*0fca6ea1SDimitry Andric };
497*0fca6ea1SDimitry Andric 
498*0fca6ea1SDimitry Andric } // namespace __pstl
499*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
500*0fca6ea1SDimitry Andric 
501*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS
502*0fca6ea1SDimitry Andric 
503*0fca6ea1SDimitry Andric #endif // _LIBCPP___PSTL_BACKENDS_DEFAULT_H
504