The names bulk, bulk_chunked, and bulk_unchunked
denote pipeable sender adaptor objects.
Let bulk-algo be either
bulk, bulk_chunked, or bulk_unchunked.
For subexpressions sndr, policy, shape, and f,
let
Policy be remove_cvref_t<decltype(policy)>,
Shape be decltype(auto(shape)), and
Func be decay_t<decltype((f))>.
Let sndr and env be subexpressions such that
Sndr is decltype((sndr)).
If sender-for<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));
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.
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->voidrequiressee below{ifconstexpr(same_as<Tag, set_value_t>){auto&[policy, shape, f]= state;
constexprbool 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 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), auto(shape), args...) is well-formed.
The exposition-only class template impls-for ([exec.snd.general])
is specialized for bulk_unchunked_t as follows:
namespace std::execution {template<>structimpls-for<bulk_unchunked_t>:default-impls{staticconstexprautocomplete=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->voidrequiressee below{ifconstexpr(same_as<Tag, set_value_t>){auto&[shape, f]= state;
constexprbool 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 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.
Effects: Equivalent to:
auto cs = get_completion_signatures<child-type<Sndr>, FWD-ENV-T(Env)...>();
auto fn =[]<class... Ts>(set_value_t(*)(Ts...)){ifconstexpr(!invocable<remove_cvref_t<data-type<Sndr>>, Ts&...>)throwunspecified-exception();
};
cs.for-each(overload-set(fn, [](auto){}));
where unspecified-exception is
a type derived from exception.
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.
The expression connect(out_sndr, rcvr) has undefined behavior
unless it creates an asynchronous operation ([exec.async.ops]) that,
when started:
If sndr has a successful completion, where
args 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,
then:
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).
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:
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.
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.
Permissions and requirements
on parallel algorithm element access functions ([algorithms.parallel.exec])
apply to f.
The asynchronous operation corresponding to
bulk-algo(sndr, policy, shape, f)
can complete with set_stopped if cancellation is requested or
ignore cancellation requests.