Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
change __sexpr so that the obj returned by get_state stores the r…
…eceiver
  • Loading branch information
ericniebler committed Jan 21, 2026
commit 3347a2965268a618c79c201973bd28753bc09dc7
32 changes: 19 additions & 13 deletions include/exec/into_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,35 +62,41 @@ namespace exec {
>;

struct __into_tuple_impl : __sexpr_defaults {
template <class _Receiver, class _Tuple>
struct __state {
using __tuple_t = _Tuple;
STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
_Receiver __rcvr_;
};

template <class _Sender, class... _Env>
static consteval auto get_completion_signatures() {
// TODO: port this to use constant evaluation
return __completions_t<__child_of<_Sender>, _Env...>{};
}

static constexpr auto get_state =
[]<class _Sender, class _Receiver>(_Sender &&, _Receiver &) {
return __mtype<__result_tuple_t<__child_of<_Sender>, env_of_t<_Receiver>>>();
[]<class _Sender, class _Receiver>(_Sender &&, _Receiver &&__rcvr) {
using __tuple_t = __result_tuple_t<__child_of<_Sender>, env_of_t<_Receiver>>;
return __state<_Receiver, __tuple_t>{static_cast<_Receiver &&>(__rcvr)};
};

static constexpr auto complete =
[]<class _State, class _Receiver, class _Tag, class... _Args>(
__ignore,
_State,
_Receiver &__rcvr,
_Tag,
_Args &&...__args) noexcept -> void {
static constexpr auto complete = []<class _State, class _Tag, class... _Args>(
__ignore,
_State &__state,
_Tag,
_Args &&...__args) noexcept -> void {
if constexpr (__std::same_as<_Tag, set_value_t>) {
using __tuple_t = __t<_State>;
using __tuple_t = _State::__tuple_t;
STDEXEC_TRY {
set_value(
static_cast<_Receiver &&>(__rcvr), __tuple_t{static_cast<_Args &&>(__args)...});
static_cast<_State &&>(__state).__rcvr_, __tuple_t{static_cast<_Args &&>(__args)...});
}
STDEXEC_CATCH_ALL {
STDEXEC::set_error(static_cast<_Receiver &&>(__rcvr), std::current_exception());
STDEXEC::set_error(static_cast<_State &&>(__state).__rcvr_, std::current_exception());
}
} else {
_Tag()(static_cast<_Receiver &&>(__rcvr), static_cast<_Args &&>(__args)...);
_Tag()(static_cast<_State &&>(__state).__rcvr_, static_cast<_Args &&>(__args)...);
}
};
};
Expand Down
70 changes: 28 additions & 42 deletions include/exec/repeat_effect_until.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
#pragma once

#include "../stdexec/__detail/__basic_sender.hpp"
#include "../stdexec/__detail/__manual_lifetime.hpp"
#include "../stdexec/__detail/__meta.hpp"
#include "../stdexec/__detail/__optional.hpp"
#include "../stdexec/execution.hpp"

#include "sequence.hpp"
Expand Down Expand Up @@ -59,7 +59,7 @@ namespace exec {
}

auto get_env() const noexcept -> env_of_t<_Receiver> {
return STDEXEC::get_env(__state_->__receiver());
return STDEXEC::get_env(__state_->__rcvr_);
}
};
};
Expand All @@ -71,50 +71,32 @@ namespace exec {
STDEXEC_PRAGMA_IGNORE_GNU("-Wtsan")

template <class _Sender, class _Receiver>
struct __repeat_effect_state
: STDEXEC::__enable_receiver_from_this<
_Sender,
_Receiver,
__repeat_effect_state<_Sender, _Receiver>
> {
struct __repeat_effect_state {
using __child_t = __decay_t<__data_of<_Sender>>;
using __receiver_t = STDEXEC::__t<__receiver<__id<_Sender>, __id<_Receiver>>>;
using __child_on_sched_sender_t =
__result_of<exec::sequence, schedule_result_t<trampoline_scheduler &>, __child_t &>;
using __child_op_t = STDEXEC::connect_result_t<__child_on_sched_sender_t, __receiver_t>;

__child_t __child_;
bool __has_child_op_ = false;
STDEXEC::__manual_lifetime<__child_op_t> __child_op_;
trampoline_scheduler __sched_;

__repeat_effect_state(_Sender &&__sndr, _Receiver &)
: __child_(STDEXEC::__get<1>(static_cast<_Sender &&>(__sndr))) {
explicit __repeat_effect_state(_Sender &&__sndr, _Receiver &&__rcvr)
: __rcvr_(static_cast<_Receiver &&>(__rcvr))
, __child_(STDEXEC::__get<1>(static_cast<_Sender &&>(__sndr))) {
__connect();
}

~__repeat_effect_state() {
if (__has_child_op_) {
__child_op_.__destroy();
}
}

void __connect() {
__child_op_.__construct_from([this] {
return STDEXEC::connect(
exec::sequence(STDEXEC::schedule(__sched_), __child_), __receiver_t{this});
});
__has_child_op_ = true;
__child_op_.__emplace_from(
STDEXEC::connect,
exec::sequence(STDEXEC::schedule(__sched_), __child_),
__receiver_t{this});
}

void __destroy() noexcept {
__child_op_.__destroy();
__has_child_op_ = false;
__child_op_.reset();
}

void __start() noexcept {
STDEXEC_ASSERT(__has_child_op_);
STDEXEC::start(__child_op_.__get());
STDEXEC::start(*__child_op_);
}

template <class _Tag, class... _Args>
Expand All @@ -123,12 +105,12 @@ namespace exec {
// If the sender completed with true, we're done
STDEXEC_TRY {
if constexpr ((__compile_time_bool_of<_Args, true> && ...)) {
STDEXEC::set_value(static_cast<_Receiver &&>(this->__receiver()));
STDEXEC::set_value(static_cast<_Receiver &&>(__rcvr_));
return;
} else if constexpr (!(__compile_time_bool_of<_Args, false> && ...)) {
const bool __done = (static_cast<bool>(static_cast<_Args &&>(__args)) && ...);
if (__done) {
STDEXEC::set_value(static_cast<_Receiver &&>(this->__receiver()));
STDEXEC::set_value(static_cast<_Receiver &&>(__rcvr_));
return;
}
}
Expand All @@ -137,25 +119,28 @@ namespace exec {
__connect();
}
STDEXEC_CATCH_ALL {
STDEXEC::set_error(
static_cast<_Receiver &&>(this->__receiver()), std::current_exception());
STDEXEC::set_error(static_cast<_Receiver &&>(__rcvr_), std::current_exception());
return;
}
STDEXEC::start(__child_op_.__get());
STDEXEC::start(*__child_op_);
}
STDEXEC_CATCH_ALL {
__destroy();
STDEXEC::set_error(
static_cast<_Receiver &&>(this->__receiver()), std::current_exception());
STDEXEC::set_error(static_cast<_Receiver &&>(__rcvr_), std::current_exception());
}
} else {
_Tag()(static_cast<_Receiver &&>(this->__receiver()), static_cast<_Args &&>(__args)...);
_Tag()(static_cast<_Receiver &&>(__rcvr_), static_cast<_Args &&>(__args)...);
}
}

_Receiver __rcvr_;
__child_t __child_;
STDEXEC::__optional<__child_op_t> __child_op_;
trampoline_scheduler __sched_;
};

template <class _Sender, class _Receiver>
__repeat_effect_state(_Sender &&, _Receiver &) -> __repeat_effect_state<_Sender, _Receiver>;
__repeat_effect_state(_Sender &&, _Receiver) -> __repeat_effect_state<_Sender, _Receiver>;

STDEXEC_PRAGMA_POP()

Expand Down Expand Up @@ -204,11 +189,12 @@ namespace exec {
};

static constexpr auto get_state =
[]<class _Sender, class _Receiver>(_Sender &&__sndr, _Receiver &__rcvr) {
return __repeat_effect_state{static_cast<_Sender &&>(__sndr), __rcvr};
[]<class _Sender, class _Receiver>(_Sender &&__sndr, _Receiver &&__rcvr) {
return __repeat_effect_state{
static_cast<_Sender &&>(__sndr), static_cast<_Receiver &&>(__rcvr)};
};

static constexpr auto start = [](auto &__state, __ignore) noexcept -> void {
static constexpr auto start = [](auto &__state) noexcept -> void {
__state.__start();
};
};
Expand Down
36 changes: 17 additions & 19 deletions include/exec/repeat_n.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace exec {
}

auto get_env() const noexcept -> env_of_t<_Receiver> {
return STDEXEC::get_env(__state_->__receiver());
return STDEXEC::get_env(__state_->__rcvr_);
}
};
};
Expand All @@ -78,21 +78,17 @@ namespace exec {
__child_count_pair(_Child, std::size_t) -> __child_count_pair<_Child>;

template <class _Sender, class _Receiver>
struct __repeat_n_state
: STDEXEC::__enable_receiver_from_this<
_Sender,
_Receiver,
__repeat_n_state<_Sender, _Receiver>
> {
struct __repeat_n_state {
using __child_count_pair_t = __decay_t<__data_of<_Sender>>;
using __child_t = decltype(__child_count_pair_t::__child_);
using __receiver_t = STDEXEC::__t<__receiver<__id<_Sender>, __id<_Receiver>>>;
using __child_on_sched_sender_t =
__result_of<exec::sequence, schedule_result_t<trampoline_scheduler &>, __child_t &>;
using __child_op_t = STDEXEC::connect_result_t<__child_on_sched_sender_t, __receiver_t>;

__repeat_n_state(_Sender &&__sndr, _Receiver &)
: __pair_(STDEXEC::__get<1>(static_cast<_Sender &&>(__sndr))) {
__repeat_n_state(_Sender &&__sndr, _Receiver &&__rcvr)
: __rcvr_(static_cast<_Receiver &&>(__rcvr))
, __pair_(STDEXEC::__get<1>(static_cast<_Sender &&>(__sndr))) {
// Q: should we skip __connect() if __count_ == 0?
__connect();
}
Expand All @@ -106,7 +102,7 @@ namespace exec {

void __start() noexcept {
if (__pair_.__count_ == 0) {
STDEXEC::set_value(static_cast<_Receiver &&>(this->__receiver()));
STDEXEC::set_value(static_cast<_Receiver &&>(__rcvr_));
} else {
STDEXEC::start(*__child_op_);
}
Expand All @@ -124,26 +120,27 @@ namespace exec {

if constexpr (__std::same_as<_Tag, set_value_t>) {
if (--__pair_.__count_ == 0) {
STDEXEC::set_value(std::move(this->__receiver()));
STDEXEC::set_value(std::move(__rcvr_));
} else {
STDEXEC::start(__connect());
}
} else {
_Tag()(std::move(this->__receiver()), static_cast<__decay_t<_Args> &&>(__arg_copy)...);
_Tag()(std::move(__rcvr_), static_cast<__decay_t<_Args> &&>(__arg_copy)...);
}
}
STDEXEC_CATCH_ALL {
STDEXEC::set_error(std::move(this->__receiver()), std::current_exception());
STDEXEC::set_error(std::move(__rcvr_), std::current_exception());
}
}

_Receiver __rcvr_;
__child_count_pair<__child_t> __pair_;
STDEXEC::__optional<__child_op_t> __child_op_;
trampoline_scheduler __sched_;
};

template <class _Sender, class _Receiver>
__repeat_n_state(_Sender &&, _Receiver &) -> __repeat_n_state<_Sender, _Receiver>;
__repeat_n_state(_Sender &&, _Receiver) -> __repeat_n_state<_Sender, _Receiver>;

struct repeat_n_t;
struct _REPEAT_N_EXPECTS_A_SENDER_OF_VOID_;
Expand Down Expand Up @@ -186,12 +183,13 @@ namespace exec {
return __completions_t<__data_of<_Sender>, _Env...>{};
}

static constexpr auto get_state =
[]<class _Sender, class _Receiver>(_Sender &&__sndr, _Receiver &__rcvr) {
return __repeat_n_state{static_cast<_Sender &&>(__sndr), __rcvr};
};
static constexpr auto get_state = []<class _Sender, class _Receiver>(
_Sender &&__sndr,
_Receiver &&__rcvr) {
return __repeat_n_state{static_cast<_Sender &&>(__sndr), static_cast<_Receiver &&>(__rcvr)};
};

static constexpr auto start = [](auto &__state, __ignore) noexcept -> void {
static constexpr auto start = [](auto &__state) noexcept -> void {
__state.__start();
};
};
Expand Down
17 changes: 8 additions & 9 deletions include/exec/unless_stop_requested.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,15 @@ namespace exec {
};

static constexpr auto start = //
[]<class _State, class _Receiver, class _Operation>(
_State&,
_Receiver& __rcvr,
_Operation& __child_op) noexcept -> void {
static_assert(!__unstoppable_receiver<_Receiver>);
if (get_stop_token(STDEXEC::get_env(__rcvr)).stop_requested()) {
STDEXEC::set_stopped((_Receiver&&) __rcvr);
return;
[]<class _State, class _Operation>(_State& __state, _Operation& __child_op) noexcept
-> void {
using __receiver_t = _State::__receiver_t;
static_assert(!__unstoppable_receiver<__receiver_t>);
if (get_stop_token(STDEXEC::get_env(__state.__rcvr_)).stop_requested()) {
STDEXEC::set_stopped(static_cast<__receiver_t&&>(__state.__rcvr_));
} else {
STDEXEC::start(__child_op);
}
STDEXEC::start(__child_op);
};

static constexpr __connect_fn connect{};
Expand Down
Loading
Loading