Skip to content

Commit 97cf943

Browse files
committed
implemented and initial version of spawn
1 parent 6057be8 commit 97cf943

File tree

7 files changed

+295
-25
lines changed

7 files changed

+295
-25
lines changed

include/beman/execution/detail/spawn.hpp

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,92 @@
11
// include/beman/execution/detail/spawn.hpp -*-C++-*-
2-
// ----------------------------------------------------------------------------
32
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4-
// ----------------------------------------------------------------------------
53

64
#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN
75
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN
86

7+
#include <beman/execution/detail/spawn_get_allocator.hpp>
8+
#include <beman/execution/detail/async_scope_token.hpp>
9+
#include <beman/execution/detail/empty_env.hpp>
10+
#include <beman/execution/detail/sender.hpp>
11+
#include <beman/execution/detail/receiver.hpp>
12+
#include <beman/execution/detail/connect_result_t.hpp>
13+
#include <beman/execution/detail/connect.hpp>
14+
#include <beman/execution/detail/start.hpp>
15+
#include <beman/execution/detail/write_env.hpp>
16+
#include <memory>
17+
#include <utility>
18+
919
// ----------------------------------------------------------------------------
1020

11-
namespace nstd {
12-
namespace xxx {}
13-
} // namespace nstd
21+
namespace beman::execution::detail {
22+
struct spawn_t {
23+
struct state_base {
24+
virtual ~state_base() = default;
25+
virtual auto complete() noexcept -> void = 0;
26+
};
27+
28+
struct receiver {
29+
using receiver_concept = ::beman::execution::receiver_t;
30+
state_base* state{};
31+
32+
auto set_value() && noexcept -> void { this->state->complete(); }
33+
auto set_stopped() && noexcept -> void { this->state->complete(); }
34+
};
35+
36+
template <typename Alloc, ::beman::execution::async_scope_token Tok, ::beman::execution::sender Sndr>
37+
struct state : state_base {
38+
using op_t = ::beman::execution::connect_result_t<Sndr, receiver>;
39+
using alloc_t = typename ::std::allocator_traits<Alloc>::template rebind_alloc<state>;
40+
using traits_t = ::std::allocator_traits<alloc_t>;
41+
42+
state(Alloc a, Sndr&& sndr, Tok tok)
43+
: alloc(a), op(::beman::execution::connect(::std::forward<Sndr>(sndr), receiver{this})), token(tok) {
44+
if (this->token.try_associate()) {
45+
::beman::execution::start(this->op);
46+
} else {
47+
this->destroy();
48+
}
49+
}
50+
auto complete() noexcept -> void override {
51+
Tok tok(this->token);
52+
this->destroy();
53+
tok.disassociate();
54+
}
55+
auto destroy() noexcept -> void {
56+
alloc_t all(this->alloc);
57+
traits_t::destroy(all, this);
58+
traits_t::deallocate(all, this, 1);
59+
}
60+
61+
alloc_t alloc;
62+
op_t op;
63+
Tok token;
64+
};
65+
66+
template <::beman::execution::sender Sender, ::beman::execution::async_scope_token Token, typename Env>
67+
auto operator()(Sender&& sender, Token&& tok, Env&& env) const {
68+
auto new_sender{tok.wrap(::std::forward<Sender>(sender))};
69+
auto [all, senv] = ::beman::execution::detail::spawn_get_allocator(new_sender, env);
70+
71+
using sender_t = decltype(::beman::execution::write_env(::std::move(new_sender), senv));
72+
using state_t = state<decltype(all), Token, sender_t>;
73+
using alloc_t = typename ::std::allocator_traits<decltype(all)>::template rebind_alloc<state_t>;
74+
using traits_t = ::std::allocator_traits<alloc_t>;
75+
alloc_t alloc(all);
76+
state_t* op{traits_t::allocate(alloc, 1u)};
77+
traits_t::construct(alloc, op, all, ::beman::execution::write_env(::std::move(new_sender), senv), tok);
78+
}
79+
template <::beman::execution::sender Sender, ::beman::execution::async_scope_token Token>
80+
auto operator()(Sender&& sender, Token&& token) const {
81+
return (*this)(::std::forward<Sender>(sender), ::std::forward<Token>(token), ::beman::execution::empty_env{});
82+
}
83+
};
84+
} // namespace beman::execution::detail
85+
86+
namespace beman::execution {
87+
using spawn_t = ::beman::execution::detail::spawn_t;
88+
inline constexpr spawn_t spawn{};
89+
} // namespace beman::execution
1490

