From Jason Turner

[exec.bulk]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpnje2zog8/{from.md → to.md} +193 -0
tmp/tmpnje2zog8/{from.md → to.md} RENAMED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #### `execution::bulk`, `execution::bulk_chunked`, and `execution::bulk_unchunked` <a id="exec.bulk">[[exec.bulk]]</a>
2
+
3
+ `bulk`, `bulk_chunked`, and `bulk_unchunked` run a task repeatedly for
4
+ every index in an index space.
5
+
6
+ The names `bulk`, `bulk_chunked`, and `bulk_unchunked` denote pipeable
7
+ sender adaptor objects. Let `bulk-algo` be either `bulk`,
8
+ `bulk_chunked`, or `bulk_unchunked`. For subexpressions `sndr`,
9
+ `policy`, `shape`, and `f`, let `Policy` be
10
+ `remove_cvref_t<decltype(policy)>`, `Shape` be `decltype(auto(shape))`,
11
+ and `Func` be `decay_t<decltype((f))>`. If
12
+
13
+ - `decltype((sndr))` does not satisfy `sender`, or
14
+ - `is_execution_policy_v<Policy>` is `false`, or
15
+ - `Shape` does not satisfy `integral`, or
16
+ - `Func` does not model `copy_constructible`,
17
+
18
+ `bulk-algo(sndr, policy, shape, f)` is ill-formed.
19
+
20
+ Otherwise, the expression `bulk-algo(sndr, policy, shape, f)` is
21
+ expression-equivalent to:
22
+
23
+ ``` cpp
24
+ transform_sender(get-domain-early(sndr), make-sender(
25
+ bulk-algo, product-type<see below, Shape, Func>{policy, shape, f}, sndr))
26
+ ```
27
+
28
+ except that `sndr` is evaluated only once. The first template argument
29
+ of *`product-type`* is `Policy` if `Policy` models `copy_constructible`,
30
+ and `const Policy&` otherwise.
31
+
32
+ Let `sndr` and `env` be subexpressions such that `Sndr` is
33
+ `decltype((sndr))`. If `sender-for<Sndr, bulk_t>` is `false`, then the
34
+ expression `bulk.transform_sender(sndr, env)` is ill-formed; otherwise,
35
+ it is equivalent to:
36
+
37
+ ``` cpp
38
+ auto [_, data, child] = sndr;
39
+ auto& [policy, shape, f] = data;
40
+ auto new_f = [func = std::move(f)](Shape begin, Shape end, auto&&... vs)
41
+ noexcept(noexcept(f(begin, vs...))) {
42
+ while (begin != end) func(begin++, vs...);
43
+ }
44
+ return bulk_chunked(std::move(child), policy, shape, std::move(new_f));
45
+ ```
46
+
47
+ [*Note 1*: This causes the `bulk(sndr, policy, shape, f)` sender to be
48
+ expressed in terms of `bulk_chunked(sndr, policy, shape, f)` when it is
49
+ connected to a receiver whose execution domain does not customize
50
+ `bulk`. — *end note*]
51
+
52
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
53
+ specialized for `bulk_chunked_t` as follows:
54
+
55
+ ``` cpp
56
+ namespace std::execution {
57
+ template<>
58
+ struct impls-for<bulk_chunked_t> : default-impls {
59
+ static constexpr auto complete = see below;
60
+
61
+ template<class Sndr, class... Env>
62
+ static consteval void check-types();
63
+ };
64
+ }
65
+ ```
66
+
67
+ The member `impls-for<bulk_chunked_t>::complete` is initialized with a
68
+ callable object equivalent to the following lambda:
69
+
70
+ ``` cpp
71
+ []<class Index, class State, class Rcvr, class Tag, class... Args>
72
+ (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
73
+ -> void requires see below {
74
+ if constexpr (same_as<Tag, set_value_t>) {
75
+ auto& [policy, shape, f] = state;
76
+ constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...));
77
+ TRY-EVAL(rcvr, [&]() noexcept(nothrow) {
78
+ f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
79
+ Tag()(std::move(rcvr), std::forward<Args>(args)...);
80
+ }());
81
+ } else {
82
+ Tag()(std::move(rcvr), std::forward<Args>(args)...);
83
+ }
84
+ }
85
+ ```
86
+
87
+ The expression in the *requires-clause* of the lambda above is `true` if
88
+ and only if `Tag` denotes a type other than `set_value_t` or if the
89
+ expression `f(auto(shape), auto(shape), args...)` is well-formed.
90
+
91
+ The exposition-only class template *`impls-for`* [[exec.snd.expos]] is
92
+ specialized for `bulk_unchunked_t` as follows:
93
+
94
+ ``` cpp
95
+ namespace std::execution {
96
+ template<>
97
+ struct impls-for<bulk_unchunked_t> : default-impls {
98
+ static constexpr auto complete = see below;
99
+ };
100
+ }
101
+ ```
102
+
103
+ The member `impls-for<bulk_unchunked_t>::complete` is initialized with a
104
+ callable object equivalent to the following lambda:
105
+
106
+ ``` cpp
107
+ []<class Index, class State, class Rcvr, class Tag, class... Args>
108
+ (Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept
109
+ -> void requires see below {
110
+ if constexpr (same_as<Tag, set_value_t>) {
111
+ auto& [policy, shape, f] = state;
112
+ constexpr bool nothrow = noexcept(f(auto(shape), args...));
113
+ TRY-EVAL(rcvr, [&]() noexcept(nothrow) {
114
+ for (decltype(auto(shape)) i = 0; i < shape; ++i) {
115
+ f(auto(i), args...);
116
+ }
117
+ Tag()(std::move(rcvr), std::forward<Args>(args)...);
118
+ }());
119
+ } else {
120
+ Tag()(std::move(rcvr), std::forward<Args>(args)...);
121
+ }
122
+ }
123
+ ```
124
+
125
+ The expression in the *requires-clause* of the lambda above is `true` if
126
+ and only if `Tag` denotes a type other than `set_value_t` or if the
127
+ expression `f(auto(shape), args...)` is well-formed.
128
+
129
+ ``` cpp
130
+ template<class Sndr, class... Env>
131
+ static consteval void check-types();
132
+ ```
133
+
134
+ *Effects:* Equivalent to:
135
+
136
+ ``` cpp
137
+ auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>();
138
+ auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {
139
+ if constexpr (!invocable<remove_cvref_t<data-type<Sndr>>, Ts&...>)
140
+ throw unspecified-exception();
141
+ };
142
+ cs.for-each(overload-set(fn, [](auto){}));
143
+ ```
144
+
145
+ where *`unspecified-exception`* is a type derived from `exception`.
146
+
147
+ Let the subexpression `out_sndr` denote the result of the invocation
148
+ `bulk-algo(sndr, policy, shape, f)` or an object equal to such, and let
149
+ the subexpression `rcvr` denote a receiver such that the expression
150
+ `connect(out_sndr, rcvr)` is well-formed. The expression
151
+ `connect(out_sndr, rcvr)` has undefined behavior unless it creates an
152
+ asynchronous operation [[exec.async.ops]] that, when started:
153
+
154
+ - If `sndr` has a successful completion, where `args` is a pack of
155
+ lvalue subexpressions referring to the value completion result datums
156
+ of `sndr`, or decayed copies of those values if they model
157
+ `copy_constructible`, then:
158
+ - If `out_sndr` also completes successfully, then:
159
+ - for `bulk`, invokes `f(i, args...)` for every i of type `Shape`
160
+ from `0` to `shape`;
161
+ - for `bulk_unchunked`, invokes `f(i, args...)` for every i of type
162
+ `Shape` from `0` to `shape`; *Recommended practice:* The
163
+ underlying scheduler should execute each iteration on a distinct
164
+ execution agent.
165
+ - for `bulk_chunked`, invokes `f(b, e, args...)` zero or more times
166
+ with pairs of b and e of type `Shape` in range \[`0`, `shape`\],
167
+ such that b < e and for every i of type `Shape` from `0` to
168
+ `shape`, there is exactly one invocation with a pair b and e, such
169
+ that i is in the range \[b, e).
170
+ - If `out_sndr` completes with `set_error(rcvr, eptr)`, then the
171
+ asynchronous operation may invoke a subset of the invocations of `f`
172
+ before the error completion handler is called, and `eptr` is an
173
+ `exception_ptr` containing either:
174
+ - an exception thrown by an invocation of `f`, or
175
+ - a `bad_alloc` exception if the implementation fails to allocate
176
+ required resources, or
177
+ - an exception derived from `runtime_error`.
178
+ - If `out_sndr` completes with `set_stopped(rcvr)`, then the
179
+ asynchronous operation may invoke a subset of the invocations of `f`
180
+ before the stopped completion handler.
181
+ - If `sndr` does not complete with `set_value`, then the completion is
182
+ forwarded to `recv`.
183
+ - For `bulk-algo`, the parameter `policy` describes the manner in which
184
+ the execution of the asynchronous operations corresponding to these
185
+ algorithms may be parallelized and the manner in which they apply `f`.
186
+ Permissions and requirements on parallel algorithm element access
187
+ functions [[algorithms.parallel.exec]] apply to `f`.
188
+
189
+ [*Note 2*: The asynchronous operation corresponding to
190
+ `bulk-algo(sndr, policy, shape, f)` can complete with `set_stopped` if
191
+ cancellation is requested or ignore cancellation
192
+ requests. — *end note*]
193
+