Skip to content

Commit 7227374

Browse files
committed
updated the simple_counting_scope implementation
1 parent 170901f commit 7227374

File tree

6 files changed

+339
-158
lines changed

6 files changed

+339
-158
lines changed

include/beman/execution/detail/simple_counting_scope.hpp

Lines changed: 128 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@
77
#include <beman/execution/detail/sender.hpp>
88
#include <beman/execution/detail/notify.hpp>
99
#include <beman/execution/detail/immovable.hpp>
10+
#include <beman/execution/detail/make_sender.hpp>
11+
#include <beman/execution/detail/impls_for.hpp>
12+
#include <beman/execution/detail/default_impls.hpp>
13+
#include <beman/execution/detail/connect.hpp>
14+
#include <beman/execution/detail/schedule.hpp>
15+
#include <beman/execution/detail/get_scheduler.hpp>
16+
#include <beman/execution/detail/get_env.hpp>
1017
#include <atomic>
18+
#include <exception>
1119
#include <mutex>
1220
#include <utility>
1321
#include <cstdlib>
@@ -18,12 +26,89 @@ namespace beman::execution {
1826
class simple_counting_scope;
1927
}
2028

29+
namespace beman::execution::detail {
30+
struct simple_counting_scope_join_t {};
31+
struct simple_counting_scope_state_base {
32+
::beman::execution::simple_counting_scope* scope;
33+
::beman::execution::detail::simple_counting_scope_state_base* next{};
34+
simple_counting_scope_state_base(::beman::execution::simple_counting_scope* s) : scope(s) {}
35+
virtual ~simple_counting_scope_state_base() = default;
36+
auto start() noexcept -> void;
37+
38+
virtual auto complete() noexcept -> void = 0;
39+
virtual auto complete_inline() noexcept -> void = 0;
40+
};
41+
42+
template <typename Env>
43+
struct completion_signatures_for_impl<
44+
::beman::execution::detail::basic_sender<::beman::execution::detail::simple_counting_scope_join_t,
45+
::beman::execution::simple_counting_scope*>,
46+
Env> {
47+
using type = ::beman::execution::completion_signatures<::beman::execution::set_value_t()>;
48+
};
49+
50+
template <>
51+
struct impls_for<::beman::execution::detail::simple_counting_scope_join_t>
52+
: ::beman::execution::detail::default_impls {
53+
template <typename Receiver>
54+
struct state : ::beman::execution::detail::simple_counting_scope_state_base {
55+
::std::remove_cvref_t<Receiver>& receiver;
56+
using op_t = decltype(::beman::execution::connect(
57+
::beman::execution::schedule(::beman::execution::get_scheduler(::beman::execution::get_env(receiver))),
58+
receiver));
59+
op_t op;
60+
state(::beman::execution::simple_counting_scope* s, Receiver& r)
61+
: ::beman::execution::detail::simple_counting_scope_state_base(s),
62+
receiver(r),
63+
op(::beman::execution::connect(::beman::execution::schedule(::beman::execution::get_scheduler(
64+
::beman::execution::get_env(this->receiver))),
65+
this->receiver)) {}
66+
auto complete() noexcept -> void override { ::beman::execution::start(this->op); }
67+
auto complete_inline() noexcept -> void override {
68+
::beman::execution::set_value(::std::move(this->receiver));
69+
}
70+
};
71+
72+
static constexpr auto get_state = []<typename Receiver>(auto&& sender, Receiver& receiver) noexcept(false) {
73+
auto [_, self] = sender;
74+
return state<Receiver>(self, receiver);
75+
};
76+
static constexpr auto start = [](::beman::execution::detail::simple_counting_scope_state_base& s, auto&) noexcept {
77+
s.start();
78+
};
79+
};
80+
} // namespace beman::execution::detail
81+
2182
// ----------------------------------------------------------------------------
2283

