Files
cppdraft_translate/cppdraft/exec/bulk.md
2025-10-25 03:02:53 +03:00

223 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[exec.bulk]
# 33 Execution control library [[exec]](./#exec)
## 33.9 Senders [[exec.snd]](exec.snd#exec.bulk)
### 33.9.12 Sender adaptors [[exec.adapt]](exec.adapt#exec.bulk)
#### 33.9.12.11 execution::bulk, execution::bulk_chunked, and execution::bulk_unchunked [exec.bulk]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4109)
bulk, bulk_chunked, and bulk_unchunked run a task repeatedly for every index in an index space[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4113)
The names bulk, bulk_chunked, and bulk_unchunked denote pipeable sender adaptor objects[.](#2.sentence-1)
Let *bulk-algo* be eitherbulk, bulk_chunked, or bulk_unchunked[.](#2.sentence-2)
For subexpressions sndr, policy, shape, and f,
letPolicy be remove_cvref_t<decltype(policy)>,Shape be decltype(auto(shape)), andFunc be decay_t<decltype((f))>[.](#2.sentence-3)
If
- [(2.1)](#2.1)
decltype((sndr)) does not satisfy [sender](exec.snd.concepts#concept:sender "33.9.3Sender concepts[exec.snd.concepts]"), or
- [(2.2)](#2.2)
is_execution_policy_v<Policy> is false, or
- [(2.3)](#2.3)
Shape does not satisfy [integral](concepts.arithmetic#concept:integral "18.4.7Arithmetic concepts[concepts.arithmetic]"), or
- [(2.4)](#2.4)
Func does not model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]"),
*bulk-algo*(sndr, policy, shape, f) is ill-formed[.](#2.sentence-4)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4136)
Otherwise,
the expression *bulk-algo*(sndr, policy, shape, f) is expression-equivalent to:
transform_sender(*get-domain-early*(sndr), *make-sender*(*bulk-algo*, *product-type*<*see below*, Shape, Func>{policy, shape, f}, sndr)) except that sndr is evaluated only once[.](#3.sentence-2)
The first template argument of *product-type* is Policy if Policy models [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]"), andconst Policy& otherwise[.](#3.sentence-3)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4150)
Let sndr and env be subexpressions such thatSndr is decltype((sndr))[.](#4.sentence-1)
If [*sender-for*](exec.snd.concepts#concept:sender-for "33.9.3Sender concepts[exec.snd.concepts]")<Sndr, bulk_t> is false, then
the expression bulk.transform_sender(sndr, env) is ill-formed;
otherwise, it is equivalent to:auto [_, data, child] = sndr;auto& [policy, shape, f] = data;auto new_f = [func = std::move(f)](Shape begin, Shape end, auto&&... vs)noexcept(noexcept(f(begin, vs...))) {while (begin != end) func(begin++, vs...);}return bulk_chunked(std::move(child), policy, shape, std::move(new_f));
[*Note [1](#note-1)*:
This causes the bulk(sndr, policy, shape, f) sender to be
expressed in terms of bulk_chunked(sndr, policy, shape, f) when
it is connected to a receiver whose
execution domain does not customize bulk[.](#4.sentence-2)
— *end note*]
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4172)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for bulk_chunked_t as follows:
[🔗](#lib:impls-for%3cbulk_chunked_t%3e)
namespace std::execution {template<>struct *impls-for*<bulk_chunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; template<class Sndr, class... Env>static consteval void *check-types*(); };}
The member *impls-for*<bulk_chunked_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class Index, class State, class Rcvr, class Tag, class... Args>(Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<Tag, set_value_t>) {auto& [policy, shape, f] = state; constexpr bool nothrow = noexcept(f(auto(shape), auto(shape), args...)); *TRY-EVAL*(rcvr, [&]() noexcept(nothrow) { f(static_cast<decltype(auto(shape))>(0), auto(shape), args...);
Tag()(std::move(rcvr), std::forward<Args>(args)...); }()); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") of the lambda above istrue if and only
if Tag denotes a type other than set_value_t or
if the expression f(auto(shape), auto(shape), args...) is well-formed[.](#5.sentence-3)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4210)
The exposition-only class template *impls-for* ([[exec.snd.expos]](exec.snd.expos "33.9.2Exposition-only entities"))
is specialized for bulk_unchunked_t as follows:namespace std::execution {template<>struct *impls-for*<bulk_unchunked_t> : *default-impls* {static constexpr auto *complete* = *see below*; };}
The member *impls-for*<bulk_unchunked_t>::*complete* is initialized with a callable object equivalent to the following lambda:[]<class Index, class State, class Rcvr, class Tag, class... Args>(Index, State& state, Rcvr& rcvr, Tag, Args&&... args) noexcept-> void requires *see below* {if constexpr ([same_as](concept.same#concept:same_as "18.4.2Concept same_­as[concept.same]")<Tag, set_value_t>) {auto& [shape, f] = state; constexpr bool nothrow = noexcept(f(auto(shape), args...)); *TRY-EVAL*(rcvr, [&]() noexcept(nothrow) {for (decltype(auto(shape)) i = 0; i < shape; ++i) { f(auto(i), args...); } Tag()(std::move(rcvr), std::forward<Args>(args)...); }()); } else { Tag()(std::move(rcvr), std::forward<Args>(args)...); }}
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") of the lambda above
is true if and only
if Tag denotes a type other than set_value_t or
if the expression f(auto(shape), args...) is well-formed[.](#6.sentence-3)
[🔗](#lib:check-types,impls-for%3cbulk_t%3e)
`template<class Sndr, class... Env>
static consteval void check-types();
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4253)
*Effects*: Equivalent to:auto cs = get_completion_signatures<*child-type*<Sndr>, *FWD-ENV-T*(Env)...>();auto fn = []<class... Ts>(set_value_t(*)(Ts...)) {if constexpr (![invocable](concept.invocable#concept:invocable "18.7.2Concept invocable[concept.invocable]")<remove_cvref_t<*data-type*<Sndr>>, Ts&...>)throw *unspecified-exception*();};
cs.*for-each*(*overload-set*(fn, [](auto){})); where *unspecified-exception* is
a type derived from exception[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4268)
Let the subexpression out_sndr denote
the result of the invocation*bulk-algo*(sndr, policy, shape, f) or
an object equal to such, and
let the subexpression rcvr denote a receiver
such that the expression connect(out_sndr, rcvr) is well-formed[.](#8.sentence-1)
The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([[exec.async.ops]](exec.async.ops "33.3Asynchronous operations")) that,
when started:
- [(8.1)](#8.1)
If sndr has a successful completion, whereargs is a pack of lvalue subexpressions
referring to the value completion result datums of sndr, or
decayed copies of those values if they model [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]"),
then:
* [(8.1.1)](#8.1.1)
If out_sndr also completes successfully, then:
+
[(8.1.1.1)](#8.1.1.1)
for bulk,
invokes f(i, args...) for every i of type Shape from 0 to shape;
+
[(8.1.1.2)](#8.1.1.2)
for bulk_unchunked,
invokes f(i, args...) for every i of type Shape from 0 to shape;
*Recommended practice*: The underlying scheduler should execute each iteration
on a distinct execution agent[.](#8.1.1.2.sentence-2)
+
[(8.1.1.3)](#8.1.1.3)
for bulk_chunked,
invokes f(b, e, args...) zero or more times
with pairs of b and e of type Shape in range [0, shape],
such that b<e and
for every i of type Shape from 0 to shape,
there is exactly one invocation with a pair b and e,
such that i is in the range [b, e)[.](#8.1.1.3.sentence-1)
* [(8.1.2)](#8.1.2)
If out_sndr completes with set_error(rcvr, eptr), then
the asynchronous operation may invoke a subset of
the invocations of f before the error completion handler is called, and eptr is an exception_ptr containing either:
+
[(8.1.2.1)](#8.1.2.1)
an exception thrown by an invocation of f, or
+
[(8.1.2.2)](#8.1.2.2)
a bad_alloc exception if
the implementation fails to allocate required resources, or
+
[(8.1.2.3)](#8.1.2.3)
an exception derived from runtime_error[.](#8.1.2.sentence-1)
* [(8.1.3)](#8.1.3)
If out_sndr completes with set_stopped(rcvr), then
the asynchronous operation may invoke a subset of
the invocations of f before the stopped completion handler[.](#8.1.3.sentence-1)
- [(8.2)](#8.2)
If sndr does not complete with set_value, then
the completion is forwarded to recv[.](#8.2.sentence-1)
- [(8.3)](#8.3)
For *bulk-algo*,
the parameter policy describes
the manner in which
the execution of the asynchronous operations corresponding to these algorithms
may be parallelized and
the manner in which
they apply f[.](#8.3.sentence-1)
Permissions and requirements
on parallel algorithm element access functions ([[algorithms.parallel.exec]](algorithms.parallel.exec "26.3.3Effect of execution policies on algorithm execution"))
apply to f[.](#8.3.sentence-2)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L4358)
[*Note [2](#note-2)*:
The asynchronous operation corresponding to*bulk-algo*(sndr, policy, shape, f) can complete with set_stopped if cancellation is requested or
ignore cancellation requests[.](#9.sentence-1)
— *end note*]