1591
// ----------------------------------------------------------------------------
1692

include/beman/execution/detail/spawn_future.hpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
55
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_FUTURE
66

7+
#include <beman/execution/detail/spawn_get_allocator.hpp>
78
#include <beman/execution/detail/as_tuple.hpp>
89
#include <beman/execution/detail/async_scope_token.hpp>
910
#include <beman/execution/detail/completion_signatures_of_t.hpp>
@@ -216,20 +217,6 @@ struct spawn_future_state
216217
auto (*fun)(void*, spawn_future_state&) noexcept -> void = nullptr;
217218
};
218219

219-
template <::beman::execution::sender Sndr, typename Ev>
220-
auto spawn_future_get_allocator(const Sndr& sndr, const Ev& ev) {
221-
if constexpr (requires { ::beman::execution::get_allocator(ev); }) {
222-
return ::std::pair(::beman::execution::get_allocator(ev), ev);
223-
} else if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(sndr)); }) {
224-
auto alloc{::beman::execution::get_allocator(::beman::execution::get_env(sndr))};
225-
return ::std::pair(alloc,
226-
::beman::execution::detail::join_env(
227-
::beman::execution::prop(::beman::execution::get_allocator, alloc), ev));
228-
} else {
229-
return ::std::pair(::std::allocator<void>{}, ev);
230-
}
231-
}
232-
233220
class spawn_future_t {
234221
public:
235222
template <::beman::execution::sender Sndr, ::beman::execution::async_scope_token Tok, typename Ev>
@@ -241,7 +228,7 @@ class spawn_future_t {
241228
using sndr_t = decltype(make());
242229
static_assert(::beman::execution::sender<Sndr>);
243230

244-
auto [alloc, senv] = spawn_future_get_allocator(sndr, ev);
231+
auto [alloc, senv] = spawn_get_allocator(sndr, ev);
245232
using state_t = ::beman::execution::detail::spawn_future_state<decltype(alloc), Tok, sndr_t, decltype(senv)>;
246233
using state_alloc_t = typename ::std::allocator_traits<decltype(alloc)>::template rebind_alloc<state_t>;
247234
using state_traits_t = ::std::allocator_traits<state_alloc_t>;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// include/beman/execution/detail/spawn_get_allocator.hpp -*-C++-*-
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_GET_ALLOCATOR
5+
#define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_SPAWN_GET_ALLOCATOR
6+
7+
#include <beman/execution/detail/get_allocator.hpp>
8+
#include <beman/execution/detail/get_env.hpp>
9+
#include <beman/execution/detail/join_env.hpp>
10+
#include <beman/execution/detail/prop.hpp>
11+
#include <beman/execution/detail/sender.hpp>
12+
#include <memory>
13+
#include <utility>
14+
15+
// ----------------------------------------------------------------------------
16+
17+
namespace beman::execution::detail {
18+
template <::beman::execution::sender Sndr, typename Ev>
19+
auto spawn_get_allocator(const Sndr& sndr, const Ev& ev) {
20+
if constexpr (requires { ::beman::execution::get_allocator(ev); }) {
21+
return ::std::pair(::beman::execution::get_allocator(ev), ev);
22+
} else if constexpr (requires { ::beman::execution::get_allocator(::beman::execution::get_env(sndr)); }) {
23+
auto alloc{::beman::execution::get_allocator(::beman::execution::get_env(sndr))};
24+
return ::std::pair(alloc,
25+
::beman::execution::detail::join_env(
26+
::beman::execution::prop(::beman::execution::get_allocator, alloc), ev));
27+
} else {
28+
return ::std::pair(::std::allocator<void>{}, ev);
29+
}
30+
}
31+
32+
} // namespace beman::execution::detail
33+
34+
// ----------------------------------------------------------------------------
35+
36+
#endif

src/beman/execution/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ target_sources(
167167
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/single_sender_value_type.hpp
168168
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/spawn.hpp
169169
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/spawn_future.hpp
170+
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/spawn_get_allocator.hpp
170171
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/split.hpp
171172
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/start.hpp
172173
${PROJECT_SOURCE_DIR}/include/beman/execution/detail/starts_on.hpp

tests/beman/execution/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ endif()
1111
list(
1212
APPEND
1313
execution_tests
14+
exec-spawn.test
1415
exec-stop-when.test
1516
exec-prop.test
1617
exec-scope-simple-counting.test

tests/beman/execution/exec-spawn-future.test.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

44
#include <beman/execution/detail/spawn_future.hpp>
5+
#include <beman/execution/detail/spawn_get_allocator.hpp>
56
#include <beman/execution/detail/queryable.hpp>
67
#include <beman/execution/detail/sender.hpp>
78
#include <beman/execution/detail/async_scope_token.hpp>
@@ -248,21 +249,21 @@ static_assert(test_std::sender<alloc_sender>);
248249
auto test_get_allocator() {
249250
{
250251
alloc_env ae{87};
251-
auto [alloc, ev] = test_detail::spawn_future_get_allocator(sender<>{}, ae);
252+
auto [alloc, ev] = test_detail::spawn_get_allocator(sender<>{}, ae);
252253
static_assert(std::same_as<decltype(alloc), allocator>);
253254
ASSERT(alloc == allocator{87});
254255
static_assert(std::same_as<decltype(ev), alloc_env>);
255256
ASSERT(ev == alloc_env{87});
256257
}
257258
{
258-
auto [alloc, ev] = test_detail::spawn_future_get_allocator(alloc_sender{53}, env{42});
259+
auto [alloc, ev] = test_detail::spawn_get_allocator(alloc_sender{53}, env{42});
259260
static_assert(std::same_as<decltype(alloc), allocator>);
260261
ASSERT(alloc == allocator{53});
261262
ASSERT(test_std::get_allocator(ev) == allocator{53});
262263
}
263264
{
264265
test_std::inplace_stop_source source;
265-
auto [alloc, ev] = test_detail::spawn_future_get_allocator(
266+
auto [alloc, ev] = test_detail::spawn_get_allocator(
266267
alloc_sender{53}, test_std::prop(test_std::get_stop_token, source.get_token()));
267268
static_assert(std::same_as<decltype(alloc), allocator>);
268269
ASSERT(alloc == allocator{53});
@@ -271,7 +272,7 @@ auto test_get_allocator() {
271272
}
272273
{
273274
test_std::inplace_stop_source source;
274-
auto [alloc, ev] = test_detail::spawn_future_get_allocator(
275+
auto [alloc, ev] = test_detail::spawn_get_allocator(
275276
alloc_sender{53},
276277
test_detail::join_env(test_std::prop(test_std::get_allocator, allocator(101)),
277278
test_std::prop(test_std::get_stop_token, source.get_token())));
@@ -281,7 +282,7 @@ auto test_get_allocator() {
281282
ASSERT(test_std::get_stop_token(ev) == source.get_token());
282283
}
283284
{
284-
auto [alloc, ev] = test_detail::spawn_future_get_allocator(sender<>{}, env{42});
285+
auto [alloc, ev] = test_detail::spawn_get_allocator(sender<>{}, env{42});
285286
static_assert(std::same_as<decltype(alloc), std::allocator<void>>);
286287
static_assert(std::same_as<decltype(ev), env>);
287288
ASSERT(ev == env{42});

0 commit comments

Comments
 (0)