Skip to content

Commit

Permalink
More work on execution::read
Browse files Browse the repository at this point in the history
flyby: adding hpx::is_nothrow_invocable
  • Loading branch information
hkaiser committed Aug 24, 2022
1 parent 51d7bf1 commit 6d5c93b
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
48 changes: 47 additions & 1 deletion libs/core/execution/include/hpx/execution/queries/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,23 @@ namespace hpx::execution::experimental {
HPX_FORWARD(Receiver, receiver)};
}

template <typename Tag1>
friend auto tag_invoke(
get_completion_signatures_t, read_sender<Tag1>, no_env)
-> dependent_completion_signatures<no_env>;

// clang-format off
template <typename Env>
friend auto tag_invoke(get_completion_signatures_t, read_sender, Env)
{
if constexpr (hpx::is_invocable_v<Tag, Env>)
if constexpr (hpx::is_nothrow_invocable_v<Tag, Env>)
{
using result_type =
completion_signatures<
set_value_t(hpx::util::invoke_result<Tag, Env>)>;
return result_type{};
}
else if constexpr (hpx::is_invocable_v<Tag, Env>)
{
using result_type =
completion_signatures<
Expand All @@ -105,6 +117,40 @@ namespace hpx::execution::experimental {
};
} // namespace detail

// execution::read is used to create a sender that retrieves a value from
// the receiver's associated environment and sends it back to the receiver
// through the value channel.
//
// execution::read is a customization point object of an unspecified class
// type
//
// Returns a sender that reaches into a receiver's environment and pulls out
// the current value associated with the customization point denoted by Tag.
// It then sends the value read back to the receiver through the value
// channel. For instance, get_scheduler() (with no arguments) is a sender
// that asks the receiver for the currently suggested scheduler and passes
// it to the receiver's set_value completion-signal.
//
// This can be useful when scheduling nested dependent work. The following
// sender pulls the current scheduler into the value channel and then
// schedules more work onto it. E.g.
//
// execution::sender auto task =
// execution::get_scheduler()
// | execution::let_value(
// [](auto sched) {
// return execution::on(sched, some nested work here);
// });
//
// this_thread::sync_wait(std::move(task)); // wait for it to finish
//
// This code uses the fact that sync_wait associates a scheduler with the
// receiver that it connects with task. get_scheduler() reads that scheduler
// out of the receiver, and passes it to let_value's receiver's set_value
// function, which in turn passes it to the lambda. That lambda returns a
// new sender that uses the scheduler to schedule some nested work onto
// sync_wait's scheduler.
//
inline constexpr struct read_t final : hpx::functional::tag<read_t>
{
private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,29 @@ namespace hpx {

template <typename R, typename F, typename... Ts>
inline constexpr bool is_invocable_r_v = is_invocable_r<R, F, Ts...>::value;

namespace detail {

template <typename Sig, bool Invocable>
struct is_nothrow_invocable_impl : std::false_type
{
};

template <typename F, typename... Ts>
struct is_nothrow_invocable_impl<F(Ts...), true>
: std::integral_constant<bool,
noexcept(std::declval<F>()(std::declval<Ts>()...))>
{
};
} // namespace detail

template <typename F, typename... Ts>
struct is_nothrow_invocable
: detail::is_nothrow_invocable_impl<F(Ts...), is_invocable_v<F, Ts...>>
{
};

template <typename F, typename... Ts>
inline constexpr bool is_nothrow_invocable_v =
is_nothrow_invocable<F, Ts...>::value;
} // namespace hpx

0 comments on commit 6d5c93b

Please sign in to comment.