Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions include/stdexec/__detail/__continues_on.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,18 @@ namespace STDEXEC
template <class _Scheduler, class _Sexpr, class _Receiver>
struct __state : __state_base<_Sexpr, _Receiver>
{
using __receiver2_t = __receiver2<_Sexpr, _Receiver>;
using __receiver2_t = __receiver2<_Sexpr, _Receiver>;
using __schedule_sender_t = schedule_result_t<_Scheduler&>;

constexpr explicit __state(_Scheduler __sched, _Receiver&& __rcvr)
noexcept(__nothrow_callable<schedule_t, _Scheduler&>
&& __nothrow_connectable<__schedule_sender_t, __receiver2_t>)
: __state::__state_base{static_cast<_Receiver&&>(__rcvr)}
, __state2_(connect(schedule(__sched), __receiver2_t{this}))
{}
STDEXEC_IMMOVABLE(__state);

connect_result_t<schedule_result_t<_Scheduler>, __receiver2_t> __state2_;
connect_result_t<__schedule_sender_t, __receiver2_t> __state2_;
};

//! @brief The @c continues_on sender's attributes.
Expand Down Expand Up @@ -342,8 +345,10 @@ namespace STDEXEC
}

static constexpr auto __get_state =
[]<class _Sender, class _Receiver>(_Sender&& __sndr,
_Receiver&& __rcvr) -> __state_for_t<_Sender, _Receiver>
[]<class _Sender, class _Receiver>(_Sender&& __sndr, _Receiver&& __rcvr) noexcept(
__nothrow_constructible_from<__state_for_t<_Sender, _Receiver>,
__data_of<_Sender>&,
_Receiver>) -> __state_for_t<_Sender, _Receiver>
requires sender_in<__child_of<_Sender>, __fwd_env_t<env_of_t<_Receiver>>>
{
static_assert(__sender_for<_Sender, continues_on_t>);
Expand Down
48 changes: 48 additions & 0 deletions test/stdexec/algos/adaptors/test_continues_on.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,40 @@ using namespace std::chrono_literals;

namespace
{
struct potentially_throwing_connect_scheduler
{
using scheduler_concept = ex::scheduler_tag;

struct sender
{
using sender_concept = ex::sender_tag;
using completion_signatures = ex::completion_signatures<ex::set_value_t()>;

template <class Receiver>
struct opstate
{
void start() & noexcept
{
ex::set_value(static_cast<Receiver&&>(receiver_));
}

Receiver receiver_;
};

template <class Receiver>
auto connect(Receiver receiver) const noexcept(false) -> opstate<Receiver>
{
return {static_cast<Receiver&&>(receiver)};
}
};

auto schedule() const noexcept -> sender
{
return {};
}

auto operator==(potentially_throwing_connect_scheduler const &) const noexcept -> bool = default;
};

TEST_CASE("continues_on returns a sender", "[adaptors][continues_on]")
{
Expand All @@ -46,6 +80,20 @@ namespace
(void) snd;
}

TEST_CASE("continues_on is nothrow connectable when the scheduler is",
"[adaptors][continues_on]")
{
using receiver_t = ex::__receiver_archetype<ex::env<>>;

auto nothrow = ex::continues_on(ex::just(), inline_scheduler{});
STATIC_REQUIRE(ex::__nothrow_connectable<decltype(nothrow), receiver_t>);

auto potentially_throwing =
ex::continues_on(ex::just(), potentially_throwing_connect_scheduler{});
STATIC_REQUIRE_FALSE(
ex::__nothrow_connectable<decltype(potentially_throwing), receiver_t>);
}

TEST_CASE("continues_on simple example", "[adaptors][continues_on]")
{
auto snd = ex::continues_on(ex::just(13), inline_scheduler{});
Expand Down