2384
class beman::execution::simple_counting_scope : ::beman::execution::detail::immovable {
85+
private:
86+
friend struct ::beman::execution::detail::simple_counting_scope_state_base;
87+
enum class state_t : unsigned char {
88+
unused,
89+
open,
90+
open_and_joining,
91+
closed,
92+
closed_and_joining,
93+
unused_and_closed,
94+
joined
95+
};
96+
2497
public:
2598
class token;
26-
class assoc;
99+
100+
simple_counting_scope() = default;
101+
simple_counting_scope(simple_counting_scope&&) = delete;
102+
~simple_counting_scope() {
103+
switch (this->state) {
104+
default:
105+
::std::terminate();
106+
case state_t::unused:
107+
case state_t::unused_and_closed:
108+
case state_t::joined:
109+
break;
110+
}
111+
}
27112

28113
auto get_token() noexcept -> token;
29114
auto close() noexcept -> void {
@@ -42,43 +127,24 @@ class beman::execution::simple_counting_scope : ::beman::execution::detail::immo
42127
}
43128
}
44129
auto join() noexcept {
45-
bool complete{false};
46-
{
47-
::std::lock_guard kerberos(this->mutex);
48-
if (0u == this->count) {
49-
this->state = state_t::joined;
50-
complete = true;
51-
}
52-
}
53-
if (complete) {
54-
n.complete();
55-
}
56-
return ::beman::execution::detail::notify(this->n);
130+
return ::beman::execution::detail::make_sender(::beman::execution::detail::simple_counting_scope_join_t{},
131+
this);
57132
}
58133

59134
private:
60-
enum class state_t : unsigned char {
61-
unused,
62-
open,
63-
open_and_joining,
64-
closed,
65-
closed_and_joining,
66-
unused_and_closed,
67-
joined
68-
};
69-
friend class assoc;
70-
auto try_associate() noexcept -> simple_counting_scope* {
135+
friend class token;
136+
auto try_associate() noexcept -> bool {
71137
::std::lock_guard lock(this->mutex);
72138
switch (this->state) {
73139
default:
74-
return nullptr;
140+
return false;
75141
case state_t::unused:
76142
this->state = state_t::open; // fall-through!
77143
[[fallthrough]];
78144
case state_t::open:
79145
case state_t::open_and_joining:
80146
++this->count;
81-
return this;
147+
return true;
82148
}
83149
}
84150
auto disassociate() noexcept -> void {
@@ -88,53 +154,34 @@ class beman::execution::simple_counting_scope : ::beman::execution::detail::immo
88154
return;
89155
this->state = state_t::joined;
90156
}
91-
n.complete();
157+
this->complete();
158+
}
159+
auto complete() noexcept -> void {
160+
auto current{[this] {
161+
::std::lock_guard lock(this->mutex);
162+
return ::std::exchange(this->head, nullptr);
163+
}()};
164+
while (current) {
165+
::std::exchange(current, current->next)->complete();
166+
}
92167
}
93168
::std::mutex mutex;
94169
::std::size_t count{};
95170
state_t state{state_t::unused};
96-
::beman::execution::detail::notifier n;
171+
::beman::execution::detail::simple_counting_scope_state_base* head{};
97172
};
98173

99174
// ----------------------------------------------------------------------------
100175

