Skip to content

Commit

Permalink
Merge pull request #1113 from NVIDIA/port-transfer-just
Browse files Browse the repository at this point in the history
port the `transfer_just` algorithm to use `transform_sender`
  • Loading branch information
ericniebler authored Oct 20, 2023
2 parents d29cf7a + e51c0d0 commit 9d84acb
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 30 deletions.
9 changes: 9 additions & 0 deletions include/stdexec/__detail/__execution_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ namespace stdexec {
}

using __transfer::transfer_t;
extern const transfer_t transfer;

//////////////////////////////////////////////////////////////////////////////////////////////////
namespace __transfer_just {
struct transfer_just_t;
}

using __transfer_just::transfer_just_t;
extern const transfer_just_t transfer_just;

//////////////////////////////////////////////////////////////////////////////////////////////////
namespace __on_v2 {
Expand Down
105 changes: 75 additions & 30 deletions include/stdexec/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@

STDEXEC_PRAGMA_PUSH()
STDEXEC_PRAGMA_IGNORE_GNU("-Wpragmas")
STDEXEC_PRAGMA_IGNORE_GNU("-Wunknown-warning-option")
STDEXEC_PRAGMA_IGNORE_GNU("-Wundefined-inline")
STDEXEC_PRAGMA_IGNORE_GNU("-Wundefined-internal")
STDEXEC_PRAGMA_IGNORE_GNU("-Wsubobject-linkage")

namespace stdexec {
// [exec.queries.queryable]
Expand Down Expand Up @@ -139,7 +140,7 @@ namespace stdexec {
} else if constexpr (__domain::__has_default_transform<_Sender>) {
return __tag_of<_Sender>().transform_sender((_Sender&&) __sndr);
} else {
return _Sender((_Sender&&) __sndr);
return static_cast<_Sender>((_Sender&&) __sndr);
}
}

Expand All @@ -149,7 +150,7 @@ namespace stdexec {
if constexpr (__domain::__has_default_transform<_Sender, _Env>) {
return __tag_of<_Sender>().transform_sender((_Sender&&) __sndr, __env);
} else {
return _Sender((_Sender&&) __sndr);
return static_cast<_Sender>((_Sender&&) __sndr);
}
}
};
Expand Down Expand Up @@ -5391,11 +5392,17 @@ namespace stdexec {
__decay_signature<set_value_t>,
__decay_signature<set_error_t>>;

inline auto __get_env_fn() noexcept {
return [](__ignore, const auto& __data, const auto& __child) noexcept -> decltype(auto) {
return __join_env(__data, stdexec::get_env(__child));
};
}

struct schedule_from_t {
template <scheduler _Scheduler, sender _Sender>
auto operator()(_Scheduler&& __sched, _Sender&& __sndr) const {
using _Env = __t<__environ<__id<__decay_t<_Scheduler>>>>;
auto __env = __join_env(_Env{(_Scheduler&&) __sched}, stdexec::get_env(__sndr));
auto __env = _Env{{(_Scheduler&&) __sched}};
auto __domain = query_or(get_domain, __sched, default_domain());
return stdexec::transform_sender(
__domain, make_sender_expr<schedule_from_t>(std::move(__env), (_Sender&&) __sndr));
Expand All @@ -5413,7 +5420,7 @@ namespace stdexec {
#endif

template <class _Sender>
using __env_t = __data_of<const _Sender&>;
using __env_t = apply_sender_result_t<const _Sender&, __result_of<__get_env_fn>>;

template <class _Sender>
using __scheduler_t =
Expand All @@ -5435,7 +5442,7 @@ namespace stdexec {

template <sender_expr_for<schedule_from_t> _Sender>
static __env_t<_Sender> get_env(const _Sender& __sndr) noexcept {
return apply_sender(__sndr, __detail::__get_data());
return apply_sender(__sndr, __get_env_fn());
}

template <sender_expr_for<schedule_from_t> _Sender, class _Env>
Expand All @@ -5448,12 +5455,11 @@ namespace stdexec {
requires sender_to<__child_of<_Sender>, __receiver_t<_Sender, _Receiver>>
static auto connect(_Sender&& __sndr, _Receiver __rcvr) //
-> __operation_t<_Sender, _Receiver> {
using _Child = __child_of<_Sender>;
return apply_sender(
(_Sender&&) __sndr,
[&](schedule_from_t, __env_t<_Sender>&& __env, _Child&& __child)
-> __operation_t<_Sender, _Receiver> {
auto __sched = get_completion_scheduler<set_value_t>(__env);
[&]<class _Data, class _Child>(
__ignore, _Data&& __data, _Child&& __child) -> __operation_t<_Sender, _Receiver> {
auto __sched = get_completion_scheduler<set_value_t>(__data);
return {__sched, (_Child&&) __child, (_Receiver&&) __rcvr};
});
}
Expand All @@ -5475,16 +5481,20 @@ namespace stdexec {
using __lowered_t = //
__result_of<schedule_from, __scheduler_t<__data_of<_Sender>>, __child_of<_Sender>>;

inline auto __get_env_fn() noexcept {
return [](__ignore, const auto& __data, const auto& __child) noexcept {
return __join_env(__data, stdexec::get_env(__child));
};
}

struct transfer_t {
template <sender _Sender, scheduler _Scheduler>
auto operator()(_Sender&& __sndr, _Scheduler&& __sched) const {
auto __domain = __get_sender_domain(__sndr);
using _Env = __t<__environ<__id<__decay_t<_Scheduler>>>>;
return stdexec::transform_sender(
__domain,
make_sender_expr<transfer_t>(
__join_env(_Env{(_Scheduler&&) __sched}, stdexec::get_env(__sndr)),
(_Sender&&) __sndr));
make_sender_expr<transfer_t>(_Env{{(_Scheduler&&) __sched}}, (_Sender&&) __sndr));
}

template <scheduler _Scheduler>
Expand All @@ -5505,8 +5515,8 @@ namespace stdexec {
tag_invoke_t(transfer_t, _Sender, get_completion_scheduler_t<set_value_t>(_Env))>;

template <sender_expr_for<transfer_t> _Sender>
static __data_of<const _Sender&> get_env(const _Sender& __sndr) noexcept {
return apply_sender(__sndr, __detail::__get_data());
static decltype(auto) get_env(const _Sender& __sndr) noexcept {
return apply_sender(__sndr, __get_env_fn());
}

template <class _Sender, class _Env>
Expand All @@ -5531,23 +5541,58 @@ namespace stdexec {
/////////////////////////////////////////////////////////////////////////////
// [execution.senders.transfer_just]
namespace __transfer_just {
// This is a helper for finding legacy cusutomizations of transfer_just.
inline auto __transfer_just_tag_invoke() {
return []<class... _Ts>(_Ts&&... __ts) -> tag_invoke_result_t<transfer_just_t, _Ts...> {
return tag_invoke(transfer_just, (_Ts&&) __ts...);
};
}

inline auto __make_env_fn() noexcept {
return []<class _Scheduler>(const _Scheduler& __sched, const auto&...) noexcept {
using _Env = __t<__schedule_from::__environ<__id<_Scheduler>>>;
return _Env{{__sched}};
};
}

inline auto __get_env_fn() noexcept {
return [](__ignore, const auto& __data) noexcept {
return __apply(__make_env_fn(), __data);
};
}

struct transfer_just_t {
using _Data = __0;
using __legacy_customizations_t = //
__types<__apply_t(decltype(__transfer_just_tag_invoke()), _Data)>;

template <scheduler _Scheduler, __movable_value... _Values>
requires tag_invocable<transfer_just_t, _Scheduler, _Values...>
&& sender<tag_invoke_result_t<transfer_just_t, _Scheduler, _Values...>>
auto operator()(_Scheduler&& __sched, _Values&&... __vals) const
noexcept(nothrow_tag_invocable<transfer_just_t, _Scheduler, _Values...>)
-> tag_invoke_result_t<transfer_just_t, _Scheduler, _Values...> {
return tag_invoke(*this, (_Scheduler&&) __sched, (_Values&&) __vals...);
auto operator()(_Scheduler&& __sched, _Values&&... __vals) const {
auto __domain = query_or(get_domain, __sched, default_domain());
return stdexec::transform_sender(
__domain,
make_sender_expr<transfer_just_t>(
std::tuple{(_Scheduler&&) __sched, (_Values&&) __vals...}));
}

template <scheduler _Scheduler, __movable_value... _Values>
requires(
!tag_invocable<transfer_just_t, _Scheduler, _Values...>
|| !sender<tag_invoke_result_t<transfer_just_t, _Scheduler, _Values...>>)
auto operator()(_Scheduler&& __sched, _Values&&... __vals) const
-> decltype(transfer(just((_Values&&) __vals...), (_Scheduler&&) __sched)) {
return transfer(just((_Values&&) __vals...), (_Scheduler&&) __sched);
template <sender_expr_for<transfer_just_t> _Sender>
static auto get_env(const _Sender& __sndr) noexcept {
return apply_sender((_Sender&&) __sndr, __get_env_fn());
}

template <class _Sender, class _Env>
static auto transform_sender(_Sender&& __sndr, const _Env& __env) {
return __apply(
[&]<class _Scheduler, class... _Values>(_Scheduler&& __sched, _Values&&... __vals) {
auto __domain = __get_env_domain(__env);
return stdexec::transform_sender(
__domain,
transfer(
stdexec::transform_sender(__domain, just((_Values&&) __vals...), __env),
(_Scheduler&&) __sched),
__env);
},
apply_sender((_Sender&&) __sndr, __detail::__get_data()));
}
};
} // namespace __transfer_just
Expand Down Expand Up @@ -6498,7 +6543,7 @@ namespace stdexec {
return stdexec::transform_sender(
__domain,
make_sender_expr<transfer_when_all_t>(
_Env{(_Scheduler&&) __sched}, (_Senders&&) __sndrs...));
_Env{{(_Scheduler&&) __sched}}, (_Senders&&) __sndrs...));
}

template <sender_expr_for<transfer_when_all_t> _Sender>
Expand Down Expand Up @@ -6542,7 +6587,7 @@ namespace stdexec {
return stdexec::transform_sender(
__domain,
make_sender_expr<transfer_when_all_with_variant_t>(
_Env{(_Scheduler&&) __sched}, (_Senders&&) __sndrs...));
_Env{{(_Scheduler&&) __sched}}, (_Senders&&) __sndrs...));
}

template <sender_expr_for<transfer_when_all_with_variant_t> _Sender>
Expand Down
37 changes: 37 additions & 0 deletions include/stdexec/functional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "concepts.hpp"

#include <functional>
#include <tuple>

namespace stdexec::__std_concepts {
#if STDEXEC_HAS_STD_CONCEPTS_HEADER()
Expand Down Expand Up @@ -103,6 +104,42 @@ namespace stdexec {
}
} __compose{};

namespace __detail {
template <class _Fn, class _Tup>
using __apply_result_t = decltype(std::apply(__declval<_Fn>(), __declval<_Tup>()));

template <class _Fn>
struct __applicable_helper {
template <class... Ts>
auto operator()(Ts&&...) const noexcept {
return std::is_invocable<_Fn, Ts...>();
}
};
} // namespace __detail

template <class _Fn, class _Tup>
concept __applicable =
__detail::__apply_result_t<__detail::__applicable_helper<_Fn>, _Tup>::value;

template <class _Fn, class _Tup>
concept __nothrow_applicable =
__applicable<_Fn, _Tup>&& noexcept(std::apply(__declval<_Fn>(), __declval<_Tup>()));

template <class _Fn, class _Tup>
requires __applicable<_Fn, _Tup>
using __apply_result_t = __detail::__apply_result_t<_Fn, _Tup>;

struct __apply_t {
template <class _Fn, class _Tup>
requires __applicable<_Fn, _Tup>
constexpr auto operator()(_Fn&& __fn, _Tup&& __tup) const
noexcept(__nothrow_applicable<_Fn, _Tup>) -> __apply_result_t<_Fn, _Tup> {
return std::apply((_Fn&&) __fn, (_Tup&&) __tup);
}
};

inline constexpr __apply_t __apply{};

template <class _Tag, class _Ty>
struct __field {
_Ty operator()(_Tag) const noexcept(__nothrow_decay_copyable<const _Ty&>) {
Expand Down

0 comments on commit 9d84acb

Please sign in to comment.