3
3
..
4
4
.. SPDX-License-Identifier: CC-BY-4.0
5
5
6
+ .. _iterators :
7
+
6
8
Iterators
7
9
---------
8
10
11
+ Requirements For Iterator Use With Device Policies
12
+ ++++++++++++++++++++++++++++++++++++++++++++++++++
13
+ Iterators and iterator-like types may or may not refer to content accessible within a `SYCL `_ kernel on a device.
14
+ The term *indirectly device accessible * refers to a type that represents content accessible on a device.
15
+ An *indirectly device accessible iterator * is such a type that can also be dereferenced within a SYCL kernel.
16
+
17
+ An example of indirectly device accessible iterators include SYCL USM shared pointers which can inherently be used in
18
+ a SYCL kernel. An example of an iterator type that is not indirectly device accessible is a random access iterator
19
+ referring to host allocated data because dereferencing it within a SYCL kernel would result in undefined behavior.
20
+
21
+ :doc: `Buffer position objects <buffer_wrappers >` returned by ``oneapi::dpl::begin `` and ``oneapi::dpl::end `` are not
22
+ iterators. However, they are indirectly device accessible because they represent data accessible on the device.
23
+
24
+ When passed to oneDPL algorithms with a ``device_policy ``, indirectly device accessible iterator types that are also
25
+ random access iterators and satisfy *SYCL device-copyable * must not cause unnecessary data movement beyond what is
26
+ required by the algorithm's semantics and what would be required to use the type directly within a SYCL kernel.
27
+ Indirectly device accessible buffer position objects must not cause unnecessary data movement beyond what is
28
+ required by the algorithm's semantics and what would be required by using an accessor to the buffer within a SYCL
29
+ kernel.
30
+
31
+ Indirect Device Accessibility Type Trait
32
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33
+
34
+ The following class template and variable template are defined in ``<oneapi/dpl/iterator> `` inside the namespace
35
+ ``oneapi::dpl ``:
36
+
37
+ .. code :: cpp
38
+
39
+ template <typename T>
40
+ struct is_indirectly_device_accessible{ /* see below */ };
41
+
42
+ template <typename T>
43
+ inline constexpr bool is_indirectly_device_accessible_v = is_indirectly_device_accessible<T>::value;
44
+
45
+ ``template <typename T> oneapi::dpl::is_indirectly_device_accessible `` is a type which has the base characteristic
46
+ of ``std::true_type `` if ``T `` is indirectly device accessible. Otherwise, it has the base characteristic of
47
+ ``std::false_type ``.
48
+
49
+ oneDPL Iterators
50
+ ++++++++++++++++
51
+
9
52
The oneDPL iterators are defined in the ``<oneapi/dpl/iterator> `` header,
10
53
in ``namespace oneapi::dpl ``.
11
54
@@ -64,6 +107,8 @@ counter; dereference operations cannot be used to modify the counter. The arithm
64
107
operators of ``counting_iterator `` behave as if applied to the values of Integral type
65
108
representing the counters of the iterator instances passed to the operators.
66
109
110
+ ``counting_iterator `` is SYCL device-copyable, and is an indirectly device accessible iterator.
111
+
67
112
.. code :: cpp
68
113
69
114
class discard_iterator
@@ -104,6 +149,8 @@ lvalue that may be assigned an arbitrary value. The assignment has no effect on
104
149
of ``discard_iterator `` behave as if applied to integer counter values maintained by the
105
150
iterator instances to determine their position relative to each other.
106
151
152
+ ``discard_iterator `` is SYCL device-copyable, and is an indirectly device accessible iterator.
153
+
107
154
.. code :: cpp
108
155
109
156
template <typename SourceIterator, typename IndexMap>
@@ -150,8 +197,14 @@ defined by the source iterator provided, and whose iteration order over the dere
150
197
is defined by either another iterator or a functor that maps the ``permutation_iterator `` index
151
198
to the index of the source iterator. The arithmetic and comparison operators of
152
199
``permutation_iterator `` behave as if applied to integer counter values maintained by the
153
- iterator instances to determine their position in the index map. ``SourceIterator `` must satisfy
154
- ``AdaptingIteratorSource ``.
200
+ iterator instances to determine their position in the index map.
201
+
202
+ ``permutation_iterator `` is SYCL device-copyable if both the ``SourceIterator `` and the ``IndexMap ``
203
+ are SYCL device-copyable. ``permutation_iterator `` is indirectly device accessible if both the
204
+ ``SourceIterator `` and the ``IndexMap `` are indirectly device accessible.
205
+
206
+ ``SourceIterator `` must satisfy ``AdaptingIteratorSource ``. When using ``permutation_iterator `` in combination with an
207
+ algorithm with a ``device_policy ``, ``SourceIterator `` must be indirectly device accessible.
155
208
156
209
The type ``IndexMap `` must be one of the following:
157
210
@@ -163,7 +216,6 @@ The type ``IndexMap`` must be one of the following:
163
216
* A functor with a signature equivalent to ``T operator()(const T&) const `` where ``T `` is a
164
217
``std::iterator_traits<SourceIterator>::difference_type ``
165
218
166
-
167
219
``permutation_iterator::operator* `` uses the counter value of the instance on which
168
220
it is invoked to index into the index map. The corresponding value in the map is then used
169
221
to index into the value set defined by the source iterator. The resulting lvalue is returned
@@ -234,6 +286,9 @@ arithmetic and comparison operators of ``transform_iterator`` behave as if appli
234
286
source iterator itself. The template type ``Iterator `` must satisfy
235
287
``AdaptingIteratorSource ``.
236
288
289
+ ``transform_iterator `` is SYCL device-copyable if the source iterator is SYCL device-copyable, and
290
+ is indirectly device accessible if the source iterator is indirectly device accessible.
291
+
237
292
.. code :: cpp
238
293
239
294
template <typename UnaryFunc, typename Iterator>
@@ -293,6 +348,9 @@ source iterators over which the ``zip_iterator`` is defined. The arithmetic oper
293
348
operation were applied to each of these iterators. The types ``T `` within the template pack
294
349
``Iterators... `` must satisfy ``AdaptingIteratorSource ``.
295
350
351
+ ``zip_iterator `` is SYCL device-copyable if all the source iterators are SYCL device-copyable, and is indirectly
352
+ device accessible if all the source iterators are indirectly device accessible.
353
+
296
354
.. code :: cpp
297
355
298
356
template <typename... Iterators>
@@ -301,3 +359,85 @@ operation were applied to each of these iterators. The types ``T`` within the te
301
359
302
360
``make_zip_iterator `` constructs and returns an instance of ``zip_iterator ``
303
361
using the set of source iterators provided.
362
+
363
+ Other Iterators
364
+ +++++++++++++++
365
+ Pointers are assumed to be USM shared or device memory pointers when used in combination with an algorithm with a
366
+ ``device_policy `` and are indirectly device accessible. Pointers are trivially copyable and therefore SYCL
367
+ device-copyable.
368
+
369
+ It is implementation defined whether other iterators are indirectly device accessible, including iterator types from
370
+ the `C++ Standard `_.
371
+
372
+ .. _iterators-device-accessible :
373
+
374
+ Customization For User Defined Iterators
375
+ ++++++++++++++++++++++++++++++++++++++++
376
+ oneDPL provides a mechanism to indicate whether custom iterators are indirectly device accessible.
377
+
378
+ Applications may define a free function ``is_onedpl_indirectly_device_accessible(T) ``, which accepts an argument of
379
+ type ``T `` and returns a type with the base characteristic of ``std::true_type `` if ``T `` is indirectly device
380
+ accessible. Otherwise, it returns a type with the base characteristic of ``std::false_type ``. The function must be
381
+ discoverable by argument-dependent lookup (ADL). It may be provided as a forward declaration only, without defining a
382
+ body.
383
+
384
+ The return type of ``is_onedpl_indirectly_device_accessible `` is examined at compile time to determine if ``T `` is
385
+ indirectly device accessible. The function overload to use must be selected with argument-dependent lookup.
386
+ [*Note *: Therefore, according to the rules in the C++ Standard, a derived type for which there is no
387
+ function overload will match its most specific base type for which an overload exists. -- *end note *]
388
+
389
+ Once ``is_onedpl_indirectly_device_accessible(T) `` is defined, the public trait
390
+ ``template<typename T> oneapi::dpl::is_indirectly_device_accessible[_v] `` will return the appropriate value. This public
391
+ trait can also be used to define the return type of ``is_onedpl_indirectly_device_accessible(T) `` by applying it to any
392
+ source iterator component types. Refer to the example below.
393
+
394
+ Example
395
+ ^^^^^^^
396
+
397
+ The following example shows how to define a customization for ``is_indirectly_device_accessible `` trait for a simple
398
+ user defined iterator. It also shows a more complicated example where the customization is defined as a hidden friend
399
+ of the iterator class.
400
+
401
+ .. code :: cpp
402
+
403
+ namespace usr
404
+ {
405
+ struct accessible_it
406
+ {
407
+ /* user definition of an indirectly device accessible iterator */
408
+ };
409
+
410
+ std::true_type
411
+ is_onedpl_indirectly_device_accessible(accessible_it);
412
+
413
+ struct inaccessible_it
414
+ {
415
+ /* user definition of an iterator which is not indirectly device accessible */
416
+ };
417
+
418
+ // The following could be omitted, as returning std::false_type matches the default behavior.
419
+ std::false_type
420
+ is_onedpl_indirectly_device_accessible(inaccessible_it);
421
+ }
422
+
423
+ static_assert(oneapi::dpl::is_indirectly_device_accessible<usr::accessible_it> == true);
424
+ static_assert(oneapi::dpl::is_indirectly_device_accessible<usr::inaccessible_it> == false);
425
+
426
+ // Example with base iterators and ADL overload as a hidden friend
427
+ template <typename It1, typename It2>
428
+ struct it_pair
429
+ {
430
+ It1 first;
431
+ It2 second;
432
+ friend auto is_onedpl_indirectly_device_accessible(it_pair) ->
433
+ std::conjunction<oneapi::dpl::is_indirectly_device_accessible<It1>,
434
+ oneapi::dpl::is_indirectly_device_accessible<It2>>;
435
+ };
436
+
437
+ static_assert(oneapi::dpl::is_indirectly_device_accessible<
438
+ it_pair<usr::accessible_it, usr::accessible_it>> == true);
439
+ static_assert(oneapi::dpl::is_indirectly_device_accessible<
440
+ it_pair<usr::accessible_it, usr::inaccessible_it>> == false);
441
+
442
+ .. _`C++ Standard` : https://isocpp.org/std/the-standard
443
+ .. _`SYCL` : https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html
0 commit comments