1 | //===----------------------------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef _LIBCPP___PSTL_BACKENDS_DEFAULT_H |
10 | #define _LIBCPP___PSTL_BACKENDS_DEFAULT_H |
11 | |
12 | #include <__algorithm/copy_n.h> |
13 | #include <__algorithm/equal.h> |
14 | #include <__algorithm/fill_n.h> |
15 | #include <__algorithm/for_each_n.h> |
16 | #include <__config> |
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> |
27 | #include <optional> |
28 | |
29 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
30 | # pragma GCC system_header |
31 | #endif |
32 | |
33 | _LIBCPP_PUSH_MACROS |
34 | #include <__undef_macros> |
35 | |
36 | #if _LIBCPP_STD_VER >= 17 |
37 | |
38 | _LIBCPP_BEGIN_NAMESPACE_STD |
39 | namespace __pstl { |
40 | |
41 | // |
42 | // This file provides an incomplete PSTL backend that implements all of the PSTL algorithms |
43 | // based on a smaller set of basis operations. |
44 | // |
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. |
47 | // |
48 | // This backend implements all the PSTL algorithms based on the following basis operations: |
49 | // |
50 | // find_if family |
51 | // -------------- |
52 | // - find |
53 | // - find_if_not |
54 | // - any_of |
55 | // - all_of |
56 | // - none_of |
57 | // - is_partitioned |
58 | // |
59 | // for_each family |
60 | // --------------- |
61 | // - for_each_n |
62 | // - fill |
63 | // - fill_n |
64 | // - replace |
65 | // - replace_if |
66 | // - generate |
67 | // - generate_n |
68 | // |
69 | // merge family |
70 | // ------------ |
71 | // No other algorithms based on merge |
72 | // |
73 | // stable_sort family |
74 | // ------------------ |
75 | // - sort |
76 | // |
77 | // transform_reduce and transform_reduce_binary family |
78 | // --------------------------------------------------- |
79 | // - count_if |
80 | // - count |
81 | // - equal(3 legs) |
82 | // - equal |
83 | // - reduce |
84 | // |
85 | // transform and transform_binary family |
86 | // ------------------------------------- |
87 | // - replace_copy_if |
88 | // - replace_copy |
89 | // - move |
90 | // - copy |
91 | // - copy_n |
92 | // - rotate_copy |
93 | // |
94 | |
95 | ////////////////////////////////////////////////////////////// |
96 | // find_if family |
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>; |
104 | return _FindIf()( |
105 | __policy, std::move(__first), std::move(__last), [&](__iter_reference<_ForwardIterator> __element) { |
106 | return __element == __value; |
107 | }); |
108 | } |
109 | }; |
110 | |
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))); |
118 | } |
119 | }; |
120 | |
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)); |
128 | if (!__res) |
129 | return nullopt; |
130 | return *__res != __last; |
131 | } |
132 | }; |
133 | |
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); |
142 | }); |
143 | if (!__res) |
144 | return nullopt; |
145 | return !*__res; |
146 | } |
147 | }; |
148 | |
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)); |
156 | if (!__res) |
157 | return nullopt; |
158 | return !*__res; |
159 | } |
160 | }; |
161 | |
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) |
170 | return nullopt; |
171 | |
172 | __first = *__maybe_first; |
173 | if (__first == __last) |
174 | return true; |
175 | ++__first; |
176 | using _NoneOf = __dispatch<__none_of, __current_configuration, _ExecutionPolicy>; |
177 | return _NoneOf()(__policy, std::move(__first), std::move(__last), __pred); |
178 | } |
179 | }; |
180 | |
181 | ////////////////////////////////////////////////////////////// |
182 | // for_each family |
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)); |
193 | } else { |
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)); |
196 | return __empty{}; |
197 | } |
198 | } |
199 | }; |
200 | |
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; }); |
209 | } |
210 | }; |
211 | |
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); |
221 | } else { |
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{}}; |
225 | } |
226 | } |
227 | }; |
228 | |
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) |
234 | const noexcept { |
235 | using _ReplaceIf = __dispatch<__replace_if, __current_configuration, _ExecutionPolicy>; |
236 | using _Ref = __iter_reference<_ForwardIterator>; |
237 | return _ReplaceIf()( |
238 | __policy, std::move(__first), std::move(__last), [&](_Ref __element) { return __element == __old; }, __new); |
239 | } |
240 | }; |
241 | |
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) |
247 | const noexcept { |
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; |
253 | }); |
254 | } |
255 | }; |
256 | |
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(); }); |
265 | } |
266 | }; |
267 | |
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(); }); |
276 | } |
277 | }; |
278 | |
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)); |
289 | } |
290 | }; |
291 | |
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); |
306 | }); |
307 | } |
308 | }; |
309 | |
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; |
319 | }); |
320 | } |
321 | }; |
322 | |
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()( |
334 | __policy, |
335 | std::move(__first1), |
336 | std::move(__last1), |
337 | std::move(__first2), |
338 | true, |
339 | std::logical_and{}, |
340 | std::forward<_Predicate>(__pred)); |
341 | } |
342 | }; |
343 | |
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) |
357 | return false; |
358 | // Fall back to the 3 legged algorithm |
359 | using _Equal3Leg = __dispatch<__equal_3leg, __current_configuration, _ExecutionPolicy>; |
360 | return _Equal3Leg()( |
361 | __policy, std::move(__first1), std::move(__last1), std::move(__first2), std::forward<_Predicate>(__pred)); |
362 | } else { |
363 | // If we don't have random access, fall back to the serial algorithm cause we can't do much |
364 | return std::equal( |
365 | std::move(__first1), |
366 | std::move(__last1), |
367 | std::move(__first2), |
368 | std::move(__last2), |
369 | std::forward<_Predicate>(__pred)); |
370 | } |
371 | } |
372 | }; |
373 | |
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) |
379 | const noexcept { |
380 | using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>; |
381 | return _TransformReduce()( |
382 | __policy, |
383 | std::move(__first), |
384 | std::move(__last), |
385 | std::move(__init), |
386 | std::forward<_BinaryOperation>(__op), |
387 | __identity{}); |
388 | } |
389 | }; |
390 | |
391 | ////////////////////////////////////////////////////////////// |
392 | // transform family |
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, |
402 | _Pred&& __pred, |
403 | _Tp const& __new_value) const noexcept { |
404 | using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>; |
405 | using _Ref = __iter_reference<_ForwardIterator>; |
406 | auto __res = |
407 | _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](_Ref __element) { |
408 | return __pred(__element) ? __new_value : __element; |
409 | }); |
410 | if (__res == nullopt) |
411 | return nullopt; |
412 | return __empty{}; |
413 | } |
414 | }; |
415 | |
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()( |
429 | __policy, |
430 | std::move(__first), |
431 | std::move(__last), |
432 | std::move(__out_it), |
433 | [&](_Ref __element) { return __element == __old_value; }, |
434 | __new_value); |
435 | } |
436 | }; |
437 | |
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) |
447 | const noexcept { |
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); |
451 | }); |
452 | } |
453 | }; |
454 | |
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) |
461 | const noexcept { |
462 | using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>; |
463 | return _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), __identity()); |
464 | } |
465 | }; |
466 | |
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)); |
476 | } else { |
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)); |
479 | } |
480 | } |
481 | }; |
482 | |
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) |
495 | return nullopt; |
496 | return _Copy()(__policy, std::move(__first), std::move(__middle), *std::move(__result_mid)); |
497 | } |
498 | }; |
499 | |
500 | } // namespace __pstl |
501 | _LIBCPP_END_NAMESPACE_STD |
502 | |
503 | #endif // _LIBCPP_STD_VER >= 17 |
504 | |
505 | _LIBCPP_POP_MACROS |
506 | |
507 | #endif // _LIBCPP___PSTL_BACKENDS_DEFAULT_H |
508 | |