xref: /freebsd-src/contrib/llvm-project/libcxx/include/__pstl/cpu_algos/transform.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_CPU_ALGOS_TRANSFORM_H
10*0fca6ea1SDimitry Andric #define _LIBCPP___PSTL_CPU_ALGOS_TRANSFORM_H
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #include <__algorithm/transform.h>
13*0fca6ea1SDimitry Andric #include <__assert>
14*0fca6ea1SDimitry Andric #include <__config>
15*0fca6ea1SDimitry Andric #include <__iterator/concepts.h>
16*0fca6ea1SDimitry Andric #include <__iterator/iterator_traits.h>
17*0fca6ea1SDimitry Andric #include <__pstl/backend_fwd.h>
18*0fca6ea1SDimitry Andric #include <__pstl/cpu_algos/cpu_traits.h>
19*0fca6ea1SDimitry Andric #include <__type_traits/is_execution_policy.h>
20*0fca6ea1SDimitry Andric #include <__utility/move.h>
21*0fca6ea1SDimitry Andric #include <optional>
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24*0fca6ea1SDimitry Andric #  pragma GCC system_header
25*0fca6ea1SDimitry Andric #endif
26*0fca6ea1SDimitry Andric 
27*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS
28*0fca6ea1SDimitry Andric #include <__undef_macros>
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
31*0fca6ea1SDimitry Andric namespace __pstl {
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
34*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _Iterator2
35*0fca6ea1SDimitry Andric __simd_transform(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Function __f) noexcept {
36*0fca6ea1SDimitry Andric   _PSTL_PRAGMA_SIMD
37*0fca6ea1SDimitry Andric   for (_DifferenceType __i = 0; __i < __n; ++__i)
38*0fca6ea1SDimitry Andric     __f(__first1[__i], __first2[__i]);
39*0fca6ea1SDimitry Andric   return __first2 + __n;
40*0fca6ea1SDimitry Andric }
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Iterator3, class _Function>
43*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _Iterator3 __simd_transform(
44*0fca6ea1SDimitry Andric     _Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Iterator3 __first3, _Function __f) noexcept {
45*0fca6ea1SDimitry Andric   _PSTL_PRAGMA_SIMD
46*0fca6ea1SDimitry Andric   for (_DifferenceType __i = 0; __i < __n; ++__i)
47*0fca6ea1SDimitry Andric     __f(__first1[__i], __first2[__i], __first3[__i]);
48*0fca6ea1SDimitry Andric   return __first3 + __n;
49*0fca6ea1SDimitry Andric }
50*0fca6ea1SDimitry Andric 
51*0fca6ea1SDimitry Andric template <class _Backend, class _RawExecutionPolicy>
52*0fca6ea1SDimitry Andric struct __cpu_parallel_transform {
53*0fca6ea1SDimitry Andric   template <class _Policy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
54*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
55*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
56*0fca6ea1SDimitry Andric              _ForwardIterator __first,
57*0fca6ea1SDimitry Andric              _ForwardIterator __last,
58*0fca6ea1SDimitry Andric              _ForwardOutIterator __result,
59*0fca6ea1SDimitry Andric              _UnaryOperation __op) const noexcept {
60*0fca6ea1SDimitry Andric     if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
61*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
62*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
63*0fca6ea1SDimitry Andric       __cpu_traits<_Backend>::__for_each(
64*0fca6ea1SDimitry Andric           __first,
65*0fca6ea1SDimitry Andric           __last,
66*0fca6ea1SDimitry Andric           [&__policy, __op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
67*0fca6ea1SDimitry Andric             using _TransformUnseq = __pstl::__transform<_Backend, __remove_parallel_policy_t<_RawExecutionPolicy>>;
68*0fca6ea1SDimitry Andric             auto __res            = _TransformUnseq()(
69*0fca6ea1SDimitry Andric                 std::__remove_parallel_policy(__policy),
70*0fca6ea1SDimitry Andric                 __brick_first,
71*0fca6ea1SDimitry Andric                 __brick_last,
72*0fca6ea1SDimitry Andric                 __result + (__brick_first - __first),
73*0fca6ea1SDimitry Andric                 __op);
74*0fca6ea1SDimitry Andric             _LIBCPP_ASSERT_INTERNAL(__res, "unseq/seq should never try to allocate!");
75*0fca6ea1SDimitry Andric             return *std::move(__res);
76*0fca6ea1SDimitry Andric           });
77*0fca6ea1SDimitry Andric       return __result + (__last - __first);
78*0fca6ea1SDimitry Andric     } else if constexpr (__is_unsequenced_execution_policy_v<_RawExecutionPolicy> &&
79*0fca6ea1SDimitry Andric                          __has_random_access_iterator_category_or_concept<_ForwardIterator>::value &&
80*0fca6ea1SDimitry Andric                          __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
81*0fca6ea1SDimitry Andric       return __pstl::__simd_transform(
82*0fca6ea1SDimitry Andric           __first,
83*0fca6ea1SDimitry Andric           __last - __first,
84*0fca6ea1SDimitry Andric           __result,
85*0fca6ea1SDimitry Andric           [&](__iter_reference<_ForwardIterator> __in_value, __iter_reference<_ForwardOutIterator> __out_value) {
86*0fca6ea1SDimitry Andric             __out_value = __op(__in_value);
87*0fca6ea1SDimitry Andric           });
88*0fca6ea1SDimitry Andric     } else {
89*0fca6ea1SDimitry Andric       return std::transform(__first, __last, __result, __op);
90*0fca6ea1SDimitry Andric     }
91*0fca6ea1SDimitry Andric   }
92*0fca6ea1SDimitry Andric };
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric template <class _Backend, class _RawExecutionPolicy>
95*0fca6ea1SDimitry Andric struct __cpu_parallel_transform_binary {
96*0fca6ea1SDimitry Andric   template <class _Policy,
97*0fca6ea1SDimitry Andric             class _ForwardIterator1,
98*0fca6ea1SDimitry Andric             class _ForwardIterator2,
99*0fca6ea1SDimitry Andric             class _ForwardOutIterator,
100*0fca6ea1SDimitry Andric             class _BinaryOperation>
101*0fca6ea1SDimitry Andric   _LIBCPP_HIDE_FROM_ABI optional<_ForwardOutIterator>
102*0fca6ea1SDimitry Andric   operator()(_Policy&& __policy,
103*0fca6ea1SDimitry Andric              _ForwardIterator1 __first1,
104*0fca6ea1SDimitry Andric              _ForwardIterator1 __last1,
105*0fca6ea1SDimitry Andric              _ForwardIterator2 __first2,
106*0fca6ea1SDimitry Andric              _ForwardOutIterator __result,
107*0fca6ea1SDimitry Andric              _BinaryOperation __op) const noexcept {
108*0fca6ea1SDimitry Andric     if constexpr (__is_parallel_execution_policy_v<_RawExecutionPolicy> &&
109*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
110*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
111*0fca6ea1SDimitry Andric                   __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
112*0fca6ea1SDimitry Andric       auto __res = __cpu_traits<_Backend>::__for_each(
113*0fca6ea1SDimitry Andric           __first1,
114*0fca6ea1SDimitry Andric           __last1,
115*0fca6ea1SDimitry Andric           [&__policy, __op, __first1, __first2, __result](
116*0fca6ea1SDimitry Andric               _ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
117*0fca6ea1SDimitry Andric             using _TransformBinaryUnseq =
118*0fca6ea1SDimitry Andric                 __pstl::__transform_binary<_Backend, __remove_parallel_policy_t<_RawExecutionPolicy>>;
119*0fca6ea1SDimitry Andric             return _TransformBinaryUnseq()(
120*0fca6ea1SDimitry Andric                 std::__remove_parallel_policy(__policy),
121*0fca6ea1SDimitry Andric                 __brick_first,
122*0fca6ea1SDimitry Andric                 __brick_last,
123*0fca6ea1SDimitry Andric                 __first2 + (__brick_first - __first1),
124*0fca6ea1SDimitry Andric                 __result + (__brick_first - __first1),
125*0fca6ea1SDimitry Andric                 __op);
126*0fca6ea1SDimitry Andric           });
127*0fca6ea1SDimitry Andric       if (!__res)
128*0fca6ea1SDimitry Andric         return nullopt;
129*0fca6ea1SDimitry Andric       return __result + (__last1 - __first1);
130*0fca6ea1SDimitry Andric     } else if constexpr (__is_unsequenced_execution_policy_v<_RawExecutionPolicy> &&
131*0fca6ea1SDimitry Andric                          __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value &&
132*0fca6ea1SDimitry Andric                          __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value &&
133*0fca6ea1SDimitry Andric                          __has_random_access_iterator_category_or_concept<_ForwardOutIterator>::value) {
134*0fca6ea1SDimitry Andric       return __pstl::__simd_transform(
135*0fca6ea1SDimitry Andric           __first1,
136*0fca6ea1SDimitry Andric           __last1 - __first1,
137*0fca6ea1SDimitry Andric           __first2,
138*0fca6ea1SDimitry Andric           __result,
139*0fca6ea1SDimitry Andric           [&](__iter_reference<_ForwardIterator1> __in1,
140*0fca6ea1SDimitry Andric               __iter_reference<_ForwardIterator2> __in2,
141*0fca6ea1SDimitry Andric               __iter_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); });
142*0fca6ea1SDimitry Andric     } else {
143*0fca6ea1SDimitry Andric       return std::transform(__first1, __last1, __first2, __result, __op);
144*0fca6ea1SDimitry Andric     }
145*0fca6ea1SDimitry Andric   }
146*0fca6ea1SDimitry Andric };
147*0fca6ea1SDimitry Andric 
148*0fca6ea1SDimitry Andric } // namespace __pstl
149*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
150*0fca6ea1SDimitry Andric 
151*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS
152*0fca6ea1SDimitry Andric 
153*0fca6ea1SDimitry Andric #endif // _LIBCPP___PSTL_CPU_ALGOS_TRANSFORM_H
154