Skip to content

Commit 6851d07

Browse files
committed
[libc++][PSTL] Implement std::transform
Reviewed By: ldionne, #libc Spies: libcxx-commits Differential Revision: https://reviews.llvm.org/D149615
1 parent cc7dc90 commit 6851d07

File tree

13 files changed

+388
-44
lines changed

13 files changed

+388
-44
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,12 @@ set(files
7878
__algorithm/pstl_backends/cpu_backends/find_if.h
7979
__algorithm/pstl_backends/cpu_backends/for_each.h
8080
__algorithm/pstl_backends/cpu_backends/serial.h
81+
__algorithm/pstl_backends/cpu_backends/transform.h
8182
__algorithm/pstl_fill.h
8283
__algorithm/pstl_find.h
8384
__algorithm/pstl_for_each.h
8485
__algorithm/pstl_frontend_dispatch.h
86+
__algorithm/pstl_transform.h
8587
__algorithm/push_heap.h
8688
__algorithm/ranges_adjacent_find.h
8789
__algorithm/ranges_all_of.h

libcxx/include/__algorithm/pstl_backend.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
3232
template <class _ExecutionPolicy, class _Iterator, class _Predicate>
3333
_Iterator __pstl_find_if(_Backend, _Iterator __first, _Iterator __last, _Predicate __pred);
3434
35+
template <class _ExecutionPolicy, class _InIterator, class _OutIterator, class _UnaryOperation>
36+
_OutIterator __pstl_transform(_InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op);
37+
38+
template <class _ExecutionPolicy, class _InIterator1, class _InIterator2, class _OutIterator, class _BinaryOperation>
39+
_OutIterator __pstl_transform(_InIterator1 __first1,
40+
_InIterator1 __last1,
41+
_InIterator2 __first2,
42+
_OutIterator __result,
43+
_BinaryOperation __op);
44+
3545
// TODO: Complete this list
3646
3747
The following functions are optional but can be provided. If provided, they are used by the corresponding

libcxx/include/__algorithm/pstl_backends/cpu_backend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@
2727
#include <__algorithm/pstl_backends/cpu_backends/fill.h>
2828
#include <__algorithm/pstl_backends/cpu_backends/find_if.h>
2929
#include <__algorithm/pstl_backends/cpu_backends/for_each.h>
30+
#include <__algorithm/pstl_backends/cpu_backends/transform.h>
3031

3132
#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKEND_H
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H
10+
#define _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H
11+
12+
#include <__algorithm/pstl_backends/cpu_backends/backend.h>
13+
#include <__algorithm/transform.h>
14+
#include <__config>
15+
#include <__iterator/iterator_traits.h>
16+
#include <__type_traits/enable_if.h>
17+
#include <__type_traits/is_execution_policy.h>
18+
#include <__type_traits/remove_cvref.h>
19+
#include <__utility/terminate_on_exception.h>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
26+
27+
_LIBCPP_BEGIN_NAMESPACE_STD
28+
29+
template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Function>
30+
_LIBCPP_HIDE_FROM_ABI _Iterator2
31+
__simd_walk_2(_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Function __f) noexcept {
32+
_PSTL_PRAGMA_SIMD
33+
for (_DifferenceType __i = 0; __i < __n; ++__i)
34+
__f(__first1[__i], __first2[__i]);
35+
return __first2 + __n;
36+
}
37+
38+
template <class _ExecutionPolicy, class _ForwardIterator, class _ForwardOutIterator, class _UnaryOperation>
39+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
40+
__cpu_backend_tag,
41+
_ForwardIterator __first,
42+
_ForwardIterator __last,
43+
_ForwardOutIterator __result,
44+
_UnaryOperation __op) {
45+
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
46+
__is_cpp17_random_access_iterator<_ForwardIterator>::value &&
47+
__is_cpp17_random_access_iterator<_ForwardOutIterator>::value) {
48+
std::__terminate_on_exception([&] {
49+
std::__par_backend::__parallel_for(
50+
__first, __last, [__op, __first, __result](_ForwardIterator __brick_first, _ForwardIterator __brick_last) {
51+
return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
52+
__cpu_backend_tag{}, __brick_first, __brick_last, __result + (__brick_first - __first), __op);
53+
});
54+
});
55+
return __result + (__last - __first);
56+
} else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
57+
__is_cpp17_random_access_iterator<_ForwardIterator>::value &&
58+
__is_cpp17_random_access_iterator<_ForwardOutIterator>::value) {
59+
return std::__simd_walk_2(
60+
__first,
61+
__last - __first,
62+
__result,
63+
[&](__iter_reference<_ForwardIterator> __in_value, __iter_reference<_ForwardOutIterator> __out_value) {
64+
__out_value = __op(__in_value);
65+
});
66+
} else {
67+
return std::transform(__first, __last, __result, __op);
68+
}
69+
}
70+
71+
template <class _Iterator1, class _DifferenceType, class _Iterator2, class _Iterator3, class _Function>
72+
_LIBCPP_HIDE_FROM_ABI _Iterator3 __simd_walk_3(
73+
_Iterator1 __first1, _DifferenceType __n, _Iterator2 __first2, _Iterator3 __first3, _Function __f) noexcept {
74+
_PSTL_PRAGMA_SIMD
75+
for (_DifferenceType __i = 0; __i < __n; ++__i)
76+
__f(__first1[__i], __first2[__i], __first3[__i]);
77+
return __first3 + __n;
78+
}
79+
template <class _ExecutionPolicy,
80+
class _ForwardIterator1,
81+
class _ForwardIterator2,
82+
class _ForwardOutIterator,
83+
class _BinaryOperation,
84+
enable_if_t<is_execution_policy_v<__remove_cvref_t<_ExecutionPolicy>>, int> = 0>
85+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator __pstl_transform(
86+
__cpu_backend_tag,
87+
_ForwardIterator1 __first1,
88+
_ForwardIterator1 __last1,
89+
_ForwardIterator2 __first2,
90+
_ForwardOutIterator __result,
91+
_BinaryOperation __op) {
92+
if constexpr (__is_parallel_execution_policy_v<_ExecutionPolicy> &&
93+
__is_cpp17_random_access_iterator<_ForwardIterator1>::value &&
94+
__is_cpp17_random_access_iterator<_ForwardIterator2>::value &&
95+
__is_cpp17_random_access_iterator<_ForwardOutIterator>::value) {
96+
std::__terminate_on_exception([&] {
97+
std::__par_backend::__parallel_for(
98+
__first1,
99+
__last1,
100+
[__op, __first1, __first2, __result](_ForwardIterator1 __brick_first, _ForwardIterator1 __brick_last) {
101+
return std::__pstl_transform<__remove_parallel_policy_t<_ExecutionPolicy>>(
102+
__cpu_backend_tag{},
103+
__brick_first,
104+
__brick_last,
105+
__first2 + (__brick_first - __first1),
106+
__result + (__brick_first - __first1),
107+
__op);
108+
});
109+
});
110+
return __result + (__last1 - __first1);
111+
} else if constexpr (__is_unsequenced_execution_policy_v<_ExecutionPolicy> &&
112+
__is_cpp17_random_access_iterator<_ForwardIterator1>::value &&
113+
__is_cpp17_random_access_iterator<_ForwardIterator2>::value &&
114+
__is_cpp17_random_access_iterator<_ForwardOutIterator>::value) {
115+
return std::__simd_walk_3(
116+
__first1,
117+
__last1 - __first1,
118+
__first2,
119+
__result,
120+
[&](__iter_reference<_ForwardIterator1> __in1,
121+
__iter_reference<_ForwardIterator2> __in2,
122+
__iter_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); });
123+
} else {
124+
return std::transform(__first1, __last1, __first2, __result, __op);
125+
}
126+
}
127+
128+
_LIBCPP_END_NAMESPACE_STD
129+
130+
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
131+
132+
#endif // _LIBCPP___ALGORITHM_PSTL_BACKENDS_CPU_BACKENDS_TRANSFORM_H
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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___ALGORITHM_PSTL_TRANSFORM_H
10+
#define _LIBCPP___ALGORITHM_PSTL_TRANSFORM_H
11+
12+
#include <__algorithm/pstl_backend.h>
13+
#include <__config>
14+
#include <__iterator/iterator_traits.h>
15+
#include <__type_traits/is_execution_policy.h>
16+
#include <__utility/terminate_on_exception.h>
17+
18+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19+
# pragma GCC system_header
20+
#endif
21+
22+
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
23+
24+
_LIBCPP_BEGIN_NAMESPACE_STD
25+
26+
template <class _ExecutionPolicy,
27+
class _ForwardIterator,
28+
class _ForwardOutIterator,
29+
class _UnaryOperation,
30+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
31+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
32+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
33+
_ExecutionPolicy&&,
34+
_ForwardIterator __first,
35+
_ForwardIterator __last,
36+
_ForwardOutIterator __result,
37+
_UnaryOperation __op) {
38+
using _Backend = typename __select_backend<_RawPolicy>::type;
39+
return std::__pstl_transform<_RawPolicy>(
40+
_Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op));
41+
}
42+
43+
template <class _ExecutionPolicy,
44+
class _ForwardIterator1,
45+
class _ForwardIterator2,
46+
class _ForwardOutIterator,
47+
class _BinaryOperation,
48+
class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>,
49+
enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0>
50+
_LIBCPP_HIDE_FROM_ABI _ForwardOutIterator transform(
51+
_ExecutionPolicy&&,
52+
_ForwardIterator1 __first1,
53+
_ForwardIterator1 __last1,
54+
_ForwardIterator2 __first2,
55+
_ForwardOutIterator __result,
56+
_BinaryOperation __op) {
57+
using _Backend = typename __select_backend<_RawPolicy>::type;
58+
return std::__pstl_transform<_RawPolicy>(
59+
_Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op));
60+
}
61+
62+
_LIBCPP_END_NAMESPACE_STD
63+
64+
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_PSTL) && _LIBCPP_STD_VER >= 17
65+
66+
#endif // _LIBCPP___ALGORITHM_PSTL_TRANSFORM_H

