Skip to content

Commit 7d56a69

Browse files
committed
avoid instantiating default sync_wait impl needlessly
1 parent 165edc2 commit 7d56a69

File tree

3 files changed

+82
-80
lines changed

3 files changed

+82
-80
lines changed

include/nvexec/stream/sync_wait.cuh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#pragma once
2020

2121
#include "../../stdexec/execution.hpp"
22+
#include "common.cuh"
23+
2224
#include <concepts>
2325
#include <exception>
2426
#include <new>
@@ -27,8 +29,6 @@
2729
#include <utility>
2830
#include <variant>
2931

30-
#include "common.cuh"
31-
3232
namespace nvexec::_strm {
3333
namespace _sync_wait {
3434
struct __env {

include/stdexec/__detail/__basic_sender.hpp

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ namespace STDEXEC {
135135
static_cast<_Sender&&>(__sndr), static_cast<_Receiver&&>(__rcvr)};
136136
};
137137

138+
static constexpr auto submit = []{};
139+
138140
static constexpr auto start = []<class _StartTag = start_t, class... _ChildOps>(
139141
__ignore,
140142
__ignore,
@@ -435,10 +437,6 @@ namespace STDEXEC {
435437

436438
using __detail::__enable_receiver_from_this;
437439

438-
template <class _Tag>
439-
using __get_attrs_fn =
440-
__result_of<__detail::__drop_front, __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
441-
442440
//! A dummy type used only for diagnostic purposes.
443441
//! See `__sexpr` for the implementation of P2300's _`basic-sender`_.
444442
template <class...>
@@ -463,19 +461,15 @@ namespace STDEXEC {
463461
using __desc_t = decltype(_DescriptorFn());
464462
using __tag_t = __desc_t::__tag;
465463

466-
template <class _Self>
467-
using __impl = __sexpr_impl<__meval<__msecond, _Self, __tag_t>>;
468-
469-
template <class _Self = __sexpr>
470-
STDEXEC_ATTRIBUTE(always_inline)
471-
auto get_env() const noexcept -> decltype(auto) {
472-
return __apply(__detail::__drop_front(__impl<_Self>::get_attrs), *this);
464+
STDEXEC_ATTRIBUTE(nodiscard, always_inline)
465+
constexpr auto get_env() const noexcept -> decltype(auto) {
466+
return __apply(__detail::__drop_front(__sexpr_impl<__tag_t>::get_attrs), *this);
473467
}
474468

475469
template <class _Self, class... _Env>
476470
static consteval auto get_completion_signatures() {
477471
static_assert(__decays_to_derived_from<_Self, __sexpr>);
478-
using __impl_t = __mtypeof<__impl<_Self>::get_completion_signatures>;
472+
using __impl_t = __mtypeof<__sexpr_impl<__tag_t>::get_completion_signatures>;
479473
using __detail::__has_static_consteval_get_completion_signatures;
480474

481475
if constexpr (__has_static_consteval_get_completion_signatures<__tag_t, _Self, _Env...>) {
@@ -489,30 +483,42 @@ namespace STDEXEC {
489483
}
490484
}
491485

486+
// Non-standard extension:
492487
template <class _Self, receiver _Receiver>
493-
STDEXEC_ATTRIBUTE(always_inline)
494-
STDEXEC_EXPLICIT_THIS_BEGIN(auto connect)(this _Self&& __self, _Receiver&& __rcvr)
495-
noexcept(__noexcept_of<__impl<_Self>::connect, _Self, _Receiver>)
496-
// -> __msecond<
497-
// __enable_if<__decays_to_derived_from<_Self, __sexpr>>,
498-
// __result_of<__impl<_Self>::connect, _Self, _Receiver>
499-
// >
500-
{
488+
STDEXEC_ATTRIBUTE(nodiscard, always_inline)
489+
static constexpr auto static_connect(_Self&& __self, _Receiver __rcvr)
490+
noexcept(__noexcept_of<__sexpr_impl<__tag_t>::connect, _Self, _Receiver>)
491+
-> __result_of<__sexpr_impl<__tag_t>::connect, _Self, _Receiver> {
501492
static_assert(__decays_to_derived_from<_Self, __sexpr>);
502-
return __impl<_Self>::connect(
493+
return __sexpr_impl<__tag_t>::connect(
503494
static_cast<_Self&&>(__self), static_cast<_Receiver&&>(__rcvr));
504495
}
505-
STDEXEC_EXPLICIT_THIS_END(connect)
496+
497+
template <receiver _Receiver>
498+
STDEXEC_ATTRIBUTE(nodiscard, always_inline)
499+
constexpr auto connect(_Receiver __rcvr) && noexcept(
500+
__noexcept_of<__sexpr_impl<__tag_t>::connect, __sexpr, _Receiver>)
501+
-> __result_of<__sexpr_impl<__tag_t>::connect, __sexpr, _Receiver> {
502+
return __sexpr_impl<__tag_t>::connect(
503+
static_cast<__sexpr&&>(*this), static_cast<_Receiver&&>(__rcvr));
504+
}
505+
506+
template <receiver _Receiver>
507+
requires __std::copy_constructible<__sexpr>
508+
STDEXEC_ATTRIBUTE(nodiscard, always_inline)
509+
constexpr auto connect(_Receiver __rcvr) const & noexcept(
510+
__noexcept_of<__sexpr_impl<__tag_t>::connect, __sexpr const &, _Receiver>)
511+
-> __result_of<__sexpr_impl<__tag_t>::connect, __sexpr const &, _Receiver> {
512+
return __sexpr_impl<__tag_t>::connect(*this, static_cast<_Receiver&&>(__rcvr));
513+
}
506514

507515
template <class _Self, receiver _Receiver>
508-
STDEXEC_ATTRIBUTE(always_inline)
509-
static auto submit(_Self&& __self, _Receiver&& __rcvr)
510-
noexcept(__noexcept_of<__impl<_Self>::submit, _Self, _Receiver>) -> __msecond<
511-
__enable_if<__decays_to_derived_from<_Self, __sexpr>>,
512-
__result_of<__impl<_Self>::submit, _Self, _Receiver>
513-
> {
516+
STDEXEC_ATTRIBUTE(nodiscard, always_inline)
517+
static constexpr auto submit(_Self&& __self, _Receiver __rcvr)
518+
noexcept(__noexcept_of<__sexpr_impl<__tag_t>::submit, _Self, _Receiver>)
519+
-> __result_of<__sexpr_impl<__tag_t>::submit, _Self, _Receiver> {
514520
static_assert(__decays_to_derived_from<_Self, __sexpr>);
515-
return __impl<_Self>::submit(
521+
return __sexpr_impl<__tag_t>::submit(
516522
static_cast<_Self&&>(__self), static_cast<_Receiver&&>(__rcvr));
517523
}
518524
};

include/stdexec/__detail/__sync_wait.hpp

Lines changed: 45 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,6 @@ namespace STDEXEC {
6262
constexpr auto query(__root_t) const noexcept -> bool {
6363
return true;
6464
}
65-
66-
// static constexpr auto query(__debug::__is_debug_env_t) noexcept -> bool
67-
// {
68-
// return true;
69-
// }
7065
};
7166

7267
// What should sync_wait(just_stopped()) return?
@@ -99,8 +94,8 @@ namespace STDEXEC {
9994
std::optional<std::tuple<_Values...>>* __values_;
10095

10196
template <class... _As>
102-
requires __std::constructible_from<std::tuple<_Values...>, _As...>
10397
void set_value(_As&&... __as) noexcept {
98+
static_assert(__std::constructible_from<std::tuple<_Values...>, _As...>);
10499
STDEXEC_TRY {
105100
__values_->emplace(static_cast<_As&&>(__as)...);
106101
}
@@ -192,60 +187,61 @@ namespace STDEXEC {
192187
////////////////////////////////////////////////////////////////////////////
193188
// [execution.senders.consumers.sync_wait]
194189
struct sync_wait_t {
195-
template <class _Sender>
190+
template <sender_in<__env> _Sender>
196191
auto operator()(_Sender&& __sndr) const {
197-
if constexpr (!sender_in<_Sender, __env>) {
198-
STDEXEC::__diagnose_sender_concept_failure<_Sender, __env>();
199-
} else {
200-
using __domain_t = __completion_domain_of_t<set_value_t, _Sender, __env>;
201-
constexpr auto __success_completion_count =
202-
__count_of<set_value_t, _Sender, __env>::value;
203-
204-
static_assert(
205-
__success_completion_count != 0,
206-
"The argument to STDEXEC::sync_wait() is a sender that cannot complete successfully. "
207-
"STDEXEC::sync_wait() requires a sender that can complete successfully in exactly one "
208-
"way. In other words, the sender's completion signatures must include exactly one "
209-
"signature of the form `set_value_t(value-types...)`.");
210-
211-
static_assert(
212-
__success_completion_count <= 1,
213-
"The sender passed to STDEXEC::sync_wait() can complete successfully in "
214-
"more than one way. Use STDEXEC::sync_wait_with_variant() instead.");
215-
216-
if constexpr (1 == __success_completion_count) {
217-
using __sync_wait_receiver = __receiver_t<_Sender>;
218-
constexpr bool __no_custom_sync_wait = __same_as<__domain_t, default_domain>;
219-
if constexpr (__no_custom_sync_wait && sender_to<_Sender, __sync_wait_receiver>) {
220-
// using __connect_result = connect_result_t<_Sender, __sync_wait_receiver>;
221-
// if constexpr (!operation_state<__connect_result>) {
222-
// static_assert(
223-
// operation_state<__connect_result>,
224-
// "The `connect` member function of the sender passed to STDEXEC::sync_wait() does "
225-
// "not return an operation state. An operation state is required to have a "
226-
// "no-throw .start() member function.");
227-
// } else
228-
{
192+
using __domain_t = __completion_domain_of_t<set_value_t, _Sender, __env>;
193+
constexpr auto __success_completion_count = __count_of<set_value_t, _Sender, __env>::value;
194+
195+
static_assert(
196+
__success_completion_count != 0,
197+
"The argument to STDEXEC::sync_wait() is a sender that cannot complete successfully. "
198+
"STDEXEC::sync_wait() requires a sender that can complete successfully in exactly one "
199+
"way. In other words, the sender's completion signatures must include exactly one "
200+
"signature of the form `set_value_t(value-types...)`.");
201+
202+
static_assert(
203+
__success_completion_count <= 1,
204+
"The sender passed to STDEXEC::sync_wait() can complete successfully in "
205+
"more than one way. Use STDEXEC::sync_wait_with_variant() instead.");
206+
207+
if constexpr (1 == __success_completion_count) {
208+
if constexpr (__same_as<__domain_t, default_domain>) {
209+
if constexpr (sender_to<_Sender, __receiver_t<_Sender>>) {
210+
using __opstate_t = connect_result_t<_Sender, __receiver_t<_Sender>>;
211+
if constexpr (operation_state<__opstate_t>) {
229212
// success path, dispatch to the default domain's sync_wait
230213
return default_domain().apply_sender(*this, static_cast<_Sender&&>(__sndr));
214+
} else {
215+
static_assert(
216+
operation_state<__opstate_t>,
217+
"The `connect` member function of the sender passed to STDEXEC::sync_wait() "
218+
"does not return an operation state. An operation state is required to have a "
219+
"no-throw .start() member function.");
231220
}
232-
} else if constexpr (__no_custom_sync_wait) {
221+
} else {
233222
static_assert(
234-
sender_to<_Sender, __sync_wait_receiver>,
223+
sender_to<_Sender, __receiver_t<_Sender>>,
235224
STDEXEC_ERROR_SYNC_WAIT_CANNOT_CONNECT_SENDER_TO_RECEIVER);
236-
} else if constexpr (!__has_implementation_for<sync_wait_t, __domain_t, _Sender>) {
237-
static_assert(
238-
__has_implementation_for<sync_wait_t, __domain_t, _Sender>,
239-
"The sender passed to STDEXEC::sync_wait() has a domain that does not provide a "
240-
"usable implementation for sync_wait().");
241-
} else {
242-
// success path, dispatch to the custom domain's sync_wait
243-
return STDEXEC::apply_sender(__domain_t(), *this, static_cast<_Sender&&>(__sndr));
244225
}
226+
} else if constexpr (!__has_implementation_for<sync_wait_t, __domain_t, _Sender>) {
227+
static_assert(
228+
__has_implementation_for<sync_wait_t, __domain_t, _Sender>,
229+
"The sender passed to STDEXEC::sync_wait() has a domain that does not provide a "
230+
"usable implementation for sync_wait().");
231+
} else {
232+
// success path, dispatch to the custom domain's sync_wait
233+
return STDEXEC::apply_sender(__domain_t(), *this, static_cast<_Sender&&>(__sndr));
245234
}
246235
}
247236
}
248237

238+
template <class _Sender>
239+
auto operator()(_Sender&&) const {
240+
STDEXEC::__diagnose_sender_concept_failure<_Sender, __env>();
241+
// dummy return type to silence follow-on errors
242+
return std::optional<std::tuple<int>>{};
243+
}
244+
249245
// clang-format off
250246
/// @brief Synchronously wait for the result of a sender, blocking the
251247
/// current thread.

0 commit comments

Comments
 (0)