@@ -56,23 +56,28 @@ class connection
5656{
5757 template <typename Signature, typename Combiner>
5858 friend class signal ;
59-
60- /*
61- * Tag for the constructor used by signal.
59+ /* *
60+ * Track liveness. Also serves as a tag for the constructor used by signal.
6261 */
63- struct enabled_tag_type {
62+ class liveness
63+ {
64+ friend class connection ;
65+ std::atomic_bool m_connected{true };
66+
67+ void disconnect () { m_connected.store (false ); }
68+ public:
69+ bool connected () const { return m_connected.load (); }
6470 };
65- static constexpr enabled_tag_type enabled_tag{};
6671
6772 /* *
6873 * connections have shared_ptr-like copy and move semantics.
6974 */
70- std::shared_ptr<std::atomic_bool> m_connected {};
75+ std::shared_ptr<liveness> m_state {};
7176
7277 /* *
7378 * Only a signal can create an enabled connection.
7479 */
75- explicit connection (enabled_tag_type /* unused */ ) : m_connected {std::make_shared<std::atomic_bool>( true )} {}
80+ explicit connection (std::shared_ptr<liveness>&& state ) : m_state {std::move (state)} {}
7681
7782public:
7883 /* *
@@ -92,8 +97,8 @@ class connection
9297 */
9398 void disconnect ()
9499 {
95- if (m_connected ) {
96- m_connected-> store ( false );
100+ if (m_state ) {
101+ m_state-> disconnect ( );
97102 }
98103 }
99104
@@ -103,7 +108,7 @@ class connection
103108 */
104109 bool connected () const
105110 {
106- return m_connected && m_connected-> load ();
111+ return m_state && m_state-> connected ();
107112 }
108113};
109114
@@ -148,23 +153,19 @@ class signal
148153 static_assert (std::is_same_v<Combiner, optional_last_value<typename function_type::result_type>>, " only the optional_last_value combiner is supported" );
149154
150155 /*
151- * Helper struct for maintaining a callback and its associated connection
156+ * Helper struct for maintaining a callback and its associated connection liveness
152157 */
153- struct connection_holder {
158+ struct connection_holder : connection::liveness {
154159 template <typename Callable>
155160 connection_holder (Callable&& callback) : m_callback{std::forward<Callable>(callback)}
156161 {
157162 }
158163
159- connection m_connection{connection::enabled_tag};
160- function_type m_callback;
164+ const function_type m_callback;
161165 };
162166
163167 mutable Mutex m_mutex;
164168
165- /* Store connection_holders as shared_ptrs to avoid having to copy them by
166- * value in operator().
167- */
168169 std::vector<std::shared_ptr<connection_holder>> m_connections GUARDED_BY (m_mutex){};
169170
170171public:
@@ -208,14 +209,14 @@ class signal
208209 }
209210 if constexpr (std::is_void_v<result_type>) {
210211 for (const auto & connection : connections) {
211- if (connection->m_connection . connected ()) {
212+ if (connection->connected ()) {
212213 connection->m_callback (args...);
213214 }
214215 }
215216 } else {
216217 result_type ret{std::nullopt };
217218 for (const auto & connection : connections) {
218- if (connection->m_connection . connected ()) {
219+ if (connection->connected ()) {
219220 ret.emplace (connection->m_callback (args...));
220221 }
221222 }
@@ -233,10 +234,10 @@ class signal
233234 LOCK (m_mutex);
234235
235236 // Garbage-collect disconnected connections to prevent unbounded growth
236- std::erase_if (m_connections, [](const auto & holder) { return !holder->m_connection . connected (); });
237+ std::erase_if (m_connections, [](const auto & holder) { return !holder->connected (); });
237238
238- const auto & connection = m_connections.emplace_back (std::make_shared<connection_holder>(std::forward<Callable>(func)));
239- return connection-> m_connection ;
239+ const auto & entry = m_connections.emplace_back (std::make_shared<connection_holder>(std::forward<Callable>(func)));
240+ return connection (entry) ;
240241 }
241242
242243 /*
@@ -246,7 +247,7 @@ class signal
246247 {
247248 LOCK (m_mutex);
248249 return std::ranges::none_of (m_connections, [](const auto & holder) {
249- return holder->m_connection . connected ();
250+ return holder->connected ();
250251 });
251252 }
252253};
0 commit comments