Chris@16
|
1 /*
|
Chris@16
|
2 boost::signals2::connection provides a handle to a signal/slot connection.
|
Chris@16
|
3
|
Chris@16
|
4 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
|
Chris@16
|
5 Begin: 2007-01-23
|
Chris@16
|
6 */
|
Chris@16
|
7 // Copyright Frank Mori Hess 2007-2008.
|
Chris@16
|
8 // Distributed under the Boost Software License, Version
|
Chris@16
|
9 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
10 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
11
|
Chris@16
|
12 // See http://www.boost.org/libs/signals2 for library home page.
|
Chris@16
|
13
|
Chris@16
|
14 #ifndef BOOST_SIGNALS2_CONNECTION_HPP
|
Chris@16
|
15 #define BOOST_SIGNALS2_CONNECTION_HPP
|
Chris@16
|
16
|
Chris@16
|
17 #include <boost/function.hpp>
|
Chris@16
|
18 #include <boost/mpl/bool.hpp>
|
Chris@16
|
19 #include <boost/noncopyable.hpp>
|
Chris@16
|
20 #include <boost/shared_ptr.hpp>
|
Chris@16
|
21 #include <boost/signals2/detail/null_output_iterator.hpp>
|
Chris@16
|
22 #include <boost/signals2/detail/unique_lock.hpp>
|
Chris@16
|
23 #include <boost/signals2/slot.hpp>
|
Chris@16
|
24 #include <boost/weak_ptr.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 namespace boost
|
Chris@16
|
27 {
|
Chris@16
|
28 namespace signals2
|
Chris@16
|
29 {
|
Chris@16
|
30 extern inline void null_deleter(const void*) {}
|
Chris@16
|
31 namespace detail
|
Chris@16
|
32 {
|
Chris@16
|
33 class connection_body_base
|
Chris@16
|
34 {
|
Chris@16
|
35 public:
|
Chris@16
|
36 connection_body_base():
|
Chris@16
|
37 _connected(true)
|
Chris@16
|
38 {
|
Chris@16
|
39 }
|
Chris@16
|
40 virtual ~connection_body_base() {}
|
Chris@16
|
41 void disconnect()
|
Chris@16
|
42 {
|
Chris@16
|
43 unique_lock<connection_body_base> local_lock(*this);
|
Chris@16
|
44 nolock_disconnect();
|
Chris@16
|
45 }
|
Chris@16
|
46 void nolock_disconnect()
|
Chris@16
|
47 {
|
Chris@16
|
48 _connected = false;
|
Chris@16
|
49 }
|
Chris@16
|
50 virtual bool connected() const = 0;
|
Chris@16
|
51 shared_ptr<void> get_blocker()
|
Chris@16
|
52 {
|
Chris@16
|
53 unique_lock<connection_body_base> local_lock(*this);
|
Chris@16
|
54 shared_ptr<void> blocker = _weak_blocker.lock();
|
Chris@16
|
55 if(blocker == shared_ptr<void>())
|
Chris@16
|
56 {
|
Chris@16
|
57 blocker.reset(this, &null_deleter);
|
Chris@16
|
58 _weak_blocker = blocker;
|
Chris@16
|
59 }
|
Chris@16
|
60 return blocker;
|
Chris@16
|
61 }
|
Chris@16
|
62 bool blocked() const
|
Chris@16
|
63 {
|
Chris@16
|
64 return !_weak_blocker.expired();
|
Chris@16
|
65 }
|
Chris@16
|
66 bool nolock_nograb_blocked() const
|
Chris@16
|
67 {
|
Chris@16
|
68 return nolock_nograb_connected() == false || blocked();
|
Chris@16
|
69 }
|
Chris@16
|
70 bool nolock_nograb_connected() const {return _connected;}
|
Chris@16
|
71 // expose part of Lockable concept of mutex
|
Chris@16
|
72 virtual void lock() = 0;
|
Chris@16
|
73 virtual void unlock() = 0;
|
Chris@16
|
74
|
Chris@16
|
75 protected:
|
Chris@16
|
76
|
Chris@16
|
77 mutable bool _connected;
|
Chris@16
|
78 weak_ptr<void> _weak_blocker;
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81 template<typename GroupKey, typename SlotType, typename Mutex>
|
Chris@16
|
82 class connection_body: public connection_body_base
|
Chris@16
|
83 {
|
Chris@16
|
84 public:
|
Chris@16
|
85 typedef Mutex mutex_type;
|
Chris@16
|
86 connection_body(const SlotType &slot_in):
|
Chris@16
|
87 slot(slot_in)
|
Chris@16
|
88 {
|
Chris@16
|
89 }
|
Chris@16
|
90 virtual ~connection_body() {}
|
Chris@16
|
91 virtual bool connected() const
|
Chris@16
|
92 {
|
Chris@16
|
93 unique_lock<mutex_type> local_lock(_mutex);
|
Chris@16
|
94 nolock_grab_tracked_objects(detail::null_output_iterator());
|
Chris@16
|
95 return nolock_nograb_connected();
|
Chris@16
|
96 }
|
Chris@16
|
97 const GroupKey& group_key() const {return _group_key;}
|
Chris@16
|
98 void set_group_key(const GroupKey &key) {_group_key = key;}
|
Chris@16
|
99 bool nolock_slot_expired() const
|
Chris@16
|
100 {
|
Chris@16
|
101 bool expired = slot.expired();
|
Chris@16
|
102 if(expired == true)
|
Chris@16
|
103 {
|
Chris@16
|
104 _connected = false;
|
Chris@16
|
105 }
|
Chris@16
|
106 return expired;
|
Chris@16
|
107 }
|
Chris@16
|
108 template<typename OutputIterator>
|
Chris@16
|
109 void nolock_grab_tracked_objects(OutputIterator inserter) const
|
Chris@16
|
110 {
|
Chris@16
|
111 slot_base::tracked_container_type::const_iterator it;
|
Chris@16
|
112 for(it = slot.tracked_objects().begin();
|
Chris@16
|
113 it != slot.tracked_objects().end();
|
Chris@16
|
114 ++it)
|
Chris@16
|
115 {
|
Chris@16
|
116 void_shared_ptr_variant locked_object
|
Chris@16
|
117 (
|
Chris@16
|
118 apply_visitor
|
Chris@16
|
119 (
|
Chris@16
|
120 detail::lock_weak_ptr_visitor(),
|
Chris@16
|
121 *it
|
Chris@16
|
122 )
|
Chris@16
|
123 );
|
Chris@16
|
124 if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
|
Chris@16
|
125 {
|
Chris@16
|
126 _connected = false;
|
Chris@16
|
127 return;
|
Chris@16
|
128 }
|
Chris@16
|
129 *inserter++ = locked_object;
|
Chris@16
|
130 }
|
Chris@16
|
131 }
|
Chris@16
|
132 // expose Lockable concept of mutex
|
Chris@16
|
133 virtual void lock()
|
Chris@16
|
134 {
|
Chris@16
|
135 _mutex.lock();
|
Chris@16
|
136 }
|
Chris@16
|
137 virtual void unlock()
|
Chris@16
|
138 {
|
Chris@16
|
139 _mutex.unlock();
|
Chris@16
|
140 }
|
Chris@16
|
141 SlotType slot;
|
Chris@16
|
142 private:
|
Chris@16
|
143 mutable mutex_type _mutex;
|
Chris@16
|
144 GroupKey _group_key;
|
Chris@16
|
145 };
|
Chris@16
|
146 }
|
Chris@16
|
147
|
Chris@16
|
148 class shared_connection_block;
|
Chris@16
|
149
|
Chris@16
|
150 class connection
|
Chris@16
|
151 {
|
Chris@16
|
152 public:
|
Chris@16
|
153 friend class shared_connection_block;
|
Chris@16
|
154
|
Chris@16
|
155 connection() {}
|
Chris@16
|
156 connection(const connection &other): _weak_connection_body(other._weak_connection_body)
|
Chris@16
|
157 {}
|
Chris@16
|
158 connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody):
|
Chris@16
|
159 _weak_connection_body(connectionBody)
|
Chris@16
|
160 {}
|
Chris@101
|
161
|
Chris@101
|
162 // move support
|
Chris@101
|
163 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
164 connection(connection && other): _weak_connection_body(std::move(other._weak_connection_body))
|
Chris@101
|
165 {
|
Chris@101
|
166 // make sure other is reset, in case it is a scoped_connection (so it
|
Chris@101
|
167 // won't disconnect on destruction after being moved away from).
|
Chris@101
|
168 other._weak_connection_body.reset();
|
Chris@101
|
169 }
|
Chris@101
|
170 connection & operator=(connection && other)
|
Chris@101
|
171 {
|
Chris@101
|
172 if(&other == this) return *this;
|
Chris@101
|
173 _weak_connection_body = std::move(other._weak_connection_body);
|
Chris@101
|
174 // make sure other is reset, in case it is a scoped_connection (so it
|
Chris@101
|
175 // won't disconnect on destruction after being moved away from).
|
Chris@101
|
176 other._weak_connection_body.reset();
|
Chris@101
|
177 return *this;
|
Chris@101
|
178 }
|
Chris@101
|
179 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
180 connection & operator=(const connection & other)
|
Chris@101
|
181 {
|
Chris@101
|
182 if(&other == this) return *this;
|
Chris@101
|
183 _weak_connection_body = other._weak_connection_body;
|
Chris@101
|
184 return *this;
|
Chris@101
|
185 }
|
Chris@101
|
186
|
Chris@16
|
187 ~connection() {}
|
Chris@16
|
188 void disconnect() const
|
Chris@16
|
189 {
|
Chris@16
|
190 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
|
Chris@16
|
191 if(connectionBody == 0) return;
|
Chris@16
|
192 connectionBody->disconnect();
|
Chris@16
|
193 }
|
Chris@16
|
194 bool connected() const
|
Chris@16
|
195 {
|
Chris@16
|
196 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
|
Chris@16
|
197 if(connectionBody == 0) return false;
|
Chris@16
|
198 return connectionBody->connected();
|
Chris@16
|
199 }
|
Chris@16
|
200 bool blocked() const
|
Chris@16
|
201 {
|
Chris@16
|
202 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
|
Chris@16
|
203 if(connectionBody == 0) return true;
|
Chris@16
|
204 return connectionBody->blocked();
|
Chris@16
|
205 }
|
Chris@16
|
206 bool operator==(const connection& other) const
|
Chris@16
|
207 {
|
Chris@16
|
208 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
|
Chris@16
|
209 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
|
Chris@16
|
210 return connectionBody == otherConnectionBody;
|
Chris@16
|
211 }
|
Chris@16
|
212 bool operator!=(const connection& other) const
|
Chris@16
|
213 {
|
Chris@16
|
214 return !(*this == other);
|
Chris@16
|
215 }
|
Chris@16
|
216 bool operator<(const connection& other) const
|
Chris@16
|
217 {
|
Chris@16
|
218 boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
|
Chris@16
|
219 boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
|
Chris@16
|
220 return connectionBody < otherConnectionBody;
|
Chris@16
|
221 }
|
Chris@16
|
222 void swap(connection &other)
|
Chris@16
|
223 {
|
Chris@16
|
224 using std::swap;
|
Chris@16
|
225 swap(_weak_connection_body, other._weak_connection_body);
|
Chris@16
|
226 }
|
Chris@16
|
227 protected:
|
Chris@16
|
228
|
Chris@16
|
229 boost::weak_ptr<detail::connection_body_base> _weak_connection_body;
|
Chris@16
|
230 };
|
Chris@16
|
231 inline void swap(connection &conn1, connection &conn2)
|
Chris@16
|
232 {
|
Chris@16
|
233 conn1.swap(conn2);
|
Chris@16
|
234 }
|
Chris@16
|
235
|
Chris@16
|
236 class scoped_connection: public connection
|
Chris@16
|
237 {
|
Chris@16
|
238 public:
|
Chris@16
|
239 scoped_connection() {}
|
Chris@16
|
240 scoped_connection(const connection &other):
|
Chris@16
|
241 connection(other)
|
Chris@16
|
242 {}
|
Chris@16
|
243 ~scoped_connection()
|
Chris@16
|
244 {
|
Chris@16
|
245 disconnect();
|
Chris@16
|
246 }
|
Chris@16
|
247 scoped_connection& operator=(const connection &rhs)
|
Chris@16
|
248 {
|
Chris@16
|
249 disconnect();
|
Chris@16
|
250 connection::operator=(rhs);
|
Chris@16
|
251 return *this;
|
Chris@16
|
252 }
|
Chris@101
|
253
|
Chris@101
|
254 // move support
|
Chris@101
|
255 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
256 scoped_connection(scoped_connection && other): connection(std::move(other))
|
Chris@101
|
257 {
|
Chris@101
|
258 }
|
Chris@101
|
259 scoped_connection(connection && other): connection(std::move(other))
|
Chris@101
|
260 {
|
Chris@101
|
261 }
|
Chris@101
|
262 scoped_connection & operator=(scoped_connection && other)
|
Chris@101
|
263 {
|
Chris@101
|
264 if(&other == this) return *this;
|
Chris@101
|
265 disconnect();
|
Chris@101
|
266 connection::operator=(std::move(other));
|
Chris@101
|
267 return *this;
|
Chris@101
|
268 }
|
Chris@101
|
269 scoped_connection & operator=(connection && other)
|
Chris@101
|
270 {
|
Chris@101
|
271 if(&other == this) return *this;
|
Chris@101
|
272 disconnect();
|
Chris@101
|
273 connection::operator=(std::move(other));
|
Chris@101
|
274 return *this;
|
Chris@101
|
275 }
|
Chris@101
|
276 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@101
|
277
|
Chris@16
|
278 connection release()
|
Chris@16
|
279 {
|
Chris@16
|
280 connection conn(_weak_connection_body);
|
Chris@16
|
281 _weak_connection_body.reset();
|
Chris@16
|
282 return conn;
|
Chris@16
|
283 }
|
Chris@16
|
284 private:
|
Chris@16
|
285 scoped_connection(const scoped_connection &other);
|
Chris@16
|
286 scoped_connection& operator=(const scoped_connection &rhs);
|
Chris@16
|
287 };
|
Chris@16
|
288 // Sun 5.9 compiler doesn't find the swap for base connection class when
|
Chris@16
|
289 // arguments are scoped_connection, so we provide this explicitly.
|
Chris@16
|
290 inline void swap(scoped_connection &conn1, scoped_connection &conn2)
|
Chris@16
|
291 {
|
Chris@16
|
292 conn1.swap(conn2);
|
Chris@16
|
293 }
|
Chris@16
|
294 }
|
Chris@16
|
295 }
|
Chris@16
|
296
|
Chris@16
|
297 #endif // BOOST_SIGNALS2_CONNECTION_HPP
|