Skip to content

Commit

Permalink
progress toward fixing build breakages
Browse files Browse the repository at this point in the history
  • Loading branch information
ericniebler committed May 25, 2024
1 parent 23da2e3 commit 665672e
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 123 deletions.
175 changes: 83 additions & 92 deletions include/exec/when_any.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,64 +38,71 @@ namespace exec {
template <class _BaseEnv>
using __env_t = __env::__join_t<__env::__with<inplace_stop_token, get_stop_token_t>, _BaseEnv>;

template <class _Ret, class... _Args>
auto __signature_to_tuple_(_Ret (*)(_Args...)) -> __decayed_tuple<_Ret, _Args...>;

template <class _Sig>
using __signature_to_tuple_t = decltype(__signature_to_tuple_(static_cast<_Sig*>(nullptr)));

template <class... _Ts>
using __nothrow_decay_copyable_and_move_constructible_t = __mbool<(
(__nothrow_decay_copyable<_Ts> && __nothrow_move_constructible<__decay_t<_Ts>>) &&...)>;

template <class _Env, class... _SenderIds>
template <class _Env, class... _CvrefSenders>
using __all_value_args_nothrow_decay_copyable = //
__mand_t<value_types_of_t<
__t<_SenderIds>,
_CvrefSenders,
_Env,
__nothrow_decay_copyable_and_move_constructible_t,
__mand_t>...>;

template <class... Args>
using __as_rvalues = __types<set_value_t(__decay_t<Args>...)>;

template <class E>
using __as_error = __types<set_error_t(E)>;

// Here we convert all set_value(Args...) to set_value(__decay_t<Args>...)
// Note, we keep all error types as they are and unconditionally add set_stopped()
template <class _Env, class... _SenderIds>
using __completion_signatures_t = __concat_completion_signatures<
__eptr_completion_if_t<__all_value_args_nothrow_decay_copyable<_Env, _SenderIds...>>,
completion_signatures<set_stopped_t()>,
__transform_completion_signatures<
__completion_signatures_of_t<__t<_SenderIds>, _Env>,
__as_rvalues,
__as_error,
__types<set_stopped_t()>,
__mappend_into_q<completion_signatures>::__f>...>;

// transform Tag(Args...) to a tuple __decayed_tuple<Tag, Args...>
template <class _Env, class... _SenderIds>
using __result_type_t = __mapply<
__transform<__q<__signature_to_tuple_t>, __munique<__q<std::variant>>>,
__completion_signatures_t<_Env, _SenderIds...>>;

template <class _Variant, class... _Ts>
concept __result_constructible_from = //
constructible_from<__decayed_tuple<_Ts...>, _Ts...>
&& constructible_from<_Variant, __decayed_tuple<_Ts...>>;
using __as_rvalues = set_value_t (*)(__decay_t<Args>...);

template <class... E>
using __as_error = set_error_t (*)(E...);

template <class... _CvrefSenders, class _Env>
auto __completions_fn(_Env&&) //
-> __concat_completion_signatures<
__eptr_completion_if_t<__all_value_args_nothrow_decay_copyable<_Env, _CvrefSenders...>>,
completion_signatures<set_stopped_t()>,
__transform_completion_signatures<
__completion_signatures_of_t<_CvrefSenders, _Env>,
__as_rvalues,
__as_error,
set_stopped_t (*)(),
__completion_signature_ptrs>...>;

// Here we convert all set_value(Args...) to set_value(__decay_t<Args>...). Note, we keep all
// error types as they are and unconditionally add set_stopped(). The indirection through the
// __completions_fn is to avoid a pack expansion bug in nvc++.
template <class _Env, class... _CvrefSenders>
using __completions_t = //
decltype(__completions_fn<_CvrefSenders...>(__declval<_Env>()));

template <class _Env, class... _CvrefSenders>
using __result_type_t = //
__for_each_completion_signature<
__completions_t<_Env, _CvrefSenders...>,
__decayed_tuple,
__munique<__q<std::variant>>::__f>;

template <class _Variant, class... _Ts>
concept __nothrow_result_constructible_from =
__nothrow_constructible_from<__decayed_tuple<_Ts...>, _Ts...>
&& __nothrow_constructible_from<_Variant, __decayed_tuple<_Ts...>>;

template <class _Receiver>
auto __make_visitor_fn(_Receiver& __rcvr) noexcept {
return [&__rcvr]<class _Tuple>(_Tuple&& __result) noexcept {
std::apply(
[&__rcvr]<class _Tag, class... _As>(_Tag, _As&&... __args) noexcept {
_Tag{}(static_cast<_Receiver&&>(__rcvr), static_cast<_As&&>(__args)...);
},
static_cast<_Tuple&&>(__result));
};
}

template <class _Receiver, class _ResultVariant>
struct __op_base : __immovable {
__op_base(_Receiver&& __receiver, int __n_senders)
__op_base(_Receiver&& __rcvr, std::size_t __n_senders)
: __count_{__n_senders}
, __receiver_{static_cast<_Receiver&&>(__receiver)} {
, __rcvr_{static_cast<_Receiver&&>(__rcvr)} {
}

using __on_stop =
Expand All @@ -107,22 +114,22 @@ namespace exec {
// If this hits true, we store the result
std::atomic<bool> __emplaced_{false};
// If this hits zero, we forward any result to the receiver
std::atomic<int> __count_{};
std::atomic<std::size_t> __count_{};

_Receiver __receiver_;
_Receiver __rcvr_;
std::optional<_ResultVariant> __result_{};

template <class _CPO, class... _Args>
void notify(_CPO, _Args&&... __args) noexcept {
template <class _Tag, class... _Args>
void notify(_Tag, _Args&&... __args) noexcept {
bool __expect = false;
if (__emplaced_.compare_exchange_strong(
__expect, true, std::memory_order_relaxed, std::memory_order_relaxed)) {
// This emplacement can happen only once
if constexpr (__nothrow_result_constructible_from<_ResultVariant, _CPO, _Args...>) {
__result_.emplace(std::tuple{_CPO{}, static_cast<_Args&&>(__args)...});
if constexpr (__nothrow_result_constructible_from<_ResultVariant, _Tag, _Args...>) {
__result_.emplace(std::tuple{_Tag{}, static_cast<_Args&&>(__args)...});
} else {
try {
__result_.emplace(std::tuple{_CPO{}, static_cast<_Args&&>(__args)...});
__result_.emplace(std::tuple{_Tag{}, static_cast<_Args&&>(__args)...});
} catch (...) {
__result_.emplace(std::tuple{set_error_t{}, std::current_exception()});
}
Expand All @@ -134,21 +141,14 @@ namespace exec {
// This relies on the fact that each sender will call notify() at most once
if (__count_.fetch_sub(1, std::memory_order_acq_rel) == 1) {
__on_stop_.reset();
auto stop_token = get_stop_token(get_env(__receiver_));
auto stop_token = get_stop_token(get_env(__rcvr_));
if (stop_token.stop_requested()) {
stdexec::set_stopped(static_cast<_Receiver&&>(__receiver_));
stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr_));
return;
}
STDEXEC_ASSERT(__result_.has_value());
std::visit(
[this]<class _Tuple>(_Tuple&& __result) {
std::apply(
[this]<class _Cpo, class... _As>(_Cpo, _As&&... __args) noexcept {
_Cpo{}(static_cast<_Receiver&&>(__receiver_), static_cast<_As&&>(__args)...);
},
static_cast<_Tuple&&>(__result));
},
static_cast<_ResultVariant&&>(*__result_));
__when_any::__make_visitor_fn(__rcvr_), static_cast<_ResultVariant&&>(*__result_));
}
}
};
Expand All @@ -166,24 +166,20 @@ namespace exec {

auto get_env() const noexcept -> __env_t<env_of_t<_Receiver>> {
auto __token = __env::__with(__op_->__stop_source_.get_token(), get_stop_token);
return __env::__join(std::move(__token), stdexec::get_env(__op_->__receiver_));
return __env::__join(std::move(__token), stdexec::get_env(__op_->__rcvr_));
}

template <class... _Args>
requires __result_constructible_from<_ResultVariant, set_value_t, _Args...>
void set_value(_Args&&... __args) noexcept {
__op_->notify(set_value_t(), static_cast<_Args&&>(__args)...);
}

template <class _Error>
requires __result_constructible_from<_ResultVariant, set_error_t, _Error>
void set_error(_Error&& __err) noexcept {
__op_->notify(set_error_t(), static_cast<_Error&&>(__err));
}

void set_stopped() noexcept
requires __result_constructible_from<_ResultVariant, set_stopped_t>
{
void set_stopped() noexcept {
__op_->notify(set_stopped_t());
}

Expand All @@ -192,34 +188,33 @@ namespace exec {
};
};

template <class _ReceiverId, class... _SenderIds>
template <class _ReceiverId, class... _CvrefSenderIds>
struct __op {
using _Receiver = stdexec::__t<_ReceiverId>;

using __result_t = __result_type_t<env_of_t<_Receiver>, _SenderIds...>;
using __result_t = __result_type_t<env_of_t<_Receiver>, __cvref_t<_CvrefSenderIds>...>;
using __receiver_t = stdexec::__t<__receiver<_Receiver, __result_t>>;
using __op_base_t = __op_base<_Receiver, __result_t>;

static constexpr bool __nothrow_construct = //
__nothrow_decay_copyable<_Receiver>
&& (__nothrow_connectable<__cvref_t<_CvrefSenderIds>, __receiver_t> && ...);

class __t : __op_base_t {
public:
template <class _SenderTuple>
__t(_SenderTuple&& __senders, _Receiver&& __rcvr) //

//
noexcept(
__nothrow_decay_copyable<_Receiver>
&& (__nothrow_connectable<stdexec::__t<_SenderIds>, __receiver_t> && ...))
__t(_SenderTuple&& __senders, _Receiver&& __rcvr) noexcept(__nothrow_construct)
: __t{
static_cast<_SenderTuple&&>(__senders),
static_cast<_Receiver&&>(__rcvr),
std::index_sequence_for<_SenderIds...>{}} {
std::index_sequence_for<_CvrefSenderIds...>{}} {
}

void start() & noexcept {
this->__on_stop_.emplace(
get_stop_token(get_env(this->__receiver_)), __on_stop_requested{this->__stop_source_});
get_stop_token(get_env(this->__rcvr_)), __on_stop_requested{this->__stop_source_});
if (this->__stop_source_.stop_requested()) {
stdexec::set_stopped(static_cast<_Receiver&&>(this->__receiver_));
stdexec::set_stopped(static_cast<_Receiver&&>(this->__rcvr_));
} else {
std::apply([](auto&... __ops) { (stdexec::start(__ops), ...); }, __ops_);
}
Expand All @@ -228,32 +223,30 @@ namespace exec {
private:
template <class _SenderTuple, std::size_t... _Is>
__t(_SenderTuple&& __senders, _Receiver&& __rcvr, std::index_sequence<_Is...>) //

//
noexcept(
__nothrow_decay_copyable<_Receiver>
&& (__nothrow_connectable<stdexec::__t<_SenderIds>, __receiver_t> && ...))
: __op_base_t{static_cast<_Receiver&&>(__rcvr), static_cast<int>(sizeof...(_SenderIds))}
noexcept(__nothrow_construct)
: __op_base_t{static_cast<_Receiver&&>(__rcvr), sizeof...(_CvrefSenderIds)}
, __ops_{__conv{[&__senders, this] {
return stdexec::connect(
std::get<_Is>(static_cast<_SenderTuple&&>(__senders)),
__receiver_t{static_cast<__op_base_t*>(this)});
}}...} {
}

std::tuple<connect_result_t<stdexec::__t<_SenderIds>, __receiver_t>...> __ops_;
std::tuple<connect_result_t<stdexec::__cvref_t<_CvrefSenderIds>, __receiver_t>...> __ops_;
};
};

template <class... _SenderIds>
struct __sender {
template <class _Self, class _Env>
using __result_t = __result_type_t<_Env, __copy_cvref_t<_Self, stdexec::__t<_SenderIds>>...>;

template <class _Receiver>
template <class _Self, class _Receiver>
using __receiver_t =
stdexec::__t<__receiver<_Receiver, __result_type_t<env_of_t<_Receiver>, _SenderIds...>>>;
stdexec::__t<__receiver<_Receiver, __result_t<_Self, env_of_t<_Receiver>>>>;

template <class _Receiver>
using __op_t = stdexec::__t<__op<__id<__decay_t<_Receiver>>, _SenderIds...>>;
template <class _Self, class _Receiver>
using __op_t = stdexec::__t<__op<__id<_Receiver>, __copy_cvref_t<_Self, _SenderIds>...>>;

class __t {
public:
Expand All @@ -267,20 +260,18 @@ namespace exec {
}

template <__decays_to<__t> _Self, receiver _Receiver>
requires(
sender_to<__copy_cvref_t<_Self, stdexec::__t<_SenderIds>>, __receiver_t<_Receiver>>
&& ...)
STDEXEC_MEMFN_DECL(
auto connect)(this _Self&& __self, _Receiver&& __rcvr) //
noexcept(__nothrow_constructible_from<__op_t<_Receiver>, _Self&&, _Receiver&&>)
-> __op_t<_Receiver> {
return __op_t<_Receiver>{
auto connect)(this _Self&& __self, _Receiver __rcvr) //
noexcept(__nothrow_constructible_from<__op_t<_Self, _Receiver>, _Self, _Receiver>)
-> __op_t<_Self, _Receiver> {
return __op_t<_Self, _Receiver>{
static_cast<_Self&&>(__self).__senders_, static_cast<_Receiver&&>(__rcvr)};
}

template <__decays_to<__t> _Self, class _Env>
static auto get_completion_signatures(_Self&&, _Env) noexcept {
return __completion_signatures_t<_Env, _SenderIds...>{};
static auto get_completion_signatures(_Self&&, _Env&&) noexcept
-> __completions_t<_Env, __copy_cvref_t<_Self, stdexec::__t<_SenderIds>>...> {
return {};
}

private:
Expand Down
2 changes: 1 addition & 1 deletion include/stdexec/__detail/__execution_fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,5 @@ template <class...>
void __print() {
}

template <class>
template <class...>
struct __undef;
28 changes: 10 additions & 18 deletions include/stdexec/__detail/__meta.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,23 @@ namespace stdexec {
using __types_ref = __types<_Ts...> &;

template <class... _Ts>
__types<_Ts...> operator+(__types<_Ts...> &);
auto operator+(__types<_Ts...> &) -> __types<_Ts...>;

template <class... _Ts, template <class...> class _List, class... _Us>
__types<_Ts..., _Us...> &operator+(__types<_Ts...> &, _List<_Us...> &);
auto operator+(__types<_Ts...> &, _List<_Us...> &) -> __types<_Ts..., _Us...> &;

struct __mappend {
template <template <class...> class _Fn>
struct __mappend_into_q {
template <class... _Lists>
using __f = decltype(+((*static_cast<__types<> *>(nullptr)) + ... + __declval<_Lists &>()));
};
static auto __concat(__types<> &__list, _Lists &...__lists) //
-> decltype((__list + ... + __lists));

template <template <class...> class _Fn, class... _Ts>
auto __mappend_into_q_(__types<_Ts...> &) -> _Fn<_Ts...>;
template <class... _Ts>
static auto __apply(__types<_Ts...> &) -> _Fn<_Ts...>;

template <template <class...> class _Fn>
struct __mappend_into_q {
template <class... _Lists>
using __f = decltype(stdexec::__mappend_into_q_<_Fn>(
((*static_cast<__types<> *>(nullptr)) + ... + __declval<_Lists &>())));
using __f = decltype(__mappend_into_q::__apply(
__mappend_into_q::__concat(__declval<__types<> &>(), __declval<_Lists &>()...)));
};

template <class _Fn>
Expand Down Expand Up @@ -687,13 +686,6 @@ namespace stdexec {
_List>;
};

// template <class _Continuation = __q<__types>>
// struct __munique {
// template <class... _Ts>
// using __f =
// __mapply<_Continuation, __minvoke<__mfold_right<__types<>, __push_back_unique<>>, _Ts...>>;
// };

template <class...>
struct __mcompose { };

Expand Down
4 changes: 2 additions & 2 deletions include/stdexec/__detail/__senders.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ namespace stdexec {
concept sender_of = //
sender_in<_Sender, _Env> //
&& same_as<
__types<_SetSig>,
__types_ref<_SetSig>,
__gather_completions_of<
__tag_of_sig_t<_SetSig>,
_Sender,
_Env,
__mcompose_q<__types_ref, __qf<__tag_of_sig_t<_SetSig>>::template __f>,
__mappend>>;
__mappend_into_q<__types_ref>>>;
} // namespace stdexec
Loading

0 comments on commit 665672e

Please sign in to comment.