libcxx/include/__pstl/internal/glue_algorithm_defs.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -134,29 +134,6 @@ template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterato
134134
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2> swap_ranges(
135135
_ExecutionPolicy&& __exec, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2);
136136

137-
// [alg.transform]
138-
139-
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryOperation>
140-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
141-
transform(_ExecutionPolicy&& __exec,
142-
_ForwardIterator1 __first,
143-
_ForwardIterator1 __last,
144-
_ForwardIterator2 __result,
145-
_UnaryOperation __op);
146-
147-
template <class _ExecutionPolicy,
148-
class _ForwardIterator1,
149-
class _ForwardIterator2,
150-
class _ForwardIterator,
151-
class _BinaryOperation>
152-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator>
153-
transform(_ExecutionPolicy&& __exec,
154-
_ForwardIterator1 __first1,
155-
_ForwardIterator1 __last1,
156-
_ForwardIterator2 __first2,
157-
_ForwardIterator __result,
158-
_BinaryOperation __op);
159-
160137
// [alg.replace]
161138

162139
template <class _ExecutionPolicy, class _ForwardIterator, class _UnaryPredicate, class _Tp>

libcxx/include/__pstl/internal/glue_algorithm_impl.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -251,27 +251,6 @@ __pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardItera
251251

252252
// [alg.transform]
253253

