Skip to content

Commit 7da63ea

Browse files
authored
[oneDPL] Add parallel range algorithms (#569)
1 parent 89d1dc7 commit 7da63ea

File tree

2 files changed

+333
-1
lines changed

2 files changed

+333
-1
lines changed

source/elements/oneDPL/source/parallel_api.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.. SPDX-FileCopyrightText: 2019-2022 Intel Corporation
2+
.. SPDX-FileCopyrightText: Contributors to the oneAPI Specification project.
23
..
34
.. SPDX-License-Identifier: CC-BY-4.0
45
@@ -10,6 +11,9 @@ including parallel algorithms added in the 6th edition known as C++20.
1011
All those algorithms work with *C++ Standard aligned execution policies* and with
1112
*device execution policies*.
1213

14+
oneDPL also provides *parallel range algorithms*: variations of C++20 range-based algorithms
15+
that take a oneDPL execution policy.
16+
1317
Additionally, oneDPL provides wrapper functions for `SYCL`_ buffers, special iterators, and
1418
a set of non-standard parallel algorithms.
1519

@@ -20,6 +24,7 @@ a set of non-standard parallel algorithms.
2024
parallel_api/buffer_wrappers.rst
2125
parallel_api/iterators.rst
2226
parallel_api/algorithms.rst
23-
27+
parallel_api/parallel_range_api.rst
28+
2429
.. _`C++ Standard`: https://isocpp.org/std/the-standard
2530
.. _`SYCL`: https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
.. SPDX-FileCopyrightText: Contributors to the oneAPI Specification project.
2+
..
3+
.. SPDX-License-Identifier: CC-BY-4.0
4+
5+
Parallel Range Algorithms
6+
-------------------------
7+
8+
oneDPL provides variations of algorithms that work with ranges defined in the `C++ Standard`_, 6th edition (C++20)
9+
and newer. These algorithms execute according to a oneDPL execution policy supplied as the first argument,
10+
similarly to other oneDPL algorithms.
11+
12+
The oneDPL parallel range algorithms rely on the functionality of C++20 and are not available in the code
13+
compiled for earlier editions of the C++ standard.
14+
15+
The parallel range algorithms reside in ``namespace oneapi::dpl::ranges``. Same as the range algorithm functions
16+
defined by the C++ standard in ``namespace std::ranges``, they cannot be found by argument-dependent name lookup
17+
and cannot be called with explicitly specified template arguments. [*Note*: A typical implementation uses
18+
predefined function objects which static function call operators have the required signatures. -- *end note*]
19+
20+
The following differences to the standard C++ range algorithms apply:
21+
22+
- Parallel range algorithms cannot be used in constant expressions.
23+
- The execution policy parameter is added.
24+
- Output data sequences are defined as ranges, not iterators.
25+
- Both input and output ranges must support random access.
26+
- For a given algorithm, at least one of the input ranges as well as the output range must be bounded.
27+
- ``for_each`` does not return its function object.
28+
29+
Except for these differences, the signatures of parallel range algorithms correspond to the working draft
30+
of the next edition of the C++ standard (C++26).
31+
32+
Whole Sequence Operations
33+
+++++++++++++++++++++++++
34+
35+
.. code:: cpp
36+
37+
// Defined in <oneapi/dpl/algorithm>
38+
39+
namespace oneapi::dpl::ranges {
40+
41+
// all_of
42+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
43+
typename Proj = std::identity,
44+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
45+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
46+
std::ranges::sized_range<R>
47+
bool all_of (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
48+
49+
// any_of
50+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
51+
typename Proj = std::identity,
52+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
53+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
54+
std::ranges::sized_range<R>
55+
bool any_of (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
56+
57+
// none_of
58+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
59+
typename Proj = std::identity,
60+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
61+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
62+
std::ranges::sized_range<R>
63+
bool none_of (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
64+
65+
// for_each
66+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
67+
typename Proj = std::identity,
68+
std::indirectly_unary_invocable< std::projected<std::ranges::iterator_t<R>, Proj> > Fn>
69+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
70+
std::ranges::sized_range<R>
71+
std::ranges::borrowed_iterator_t<R>
72+
for_each (ExecutionPolicy&& pol, R&& r, Fn f, Proj proj = {});
73+
74+
// count
75+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
76+
typename Proj = std::identity,
77+
typename T = std::projected_value_t<std::ranges::iterator_t<R>, Proj>>
78+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
79+
std::ranges::sized_range<R> &&
80+
std::indirect_binary_predicate< std::ranges::equal_to,
81+
std::projected<std::ranges::iterator_t<R>, Proj>,
82+
const T* >
83+
std::ranges::range_difference_t<R>
84+
count (ExecutionPolicy&& pol, R&& r, const T& value, Proj proj = {});
85+
86+
// count_if
87+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
88+
typename Proj = std::identity,
89+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
90+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
91+
std::ranges::sized_range<R>
92+
std::ranges::range_difference_t<R>
93+
count_if (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
94+
95+
}
96+
97+
Element Search Operations
98+
+++++++++++++++++++++++++
99+
100+
.. code:: cpp
101+
102+
// Defined in <oneapi/dpl/algorithm>
103+
104+
namespace oneapi::dpl::ranges {
105+
106+
// find
107+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
108+
typename Proj = std::identity,
109+
typename T = std::projected_value_t<std::ranges::iterator_t<R>, Proj>>
110+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
111+
std::ranges::sized_range<R> &&
112+
std::indirect_binary_predicate< std::ranges::equal_to,
113+
std::projected<std::ranges::iterator_t<R>, Proj>,
114+
const T* >
115+
std::ranges::borrowed_iterator_t<R>
116+
find (ExecutionPolicy&& pol, R&& r, const T& value, Proj proj = {});
117+
118+
// find_if
119+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
120+
typename Proj = std::identity,
121+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
122+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
123+
std::ranges::sized_range<R>
124+
std::ranges::borrowed_iterator_t<R>
125+
find_if (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
126+
127+
// find_if_not
128+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
129+
typename Proj = std::identity,
130+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
131+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
132+
std::ranges::sized_range<R>
133+
std::ranges::borrowed_iterator_t<R>
134+
find_if_not (ExecutionPolicy&& pol, R&& r, Pred pred, Proj proj = {});
135+
136+
// adjacent_find
137+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
138+
typename Proj = std::identity,
139+
std::indirect_binary_predicate< std::projected<std::ranges::iterator_t<R>, Proj>,
140+
std::projected<std::ranges::iterator_t<R>, Proj> >
141+
Pred = std::ranges::equal_to>
142+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
143+
std::ranges::sized_range<R>
144+
std::ranges::borrowed_iterator_t<R>
145+
adjacent_find (ExecutionPolicy&& pol, R&& r, Pred pred = {}, Proj proj = {});
146+
147+
// min_element
148+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
149+
typename Proj = std::identity,
150+
std::indirect_strict_weak_order< std::projected<std::ranges::iterator_t<R>, Proj> >
151+
Comp = std::ranges::less>
152+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
153+
std::ranges::sized_range<R>
154+
std::ranges::borrowed_iterator_t<R>
155+
min_element (ExecutionPolicy&& pol, R&& r, Comp comp = {}, Proj proj = {});
156+
157+
// max_element
158+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
159+
typename Proj = std::identity,
160+
std::indirect_strict_weak_order< std::projected<std::ranges::iterator_t<R>, Proj> >
161+
Comp = std::ranges::less>
162+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
163+
std::ranges::sized_range<R>
164+
std::ranges::borrowed_iterator_t<R>
165+
max_element (ExecutionPolicy&& pol, R&& r, Comp comp = {}, Proj proj = {});
166+
167+
}
168+
169+
Sequence Search and Comparison
170+
++++++++++++++++++++++++++++++
171+
172+
.. code:: cpp
173+
174+
// Defined in <oneapi/dpl/algorithm>
175+
176+
namespace oneapi::dpl::ranges {
177+
178+
// equal
179+
template<typename ExecutionPolicy, std::ranges::random_access_range R1,
180+
std::ranges::random_access_range R2, typename Pred = std::ranges::equal_to,
181+
typename Proj1 = std::identity, typename Proj2 = std::identity>
182+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
183+
(std::ranges::sized_range<R1> || std::ranges::sized_range<R2>) &&
184+
std::indirectly_comparable< std::ranges::iterator_t<R1>, std::ranges::iterator_t<R2>,
185+
Pred, Proj1, Proj2 >
186+
bool equal (ExecutionPolicy&& pol, R1&& r1, R2&& r2, Pred pred = {},
187+
Proj1 proj1 = {}, Proj2 proj2 = {});
188+
189+
// search
190+
template<typename ExecutionPolicy, std::ranges::random_access_range R1,
191+
std::ranges::random_access_range R2, typename Pred = std::ranges::equal_to,
192+
typename Proj1 = std::identity, typename Proj2 = std::identity>
193+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
194+
std::ranges::sized_range<R1> && std::ranges::sized_range<R2> &&
195+
std::indirectly_comparable< std::ranges::iterator_t<R1>, std::ranges::iterator_t<R2>,
196+
Pred, Proj1, Proj2 >
197+
std::ranges::borrowed_subrange_t<R1>
198+
search (ExecutionPolicy&& pol, R1&& r1, R2&& r2, Pred pred = {},
199+
Proj1 proj1 = {}, Proj2 proj2 = {});
200+
201+
// search_n
202+
template<typename ExecutionPolicy, std::ranges::random_access_range R,
203+
typename Pred = std::ranges::equal_to, typename Proj = std::identity,
204+
typename T = std::projected_value_t<std::ranges::iterator_t<R>, Proj>>
205+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
206+
std::ranges::sized_range<R> &&
207+
std::indirectly_comparable< std::ranges::iterator_t<R>, const T*, Pred, Proj >
208+
std::ranges::borrowed_subrange_t<R>
209+
search_n (ExecutionPolicy&& pol, R&& r, std::ranges::range_difference_t<R> count,
210+
const T& value, Pred pred = {}, Proj proj = {});
211+
212+
}
213+
214+
Sorting and Merge
215+
+++++++++++++++++
216+
217+
.. code:: cpp
218+
219+
// Defined in <oneapi/dpl/algorithm>
220+
221+
namespace oneapi::dpl::ranges {
222+
223+
// sort
224+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
225+
typename Comp = std::ranges::less, typename Proj = std::identity>
226+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
227+
std::ranges::sized_range<R> && std::sortable<std::ranges::iterator_t<R>, Comp, Proj>
228+
std::ranges::borrowed_iterator_t<R>
229+
sort (ExecutionPolicy&& pol, R&& r, Comp comp = {}, Proj proj = {});
230+
231+
// stable_sort
232+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
233+
typename Comp = std::ranges::less, typename Proj = std::identity>
234+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
235+
std::ranges::sized_range<R> && std::sortable<std::ranges::iterator_t<R>, Comp, Proj>
236+
std::ranges::borrowed_iterator_t<R>
237+
stable_sort (ExecutionPolicy&& pol, R&& r, Comp comp = {}, Proj proj = {});
238+
239+
// is_sorted
240+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
241+
typename Proj = std::identity,
242+
std::indirect_strict_weak_order< std::projected<std::ranges::iterator_t<R>, Proj> >
243+
Comp = std::ranges::less>
244+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
245+
std::ranges::sized_range<R>
246+
bool is_sorted (ExecutionPolicy&& pol, R&& r, Comp comp = {}, Proj proj = {});
247+
248+
// merge
249+
template <typename ExecutionPolicy, std::ranges::random_access_range R1,
250+
std::ranges::random_access_range R2, std::ranges::random_access_range OutR,
251+
typename Comp = std::ranges::less, typename Proj1 = std::identity,
252+
typename Proj2 = std::identity>
253+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
254+
std::ranges::sized_range<R1> && std::ranges::sized_range<R2> &&
255+
std::ranges::sized_range<OutR> &&
256+
std::mergeable<std::ranges::iterator_t<R1>, std::ranges::iterator_t<R2>,
257+
std::ranges::iterator_t<OutR>, Comp, Proj1, Proj2>
258+
std::ranges::merge_result<std::ranges::borrowed_iterator_t<R1>,
259+
std::ranges::borrowed_iterator_t<R2>,
260+
std::ranges::borrowed_iterator_t<OutR>>
261+
merge (R1&& r1, R2&& r2, OutR&& result, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
262+
263+
}
264+
265+
Mutating Operations
266+
+++++++++++++++++++
267+
268+
.. code:: cpp
269+
270+
// Defined in <oneapi/dpl/algorithm>
271+
272+
namespace oneapi::dpl::ranges {
273+
274+
// copy
275+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
276+
std::ranges::random_access_range OutR>
277+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
278+
std::ranges::sized_range<R> && std::ranges::sized_range<OutR> &&
279+
std::indirectly_copyable<std::ranges::iterator_t<R>, std::ranges::iterator_t<OutR>>
280+
std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>,
281+
std::ranges::borrowed_iterator_t<OutR>>
282+
copy (ExecutionPolicy&& pol, R&& r, OutR&& result);
283+
284+
// copy_if
285+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
286+
std::ranges::random_access_range OutR, typename Proj = std::identity,
287+
std::indirect_unary_predicate< std::projected<std::ranges::iterator_t<R>, Proj> > Pred>
288+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
289+
std::ranges::sized_range<R> && std::ranges::sized_range<OutR> &&
290+
std::indirectly_copyable<std::ranges::iterator_t<R>, std::ranges::iterator_t<OutR>>
291+
std::ranges::copy_if_result<std::ranges::borrowed_iterator_t<R>,
292+
std::ranges::borrowed_iterator_t<OutR>>
293+
copy_if (ExecutionPolicy&& pol, R&& r, OutR&& result, Pred pred, Proj proj = {});
294+
295+
// transform (unary)
296+
template <typename ExecutionPolicy, std::ranges::random_access_range R,
297+
std::ranges::random_access_range OutR, std::copy_constructible Fn,
298+
typename Proj = std::identity>
299+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
300+
std::ranges::sized_range<R> && std::ranges::sized_range<OutR> &&
301+
std::indirectly_writable< std::ranges::iterator_t<OutR>,
302+
std::indirect_result_t<Fn&, std::projected<std::ranges::iterator_t<R>, Proj>> >
303+
std::ranges::unary_transform_result<std::ranges::borrowed_iterator_t<R>,
304+
std::ranges::borrowed_iterator_t<OutR>>
305+
transform (ExecutionPolicy&& pol, R&& r, OutR&& result, Fn unary_op, Proj proj = {});
306+
307+
// transform (binary)
308+
template <typename ExecutionPolicy, std::ranges::random_access_range R1,
309+
std::ranges::random_access_range R2, std::ranges::random_access_range OutR,
310+
std::copy_constructible Fn, typename Proj1 = std::identity,
311+
typename Proj2 = std::identity>
312+
requires oneapi::dpl::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> &&
313+
(std::ranges::sized_range<R1> || std::ranges::sized_range<R2>) &&
314+
std::ranges::sized_range<OutR> &&
315+
std::indirectly_writable< std::ranges::iterator_t<OutR>,
316+
std::indirect_result_t<Fn&, std::projected<std::ranges::iterator_t<R1>, Proj1>,
317+
std::projected<std::ranges::iterator_t<R2>, Proj2>> >
318+
std::ranges::binary_transform_result<std::ranges::borrowed_iterator_t<R1>,
319+
std::ranges::borrowed_iterator_t<R2>,
320+
std::ranges::borrowed_iterator_t<OutR>>
321+
transform (ExecutionPolicy&& pol, R1&& r1, R2&& r2, OutR&& result, Fn binary_op,
322+
Proj1 proj1 = {}, Proj2 proj2 = {});
323+
324+
}
325+
326+
.. _`C++ Standard`: https://isocpp.org/std/the-standard
327+
.. _`SYCL`: https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html

0 commit comments

Comments
 (0)