101-
// NOLINTBEGIN(misc-unconventional-assign-operator,hicpp-special-member-functions)
102-
class beman::execution::simple_counting_scope::assoc {
103-
public:
104-
assoc() = default;
105-
assoc(const assoc& other) noexcept : assoc(other.scope) {}
106-
assoc(assoc&& other) noexcept : scope(::std::exchange(other.scope, nullptr)) {}
107-
~assoc() {
108-
if (this->scope)
109-
this->scope->disassociate();
110-
}
111-
112-
auto operator=(assoc other) noexcept -> assoc& {
113-
::std::swap(this->scope, other.scope);
114-
return *this;
115-
}
116-
117-
explicit operator bool() const noexcept { return this->scope != nullptr; }
118-
119-
private:
120-
friend class beman::execution::simple_counting_scope::token;
121-
explicit assoc(beman::execution::simple_counting_scope* scp) : scope(scp ? scp->try_associate() : nullptr) {}
122-
beman::execution::simple_counting_scope* scope{};
123-
};
124-
// NOLINTEND(misc-unconventional-assign-operator,hicpp-special-member-functions)
125-
126-
// ----------------------------------------------------------------------------
127-
128176
class beman::execution::simple_counting_scope::token {
129177
public:
130178
template <::beman::execution::sender Sender>
131179
auto wrap(Sender&& sender) const noexcept -> Sender&& {
132180
return ::std::forward<Sender>(sender);
133181
}
134182

135-
auto try_associate() const -> beman::execution::simple_counting_scope::assoc {
136-
return beman::execution::simple_counting_scope::assoc(this->scope);
137-
}
183+
auto try_associate() const noexcept -> bool { return this->scope->try_associate(); }
184+
auto disassociate() const noexcept -> void { this->scope->disassociate(); }
138185

139186
private:
140187
friend class beman::execution::simple_counting_scope;
@@ -149,6 +196,29 @@ inline auto beman::execution::simple_counting_scope::get_token() noexcept
149196
return beman::execution::simple_counting_scope::token(this);
150197
}
151198

199+
auto beman::execution::detail::simple_counting_scope_state_base::start() noexcept -> void {
200+
switch (this->scope->state) {
201+
case ::beman::execution::simple_counting_scope::state_t::unused:
202+
case ::beman::execution::simple_counting_scope::state_t::unused_and_closed:
203+
case ::beman::execution::simple_counting_scope::state_t::joined:
204+
this->scope->state = ::beman::execution::simple_counting_scope::state_t::joined;
205+
this->complete_inline();
206+
return;
207+
case ::beman::execution::simple_counting_scope::state_t::open:
208+
this->scope->state = ::beman::execution::simple_counting_scope::state_t::open_and_joining;
209+
break;
210+
case ::beman::execution::simple_counting_scope::state_t::open_and_joining:
211+
break;
212+
case ::beman::execution::simple_counting_scope::state_t::closed:
213+
this->scope->state = ::beman::execution::simple_counting_scope::state_t::closed_and_joining;
214+
break;
215+
case ::beman::execution::simple_counting_scope::state_t::closed_and_joining:
216+
break;
217+
}
218+
::std::lock_guard kerberos(this->scope->mutex);
219+
this->next = std::exchange(this->scope->head, this);
220+
}
221+
152222
// ----------------------------------------------------------------------------
153223

154224
#endif

tests/beman/execution/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ endif()
1111
list(
1212
APPEND
1313
execution_tests
14+
exec-scope-simple-counting.test
1415
exec-scope-concepts.test
1516
exec-nest.test
1617
issue-144.test
1718
exec-on.test
1819
notify.test
19-
exec-scounting.test
2020
exec-awaitable.test
2121
allocator-requirements-general.test
2222
exec-connect.test
@@ -134,6 +134,7 @@ foreach(test ${execution_tests})
134134
add_test(NAME ${TEST_EXE} COMMAND $<TARGET_FILE:${TEST_EXE}>)
135135
endforeach()
136136

137+
if(FALSE)
137138
if(NOT PROJECT_IS_TOP_LEVEL AND BEMAN_EXECUTION_ENABLE_TESTING)
138139
# test if the targets are findable from the build directory
139140
# cmake-format: off
@@ -156,3 +157,4 @@ if(NOT PROJECT_IS_TOP_LEVEL AND BEMAN_EXECUTION_ENABLE_TESTING)
156157
)
157158
# cmake-format: on
158159
endif()
160+
endif()

0 commit comments

Comments
 (0)