254-
template <class _ExecutionPolicy, class _ForwardIterator1, class _ForwardIterator2, class _UnaryOperation>
255-
__pstl::__internal::__enable_if_execution_policy<_ExecutionPolicy, _ForwardIterator2>
256-
transform(_ExecutionPolicy&& __exec,
257-
_ForwardIterator1 __first,
258-
_ForwardIterator1 __last,
259-
_ForwardIterator2 __result,
260-
_UnaryOperation __op) {
261-
typedef typename iterator_traits<_ForwardIterator1>::reference _InputType;
262-
typedef typename iterator_traits<_ForwardIterator2>::reference _OutputType;
263-
264-
auto __dispatch_tag = __pstl::__internal::__select_backend(__exec, __first, __result);
265-
266-
return __pstl::__internal::__pattern_walk2(
267-
__dispatch_tag,
268-
std::forward<_ExecutionPolicy>(__exec),
269-
__first,
270-
__last,
271-
__result,
272-
[__op](_InputType __x, _OutputType __y) mutable { __y = __op(__x); });
273-
}
274-
275254
template <class _ExecutionPolicy,
276255
class _ForwardIterator1,
277256
class _ForwardIterator2,

libcxx/include/algorithm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,7 @@ template <class BidirectionalIterator, class Compare>
17921792
#include <__algorithm/pstl_fill.h>
17931793
#include <__algorithm/pstl_find.h>
17941794
#include <__algorithm/pstl_for_each.h>
1795+
#include <__algorithm/pstl_transform.h>
17951796
#include <__algorithm/push_heap.h>
17961797
#include <__algorithm/ranges_adjacent_find.h>
17971798
#include <__algorithm/ranges_all_of.h>

libcxx/include/module.modulemap.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ module std [system] {
341341
module pstl_backends_cpu_backends_serial {
342342
private header "__algorithm/pstl_backends/cpu_backends/serial.h"
343343
}
344+
module pstl_backends_cpu_backends_transform {
345+
private header "__algorithm/pstl_backends/cpu_backends/transform.h"
346+
}
344347
module push_heap { private header "__algorithm/push_heap.h" }
345348
module ranges_adjacent_find { private header "__algorithm/ranges_adjacent_find.h" }
346349
module ranges_all_of { private header "__algorithm/ranges_all_of.h" }

libcxx/test/libcxx/private_headers.verify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ END-SCRIPT
121121
#include <__algorithm/pstl_backends/cpu_backends/find_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/find_if.h'}}
122122
#include <__algorithm/pstl_backends/cpu_backends/for_each.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/for_each.h'}}
123123
#include <__algorithm/pstl_backends/cpu_backends/serial.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/serial.h'}}
124+
#include <__algorithm/pstl_backends/cpu_backends/transform.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/pstl_backends/cpu_backends/transform.h'}}
124125
#include <__algorithm/push_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/push_heap.h'}}
125126
#include <__algorithm/ranges_adjacent_find.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_adjacent_find.h'}}
126127
#include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}

0 commit comments

Comments
 (0)