Skip to content

Commit 3abc52f

Browse files
committed
merge the __submit implementation into start_detached for stdexec/
1 parent c25517a commit 3abc52f

4 files changed

Lines changed: 70 additions & 161 deletions

File tree

include/stdexec/__detail/__receiver_ref.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "__execution_fwd.hpp"
1919

2020
#include "__completion_signatures.hpp"
21-
#include "__env.hpp"
2221
#include "__receivers.hpp"
2322

2423
#include <functional>

include/stdexec/__detail/__start_detached.hpp

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,76 @@
1717

1818
#include "__execution_fwd.hpp"
1919

20+
#include <memory>
21+
2022
#include "__meta.hpp"
2123
#include "__env.hpp"
2224
#include "__receivers.hpp"
23-
#include "__submit.hpp"
25+
#include "__env.hpp"
26+
#include "__scope.hpp"
2427
#include "__transform_sender.hpp"
25-
#include "__type_traits.hpp"
2628

2729
namespace stdexec {
2830
/////////////////////////////////////////////////////////////////////////////
2931
// [execution.senders.consumer.start_detached]
3032
namespace __start_detached {
31-
template <class _EnvId>
32-
struct __detached_receiver {
33-
using _Env = stdexec::__t<_EnvId>;
33+
template <class _SenderId, class _EnvId>
34+
struct __operation {
35+
using _Sender = __cvref_t<_SenderId>;
36+
using _Env = __t<_EnvId>;
37+
38+
explicit __operation(_Sender&& __sndr, _Env __env)
39+
: __env_(static_cast<_Env&&>(__env))
40+
, __op_state_(connect(static_cast<_Sender&&>(__sndr), __receiver{this})) {
41+
}
3442

35-
struct __t {
43+
static void __destroy_delete(__operation* __self) noexcept {
44+
if constexpr (__callable<get_allocator_t, _Env>) {
45+
auto __alloc = stdexec::get_allocator(__self->__env_);
46+
using _Alloc = decltype(__alloc);
47+
using _OpAlloc =
48+
typename std::allocator_traits<_Alloc>::template rebind_alloc<__operation>;
49+
_OpAlloc __op_alloc{__alloc};
50+
std::allocator_traits<_OpAlloc>::destroy(__op_alloc, __self);
51+
std::allocator_traits<_OpAlloc>::deallocate(__op_alloc, __self, 1);
52+
} else {
53+
delete __self;
54+
}
55+
}
56+
57+
// The start_detached receiver deletes the operation state.
58+
struct __receiver {
3659
using receiver_concept = receiver_t;
37-
using __id = __detached_receiver;
38-
STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
60+
using __t = __receiver;
61+
using __id = __receiver;
3962

4063
template <class... _As>
4164
void set_value(_As&&...) noexcept {
65+
__operation::__destroy_delete(__op_); // NB: invalidates *this
4266
}
4367

4468
template <class _Error>
4569
[[noreturn]]
4670
void set_error(_Error&&) noexcept {
71+
// A detached operation failed. There is noplace for the error to go.
72+
// This is unrecoverable, so we terminate.
4773
std::terminate();
4874
}
4975

5076
void set_stopped() noexcept {
77+
__operation::__destroy_delete(__op_); // NB: invalidates *this
5178
}
5279

5380
auto get_env() const noexcept -> const _Env& {
54-
// BUGBUG NOT TO SPEC
55-
return __env_;
81+
return __op_->__env_;
5682
}
83+
84+
__operation* __op_;
5785
};
58-
};
5986

60-
template <class _Env = env<>>
61-
using __detached_receiver_t = __t<__detached_receiver<__id<__decay_t<_Env>>>>;
87+
STDEXEC_ATTRIBUTE((no_unique_address)) _Env __env_;
88+
connect_result_t<_Sender, __receiver> __op_state_;
89+
};
6290

6391
struct start_detached_t {
6492
template <sender_in<__root_env> _Sender>
@@ -84,11 +112,36 @@ namespace stdexec {
84112
__as_root_env(static_cast<_Env&&>(__env)));
85113
}
86114

115+
// Below is the default implementation for `start_detached`.
87116
template <class _Sender, class _Env = __root_env>
88-
requires sender_to<_Sender, __detached_receiver_t<_Env>>
89-
void apply_sender(_Sender&& __sndr, _Env&& __env = {}) const {
90-
__submit(
91-
static_cast<_Sender&&>(__sndr), __detached_receiver_t<_Env>{static_cast<_Env&&>(__env)});
117+
requires sender_in<_Sender, __as_root_env_t<_Env>>
118+
void apply_sender(_Sender&& __sndr, _Env&& __env = {}) const noexcept(false) {
119+
using _Op = __operation<__cvref_id<_Sender>, __id<__decay_t<_Env>>>;
120+
// Use the provided allocator, if any, to allocate the operation state.
121+
if constexpr (__callable<get_allocator_t, _Env>) {
122+
auto __alloc = get_allocator(__env);
123+
using _Alloc = decltype(__alloc);
124+
using _OpAlloc = typename std::allocator_traits<_Alloc>::template rebind_alloc<_Op>;
125+
// We use the allocator to allocate the operation state and also to construct
126+
// it.
127+
_OpAlloc __op_alloc{__alloc};
128+
_Op* __op = std::allocator_traits<_OpAlloc>::allocate(__op_alloc, 1);
129+
__scope_guard __g{[__op, &__op_alloc]() noexcept {
130+
std::allocator_traits<_OpAlloc>::deallocate(__op_alloc, __op, 1);
131+
}};
132+
// This can potentially throw. If it does, the scope guard will deallocate the
133+
// storage automatically.
134+
std::allocator_traits<_OpAlloc>::construct(
135+
__op_alloc, __op, static_cast<_Sender&&>(__sndr), static_cast<_Env&&>(__env));
136+
// The operation state is now constructed, dismiss the scope guard.
137+
__g.__dismiss();
138+
// This cannot throw:
139+
stdexec::start(__op->__op_state_);
140+
} else {
141+
// The caller did not provide an allocator, so we use the default allocator.
142+
_Op* __op = new _Op(static_cast<_Sender&&>(__sndr), static_cast<_Env&&>(__env));
143+
start(__op->__op_state_);
144+
}
92145
}
93146
};
94147
} // namespace __start_detached

include/stdexec/__detail/__submit.hpp

Lines changed: 0 additions & 142 deletions
This file was deleted.

include/stdexec/execution.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
#include "__detail/__starts_on.hpp" // IWYU pragma: export
5353
#include "__detail/__stopped_as_error.hpp" // IWYU pragma: export
5454
#include "__detail/__stopped_as_optional.hpp" // IWYU pragma: export
55-
#include "__detail/__submit.hpp" // IWYU pragma: export
5655
#include "__detail/__sync_wait.hpp" // IWYU pragma: export
5756
#include "__detail/__then.hpp" // IWYU pragma: export
5857
#include "__detail/__transfer_just.hpp" // IWYU pragma: export

0 commit comments

Comments
 (0)