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___PSTL_BACKENDS_DEFAULT_H
10 #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H
12 #include <__algorithm/copy_n.h>
13 #include <__algorithm/equal.h>
14 #include <__algorithm/fill_n.h>
15 #include <__algorithm/for_each_n.h>
17 #include <__functional/identity.h>
18 #include <__functional/not_fn.h>
19 #include <__functional/operations.h>
20 #include <__iterator/concepts.h>
21 #include <__iterator/iterator_traits.h>
22 #include <__pstl/backend_fwd.h>
23 #include <__pstl/dispatch.h>
24 #include <__utility/empty.h>
25 #include <__utility/forward.h>
26 #include <__utility/move.h>
29 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30 # pragma GCC system_header
34 #include <__undef_macros>
36 #if _LIBCPP_STD_VER >= 17
38 _LIBCPP_BEGIN_NAMESPACE_STD
42 // This file provides an incomplete PSTL backend that implements all of the PSTL algorithms
43 // based on a smaller set of basis operations.
45 // It is intended as a building block for other PSTL backends that implement some operations more
46 // efficiently but may not want to define the full set of PSTL algorithms.
48 // This backend implements all the PSTL algorithms based on the following basis operations:
71 // No other algorithms based on merge
77 // transform_reduce and transform_reduce_binary family
78 // ---------------------------------------------------
85 // transform and transform_binary family
86 // -------------------------------------
95 //////////////////////////////////////////////////////////////
97 //////////////////////////////////////////////////////////////
98 template <class _ExecutionPolicy
>
99 struct __find
<__default_backend_tag
, _ExecutionPolicy
> {
100 template <class _Policy
, class _ForwardIterator
, class _Tp
>
101 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardIterator
>
102 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, const _Tp
& __value
) const noexcept
{
103 using _FindIf
= __dispatch
<__find_if
, __current_configuration
, _ExecutionPolicy
>;
105 __policy
, std::move(__first
), std::move(__last
), [&](__iter_reference
<_ForwardIterator
> __element
) {
106 return __element
== __value
;
111 template <class _ExecutionPolicy
>
112 struct __find_if_not
<__default_backend_tag
, _ExecutionPolicy
> {
113 template <class _Policy
, class _ForwardIterator
, class _Pred
>
114 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardIterator
>
115 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
) const noexcept
{
116 using _FindIf
= __dispatch
<__find_if
, __current_configuration
, _ExecutionPolicy
>;
117 return _FindIf()(__policy
, __first
, __last
, std::not_fn(std::forward
<_Pred
>(__pred
)));
121 template <class _ExecutionPolicy
>
122 struct __any_of
<__default_backend_tag
, _ExecutionPolicy
> {
123 template <class _Policy
, class _ForwardIterator
, class _Pred
>
124 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
125 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
) const noexcept
{
126 using _FindIf
= __dispatch
<__find_if
, __current_configuration
, _ExecutionPolicy
>;
127 auto __res
= _FindIf()(__policy
, __first
, __last
, std::forward
<_Pred
>(__pred
));
130 return *__res
!= __last
;
134 template <class _ExecutionPolicy
>
135 struct __all_of
<__default_backend_tag
, _ExecutionPolicy
> {
136 template <class _Policy
, class _ForwardIterator
, class _Pred
>
137 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
138 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
) const noexcept
{
139 using _AnyOf
= __dispatch
<__any_of
, __current_configuration
, _ExecutionPolicy
>;
140 auto __res
= _AnyOf()(__policy
, __first
, __last
, [&](__iter_reference
<_ForwardIterator
> __value
) {
141 return !__pred(__value
);
149 template <class _ExecutionPolicy
>
150 struct __none_of
<__default_backend_tag
, _ExecutionPolicy
> {
151 template <class _Policy
, class _ForwardIterator
, class _Pred
>
152 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
153 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
) const noexcept
{
154 using _AnyOf
= __dispatch
<__any_of
, __current_configuration
, _ExecutionPolicy
>;
155 auto __res
= _AnyOf()(__policy
, __first
, __last
, std::forward
<_Pred
>(__pred
));
162 template <class _ExecutionPolicy
>
163 struct __is_partitioned
<__default_backend_tag
, _ExecutionPolicy
> {
164 template <class _Policy
, class _ForwardIterator
, class _Pred
>
165 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
166 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
) const noexcept
{
167 using _FindIfNot
= __dispatch
<__find_if_not
, __current_configuration
, _ExecutionPolicy
>;
168 auto __maybe_first
= _FindIfNot()(__policy
, std::move(__first
), __last
, __pred
);
169 if (__maybe_first
== nullopt
)
172 __first
= *__maybe_first
;
173 if (__first
== __last
)
176 using _NoneOf
= __dispatch
<__none_of
, __current_configuration
, _ExecutionPolicy
>;
177 return _NoneOf()(__policy
, std::move(__first
), std::move(__last
), __pred
);
181 //////////////////////////////////////////////////////////////
183 //////////////////////////////////////////////////////////////
184 template <class _ExecutionPolicy
>
185 struct __for_each_n
<__default_backend_tag
, _ExecutionPolicy
> {
186 template <class _Policy
, class _ForwardIterator
, class _Size
, class _Function
>
187 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
188 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _Size __size
, _Function __func
) const noexcept
{
189 if constexpr (__has_random_access_iterator_category_or_concept
<_ForwardIterator
>::value
) {
190 using _ForEach
= __dispatch
<__for_each
, __current_configuration
, _ExecutionPolicy
>;
191 _ForwardIterator __last
= __first
+ __size
;
192 return _ForEach()(__policy
, std::move(__first
), std::move(__last
), std::move(__func
));
194 // Otherwise, use the serial algorithm to avoid doing two passes over the input
195 std::for_each_n(std::move(__first
), __size
, std::move(__func
));
201 template <class _ExecutionPolicy
>
202 struct __fill
<__default_backend_tag
, _ExecutionPolicy
> {
203 template <class _Policy
, class _ForwardIterator
, class _Tp
>
204 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
205 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Tp
const& __value
) const noexcept
{
206 using _ForEach
= __dispatch
<__for_each
, __current_configuration
, _ExecutionPolicy
>;
207 using _Ref
= __iter_reference
<_ForwardIterator
>;
208 return _ForEach()(__policy
, std::move(__first
), std::move(__last
), [&](_Ref __element
) { __element
= __value
; });
212 template <class _ExecutionPolicy
>
213 struct __fill_n
<__default_backend_tag
, _ExecutionPolicy
> {
214 template <class _Policy
, class _ForwardIterator
, class _Size
, class _Tp
>
215 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
216 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _Size __n
, _Tp
const& __value
) const noexcept
{
217 if constexpr (__has_random_access_iterator_category_or_concept
<_ForwardIterator
>::value
) {
218 using _Fill
= __dispatch
<__fill
, __current_configuration
, _ExecutionPolicy
>;
219 _ForwardIterator __last
= __first
+ __n
;
220 return _Fill()(__policy
, std::move(__first
), std::move(__last
), __value
);
222 // Otherwise, use the serial algorithm to avoid doing two passes over the input
223 std::fill_n(std::move(__first
), __n
, __value
);
224 return optional
<__empty
>{__empty
{}};
229 template <class _ExecutionPolicy
>
230 struct __replace
<__default_backend_tag
, _ExecutionPolicy
> {
231 template <class _Policy
, class _ForwardIterator
, class _Tp
>
232 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
233 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Tp
const& __old
, _Tp
const& __new
)
235 using _ReplaceIf
= __dispatch
<__replace_if
, __current_configuration
, _ExecutionPolicy
>;
236 using _Ref
= __iter_reference
<_ForwardIterator
>;
238 __policy
, std::move(__first
), std::move(__last
), [&](_Ref __element
) { return __element
== __old
; }, __new
);
242 template <class _ExecutionPolicy
>
243 struct __replace_if
<__default_backend_tag
, _ExecutionPolicy
> {
244 template <class _Policy
, class _ForwardIterator
, class _Pred
, class _Tp
>
245 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
> operator()(
246 _Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Pred
&& __pred
, _Tp
const& __new_value
)
248 using _ForEach
= __dispatch
<__for_each
, __current_configuration
, _ExecutionPolicy
>;
249 using _Ref
= __iter_reference
<_ForwardIterator
>;
250 return _ForEach()(__policy
, std::move(__first
), std::move(__last
), [&](_Ref __element
) {
251 if (__pred(__element
))
252 __element
= __new_value
;
257 template <class _ExecutionPolicy
>
258 struct __generate
<__default_backend_tag
, _ExecutionPolicy
> {
259 template <class _Policy
, class _ForwardIterator
, class _Generator
>
260 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
261 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Generator
&& __gen
) const noexcept
{
262 using _ForEach
= __dispatch
<__for_each
, __current_configuration
, _ExecutionPolicy
>;
263 using _Ref
= __iter_reference
<_ForwardIterator
>;
264 return _ForEach()(__policy
, std::move(__first
), std::move(__last
), [&](_Ref __element
) { __element
= __gen(); });
268 template <class _ExecutionPolicy
>
269 struct __generate_n
<__default_backend_tag
, _ExecutionPolicy
> {
270 template <class _Policy
, class _ForwardIterator
, class _Size
, class _Generator
>
271 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
272 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _Size __n
, _Generator
&& __gen
) const noexcept
{
273 using _ForEachN
= __dispatch
<__for_each_n
, __current_configuration
, _ExecutionPolicy
>;
274 using _Ref
= __iter_reference
<_ForwardIterator
>;
275 return _ForEachN()(__policy
, std::move(__first
), __n
, [&](_Ref __element
) { __element
= __gen(); });
279 //////////////////////////////////////////////////////////////
280 // stable_sort family
281 //////////////////////////////////////////////////////////////
282 template <class _ExecutionPolicy
>
283 struct __sort
<__default_backend_tag
, _ExecutionPolicy
> {
284 template <class _Policy
, class _RandomAccessIterator
, class _Comp
>
285 _LIBCPP_HIDE_FROM_ABI optional
<__empty
> operator()(
286 _Policy
&& __policy
, _RandomAccessIterator __first
, _RandomAccessIterator __last
, _Comp
&& __comp
) const noexcept
{
287 using _StableSort
= __dispatch
<__stable_sort
, __current_configuration
, _ExecutionPolicy
>;
288 return _StableSort()(__policy
, std::move(__first
), std::move(__last
), std::forward
<_Comp
>(__comp
));
292 //////////////////////////////////////////////////////////////
293 // transform_reduce family
294 //////////////////////////////////////////////////////////////
295 template <class _ExecutionPolicy
>
296 struct __count_if
<__default_backend_tag
, _ExecutionPolicy
> {
297 template <class _Policy
, class _ForwardIterator
, class _Predicate
>
298 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__iter_diff_t
<_ForwardIterator
>> operator()(
299 _Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Predicate
&& __pred
) const noexcept
{
300 using _TransformReduce
= __dispatch
<__transform_reduce
, __current_configuration
, _ExecutionPolicy
>;
301 using _DiffT
= __iter_diff_t
<_ForwardIterator
>;
302 using _Ref
= __iter_reference
<_ForwardIterator
>;
303 return _TransformReduce()(
304 __policy
, std::move(__first
), std::move(__last
), _DiffT
{}, std::plus
{}, [&](_Ref __element
) -> _DiffT
{
305 return __pred(__element
) ? _DiffT(1) : _DiffT(0);
310 template <class _ExecutionPolicy
>
311 struct __count
<__default_backend_tag
, _ExecutionPolicy
> {
312 template <class _Policy
, class _ForwardIterator
, class _Tp
>
313 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__iter_diff_t
<_ForwardIterator
>>
314 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Tp
const& __value
) const noexcept
{
315 using _CountIf
= __dispatch
<__count_if
, __current_configuration
, _ExecutionPolicy
>;
316 using _Ref
= __iter_reference
<_ForwardIterator
>;
317 return _CountIf()(__policy
, std::move(__first
), std::move(__last
), [&](_Ref __element
) -> bool {
318 return __element
== __value
;
323 template <class _ExecutionPolicy
>
324 struct __equal_3leg
<__default_backend_tag
, _ExecutionPolicy
> {
325 template <class _Policy
, class _ForwardIterator1
, class _ForwardIterator2
, class _Predicate
>
326 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
327 operator()(_Policy
&& __policy
,
328 _ForwardIterator1 __first1
,
329 _ForwardIterator1 __last1
,
330 _ForwardIterator2 __first2
,
331 _Predicate
&& __pred
) const noexcept
{
332 using _TransformReduce
= __dispatch
<__transform_reduce_binary
, __current_configuration
, _ExecutionPolicy
>;
333 return _TransformReduce()(
340 std::forward
<_Predicate
>(__pred
));
344 template <class _ExecutionPolicy
>
345 struct __equal
<__default_backend_tag
, _ExecutionPolicy
> {
346 template <class _Policy
, class _ForwardIterator1
, class _ForwardIterator2
, class _Predicate
>
347 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<bool>
348 operator()(_Policy
&& __policy
,
349 _ForwardIterator1 __first1
,
350 _ForwardIterator1 __last1
,
351 _ForwardIterator2 __first2
,
352 _ForwardIterator2 __last2
,
353 _Predicate
&& __pred
) const noexcept
{
354 if constexpr (__has_random_access_iterator_category
<_ForwardIterator1
>::value
&&
355 __has_random_access_iterator_category
<_ForwardIterator2
>::value
) {
356 if (__last1
- __first1
!= __last2
- __first2
)
358 // Fall back to the 3 legged algorithm
359 using _Equal3Leg
= __dispatch
<__equal_3leg
, __current_configuration
, _ExecutionPolicy
>;
361 __policy
, std::move(__first1
), std::move(__last1
), std::move(__first2
), std::forward
<_Predicate
>(__pred
));
363 // If we don't have random access, fall back to the serial algorithm cause we can't do much
369 std::forward
<_Predicate
>(__pred
));
374 template <class _ExecutionPolicy
>
375 struct __reduce
<__default_backend_tag
, _ExecutionPolicy
> {
376 template <class _Policy
, class _ForwardIterator
, class _Tp
, class _BinaryOperation
>
377 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_Tp
>
378 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _Tp __init
, _BinaryOperation
&& __op
)
380 using _TransformReduce
= __dispatch
<__transform_reduce
, __current_configuration
, _ExecutionPolicy
>;
381 return _TransformReduce()(
386 std::forward
<_BinaryOperation
>(__op
),
391 //////////////////////////////////////////////////////////////
393 //////////////////////////////////////////////////////////////
394 template <class _ExecutionPolicy
>
395 struct __replace_copy_if
<__default_backend_tag
, _ExecutionPolicy
> {
396 template <class _Policy
, class _ForwardIterator
, class _ForwardOutIterator
, class _Pred
, class _Tp
>
397 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
398 operator()(_Policy
&& __policy
,
399 _ForwardIterator __first
,
400 _ForwardIterator __last
,
401 _ForwardOutIterator __out_it
,
403 _Tp
const& __new_value
) const noexcept
{
404 using _Transform
= __dispatch
<__transform
, __current_configuration
, _ExecutionPolicy
>;
405 using _Ref
= __iter_reference
<_ForwardIterator
>;
407 _Transform()(__policy
, std::move(__first
), std::move(__last
), std::move(__out_it
), [&](_Ref __element
) {
408 return __pred(__element
) ? __new_value
: __element
;
410 if (__res
== nullopt
)
416 template <class _ExecutionPolicy
>
417 struct __replace_copy
<__default_backend_tag
, _ExecutionPolicy
> {
418 template <class _Policy
, class _ForwardIterator
, class _ForwardOutIterator
, class _Tp
>
419 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<__empty
>
420 operator()(_Policy
&& __policy
,
421 _ForwardIterator __first
,
422 _ForwardIterator __last
,
423 _ForwardOutIterator __out_it
,
424 _Tp
const& __old_value
,
425 _Tp
const& __new_value
) const noexcept
{
426 using _ReplaceCopyIf
= __dispatch
<__replace_copy_if
, __current_configuration
, _ExecutionPolicy
>;
427 using _Ref
= __iter_reference
<_ForwardIterator
>;
428 return _ReplaceCopyIf()(
433 [&](_Ref __element
) { return __element
== __old_value
; },
438 // TODO: Use the std::copy/move shenanigans to forward to std::memmove
439 // Investigate whether we want to still forward to std::transform(policy)
440 // in that case for the execution::par part, or whether we actually want
441 // to run everything serially in that case.
442 template <class _ExecutionPolicy
>
443 struct __move
<__default_backend_tag
, _ExecutionPolicy
> {
444 template <class _Policy
, class _ForwardIterator
, class _ForwardOutIterator
>
445 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardOutIterator
>
446 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _ForwardOutIterator __out_it
)
448 using _Transform
= __dispatch
<__transform
, __current_configuration
, _ExecutionPolicy
>;
449 return _Transform()(__policy
, std::move(__first
), std::move(__last
), std::move(__out_it
), [&](auto&& __element
) {
450 return std::move(__element
);
455 // TODO: Use the std::copy/move shenanigans to forward to std::memmove
456 template <class _ExecutionPolicy
>
457 struct __copy
<__default_backend_tag
, _ExecutionPolicy
> {
458 template <class _Policy
, class _ForwardIterator
, class _ForwardOutIterator
>
459 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardOutIterator
>
460 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _ForwardIterator __last
, _ForwardOutIterator __out_it
)
462 using _Transform
= __dispatch
<__transform
, __current_configuration
, _ExecutionPolicy
>;
463 return _Transform()(__policy
, std::move(__first
), std::move(__last
), std::move(__out_it
), __identity());
467 template <class _ExecutionPolicy
>
468 struct __copy_n
<__default_backend_tag
, _ExecutionPolicy
> {
469 template <class _Policy
, class _ForwardIterator
, class _Size
, class _ForwardOutIterator
>
470 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardOutIterator
>
471 operator()(_Policy
&& __policy
, _ForwardIterator __first
, _Size __n
, _ForwardOutIterator __out_it
) const noexcept
{
472 if constexpr (__has_random_access_iterator_category_or_concept
<_ForwardIterator
>::value
) {
473 using _Copy
= __dispatch
<__copy
, __current_configuration
, _ExecutionPolicy
>;
474 _ForwardIterator __last
= __first
+ __n
;
475 return _Copy()(__policy
, std::move(__first
), std::move(__last
), std::move(__out_it
));
477 // Otherwise, use the serial algorithm to avoid doing two passes over the input
478 return std::copy_n(std::move(__first
), __n
, std::move(__out_it
));
483 template <class _ExecutionPolicy
>
484 struct __rotate_copy
<__default_backend_tag
, _ExecutionPolicy
> {
485 template <class _Policy
, class _ForwardIterator
, class _ForwardOutIterator
>
486 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI optional
<_ForwardOutIterator
>
487 operator()(_Policy
&& __policy
,
488 _ForwardIterator __first
,
489 _ForwardIterator __middle
,
490 _ForwardIterator __last
,
491 _ForwardOutIterator __out_it
) const noexcept
{
492 using _Copy
= __dispatch
<__copy
, __current_configuration
, _ExecutionPolicy
>;
493 auto __result_mid
= _Copy()(__policy
, __middle
, std::move(__last
), std::move(__out_it
));
494 if (__result_mid
== nullopt
)
496 return _Copy()(__policy
, std::move(__first
), std::move(__middle
), *std::move(__result_mid
));
500 } // namespace __pstl
501 _LIBCPP_END_NAMESPACE_STD
503 #endif // _LIBCPP_STD_VER >= 17
507 #endif // _LIBCPP___PSTL_BACKENDS_DEFAULT_H