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 {
1826class 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
2384class 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-
128176class 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
0 commit comments