Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/signals2/detail/signal_template.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 /* | |
2 Template for Signa1, Signal2, ... classes that support signals | |
3 with 1, 2, ... parameters | |
4 | |
5 Begin: 2007-01-23 | |
6 */ | |
7 // Copyright Frank Mori Hess 2007-2008 | |
8 // | |
9 // Use, modification and | |
10 // distribution is subject to the Boost Software License, Version | |
11 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
12 // http://www.boost.org/LICENSE_1_0.txt) | |
13 | |
14 // This file is included iteratively, and should not be protected from multiple inclusion | |
15 | |
16 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
17 #define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION() | |
18 #else | |
19 #define BOOST_SIGNALS2_NUM_ARGS 1 | |
20 #endif | |
21 | |
22 // R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex | |
23 #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \ | |
24 BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \ | |
25 Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex | |
26 | |
27 namespace boost | |
28 { | |
29 namespace signals2 | |
30 { | |
31 namespace detail | |
32 { | |
33 // helper for bound_extended_slot_function that handles specialization for void return | |
34 template<typename R> | |
35 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) | |
36 { | |
37 public: | |
38 typedef R result_type; | |
39 template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
40 BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
41 result_type operator()(ExtendedSlotFunction &func, const connection &conn | |
42 BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
43 BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
44 { | |
45 return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
46 BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
47 } | |
48 }; | |
49 #ifdef BOOST_NO_VOID_RETURNS | |
50 template<> | |
51 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void> | |
52 { | |
53 public: | |
54 typedef result_type_wrapper<void>::type result_type; | |
55 template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
56 BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
57 result_type operator()(ExtendedSlotFunction &func, const connection &conn | |
58 BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
59 BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
60 { | |
61 func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
62 BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
63 return result_type(); | |
64 } | |
65 }; | |
66 #endif | |
67 // wrapper around an signalN::extended_slot_function which binds the | |
68 // connection argument so it looks like a normal | |
69 // signalN::slot_function | |
70 | |
71 template<typename ExtendedSlotFunction> | |
72 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS) | |
73 { | |
74 public: | |
75 typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type; | |
76 BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun): | |
77 _fun(fun), _connection(new connection) | |
78 {} | |
79 void set_connection(const connection &conn) | |
80 { | |
81 *_connection = conn; | |
82 } | |
83 | |
84 #if BOOST_SIGNALS2_NUM_ARGS > 0 | |
85 template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
86 #endif // BOOST_SIGNALS2_NUM_ARGS > 0 | |
87 result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) | |
88 { | |
89 return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) | |
90 <typename ExtendedSlotFunction::result_type>() | |
91 (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
92 BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
93 } | |
94 // const overload | |
95 #if BOOST_SIGNALS2_NUM_ARGS > 0 | |
96 template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
97 #endif // BOOST_SIGNALS2_NUM_ARGS > 0 | |
98 result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
99 { | |
100 return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) | |
101 <typename ExtendedSlotFunction::result_type>() | |
102 (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
103 BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
104 } | |
105 template<typename T> | |
106 bool operator==(const T &other) const | |
107 { | |
108 return _fun == other; | |
109 } | |
110 private: | |
111 BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)() | |
112 {} | |
113 | |
114 ExtendedSlotFunction _fun; | |
115 boost::shared_ptr<connection> _connection; | |
116 }; | |
117 | |
118 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
119 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); | |
120 | |
121 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
122 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION | |
123 { | |
124 public: | |
125 typedef SlotFunction slot_function_type; | |
126 // typedef slotN<Signature, SlotFunction> slot_type; | |
127 typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
128 <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), | |
129 slot_function_type> slot_type; | |
130 typedef ExtendedSlotFunction extended_slot_function_type; | |
131 // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type; | |
132 typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type; | |
133 typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type; | |
134 private: | |
135 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
136 class slot_invoker; | |
137 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
138 typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker; | |
139 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
140 typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type; | |
141 typedef typename group_key<Group>::type group_key_type; | |
142 typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type; | |
143 typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type; | |
144 typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type> | |
145 bound_extended_slot_function_type; | |
146 public: | |
147 typedef Combiner combiner_type; | |
148 typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type; | |
149 typedef Group group_type; | |
150 typedef GroupCompare group_compare_type; | |
151 typedef typename detail::slot_call_iterator_t<slot_invoker, | |
152 typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator; | |
153 | |
154 BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg, | |
155 const group_compare_type &group_compare): | |
156 _shared_state(new invocation_state(connection_list_type(group_compare), combiner_arg)), | |
157 _garbage_collector_it(_shared_state->connection_bodies().end()) | |
158 {} | |
159 // connect slot | |
160 connection connect(const slot_type &slot, connect_position position = at_back) | |
161 { | |
162 unique_lock<mutex_type> lock(_mutex); | |
163 return nolock_connect(slot, position); | |
164 } | |
165 connection connect(const group_type &group, | |
166 const slot_type &slot, connect_position position = at_back) | |
167 { | |
168 unique_lock<Mutex> lock(_mutex); | |
169 return nolock_connect(group, slot, position); | |
170 } | |
171 // connect extended slot | |
172 connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back) | |
173 { | |
174 unique_lock<mutex_type> lock(_mutex); | |
175 bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); | |
176 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); | |
177 connection conn = nolock_connect(slot, position); | |
178 bound_slot.set_connection(conn); | |
179 return conn; | |
180 } | |
181 connection connect_extended(const group_type &group, | |
182 const extended_slot_type &ext_slot, connect_position position = at_back) | |
183 { | |
184 unique_lock<Mutex> lock(_mutex); | |
185 bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); | |
186 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); | |
187 connection conn = nolock_connect(group, slot, position); | |
188 bound_slot.set_connection(conn); | |
189 return conn; | |
190 } | |
191 // disconnect slot(s) | |
192 void disconnect_all_slots() | |
193 { | |
194 shared_ptr<invocation_state> local_state = | |
195 get_readable_state(); | |
196 typename connection_list_type::iterator it; | |
197 for(it = local_state->connection_bodies().begin(); | |
198 it != local_state->connection_bodies().end(); ++it) | |
199 { | |
200 (*it)->disconnect(); | |
201 } | |
202 } | |
203 void disconnect(const group_type &group) | |
204 { | |
205 shared_ptr<invocation_state> local_state = | |
206 get_readable_state(); | |
207 group_key_type group_key(grouped_slots, group); | |
208 typename connection_list_type::iterator it; | |
209 typename connection_list_type::iterator end_it = | |
210 local_state->connection_bodies().upper_bound(group_key); | |
211 for(it = local_state->connection_bodies().lower_bound(group_key); | |
212 it != end_it; ++it) | |
213 { | |
214 (*it)->disconnect(); | |
215 } | |
216 } | |
217 template <typename T> | |
218 void disconnect(const T &slot) | |
219 { | |
220 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group; | |
221 do_disconnect(slot, is_group()); | |
222 } | |
223 // emit signal | |
224 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) | |
225 { | |
226 shared_ptr<invocation_state> local_state; | |
227 typename connection_list_type::iterator it; | |
228 { | |
229 unique_lock<mutex_type> list_lock(_mutex); | |
230 // only clean up if it is safe to do so | |
231 if(_shared_state.unique()) | |
232 nolock_cleanup_connections(false, 1); | |
233 /* Make a local copy of _shared_state while holding mutex, so we are | |
234 thread safe against the combiner or connection list getting modified | |
235 during invocation. */ | |
236 local_state = _shared_state; | |
237 } | |
238 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
239 slot_call_iterator_cache_type cache(invoker); | |
240 invocation_janitor janitor(cache, *this, &local_state->connection_bodies()); | |
241 return detail::combiner_invoker<typename combiner_type::result_type>() | |
242 ( | |
243 local_state->combiner(), | |
244 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache), | |
245 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache) | |
246 ); | |
247 } | |
248 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
249 { | |
250 shared_ptr<invocation_state> local_state; | |
251 typename connection_list_type::iterator it; | |
252 { | |
253 unique_lock<mutex_type> list_lock(_mutex); | |
254 // only clean up if it is safe to do so | |
255 if(_shared_state.unique()) | |
256 nolock_cleanup_connections(false, 1); | |
257 /* Make a local copy of _shared_state while holding mutex, so we are | |
258 thread safe against the combiner or connection list getting modified | |
259 during invocation. */ | |
260 local_state = _shared_state; | |
261 } | |
262 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
263 slot_call_iterator_cache_type cache(invoker); | |
264 invocation_janitor janitor(cache, *this, &local_state->connection_bodies()); | |
265 return detail::combiner_invoker<typename combiner_type::result_type>() | |
266 ( | |
267 local_state->combiner(), | |
268 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache), | |
269 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache) | |
270 ); | |
271 } | |
272 std::size_t num_slots() const | |
273 { | |
274 shared_ptr<invocation_state> local_state = | |
275 get_readable_state(); | |
276 typename connection_list_type::iterator it; | |
277 std::size_t count = 0; | |
278 for(it = local_state->connection_bodies().begin(); | |
279 it != local_state->connection_bodies().end(); ++it) | |
280 { | |
281 if((*it)->connected()) ++count; | |
282 } | |
283 return count; | |
284 } | |
285 bool empty() const | |
286 { | |
287 shared_ptr<invocation_state> local_state = | |
288 get_readable_state(); | |
289 typename connection_list_type::iterator it; | |
290 for(it = local_state->connection_bodies().begin(); | |
291 it != local_state->connection_bodies().end(); ++it) | |
292 { | |
293 if((*it)->connected()) return false; | |
294 } | |
295 return true; | |
296 } | |
297 combiner_type combiner() const | |
298 { | |
299 unique_lock<mutex_type> lock(_mutex); | |
300 return _shared_state->combiner(); | |
301 } | |
302 void set_combiner(const combiner_type &combiner_arg) | |
303 { | |
304 unique_lock<mutex_type> lock(_mutex); | |
305 if(_shared_state.unique()) | |
306 _shared_state->combiner() = combiner_arg; | |
307 else | |
308 _shared_state.reset(new invocation_state(*_shared_state, combiner_arg)); | |
309 } | |
310 private: | |
311 typedef Mutex mutex_type; | |
312 | |
313 // slot_invoker is passed to slot_call_iterator_t to run slots | |
314 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
315 class slot_invoker | |
316 { | |
317 public: | |
318 typedef nonvoid_slot_result_type result_type; | |
319 // typename add_reference<Tn>::type | |
320 #define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \ | |
321 typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type | |
322 // typename add_reference<Tn>::type argn | |
323 #define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \ | |
324 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \ | |
325 BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) | |
326 // typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn | |
327 #define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \ | |
328 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~) | |
329 slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :) | |
330 #undef BOOST_SIGNALS2_ADD_REF_ARGS | |
331 | |
332 // m_argn | |
333 #define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n)) | |
334 // m_argn ( argn ) | |
335 #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \ | |
336 BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) ) | |
337 // m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn) | |
338 BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~) | |
339 #undef BOOST_SIGNALS2_MISC_STATEMENT | |
340 {} | |
341 result_type operator ()(const connection_body_type &connectionBody) const | |
342 { | |
343 result_type *resolver = 0; | |
344 return m_invoke(connectionBody, | |
345 resolver); | |
346 } | |
347 private: | |
348 // declare assignment operator private since this class might have reference or const members | |
349 slot_invoker & operator=(const slot_invoker &); | |
350 | |
351 #define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \ | |
352 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ; | |
353 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~) | |
354 #undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT | |
355 #undef BOOST_SIGNALS2_ADD_REF_ARG | |
356 #undef BOOST_SIGNALS2_ADD_REF_TYPE | |
357 | |
358 // m_arg1, m_arg2, ..., m_argn | |
359 #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~) | |
360 result_type m_invoke(const connection_body_type &connectionBody, | |
361 const void_type *) const | |
362 { | |
363 connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
364 return void_type(); | |
365 } | |
366 result_type m_invoke(const connection_body_type &connectionBody, ...) const | |
367 { | |
368 return connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
369 } | |
370 }; | |
371 #undef BOOST_SIGNALS2_M_ARG_NAMES | |
372 #undef BOOST_SIGNALS2_M_ARG_NAME | |
373 | |
374 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
375 // a struct used to optimize (minimize) the number of shared_ptrs that need to be created | |
376 // inside operator() | |
377 class invocation_state | |
378 { | |
379 public: | |
380 invocation_state(const connection_list_type &connections_in, | |
381 const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)), | |
382 _combiner(new combiner_type(combiner_in)) | |
383 {} | |
384 invocation_state(const invocation_state &other, const connection_list_type &connections_in): | |
385 _connection_bodies(new connection_list_type(connections_in)), | |
386 _combiner(other._combiner) | |
387 {} | |
388 invocation_state(const invocation_state &other, const combiner_type &combiner_in): | |
389 _connection_bodies(other._connection_bodies), | |
390 _combiner(new combiner_type(combiner_in)) | |
391 {} | |
392 connection_list_type & connection_bodies() { return *_connection_bodies; } | |
393 const connection_list_type & connection_bodies() const { return *_connection_bodies; } | |
394 combiner_type & combiner() { return *_combiner; } | |
395 const combiner_type & combiner() const { return *_combiner; } | |
396 private: | |
397 invocation_state(const invocation_state &); | |
398 | |
399 shared_ptr<connection_list_type> _connection_bodies; | |
400 shared_ptr<combiner_type> _combiner; | |
401 }; | |
402 // Destructor of invocation_janitor does some cleanup when a signal invocation completes. | |
403 // Code can't be put directly in signal's operator() due to complications from void return types. | |
404 class invocation_janitor | |
405 { | |
406 public: | |
407 typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type; | |
408 invocation_janitor | |
409 ( | |
410 const slot_call_iterator_cache_type &cache, | |
411 const signal_type &sig, | |
412 const connection_list_type *connection_bodies | |
413 ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies) | |
414 {} | |
415 ~invocation_janitor() | |
416 { | |
417 // force a full cleanup of disconnected slots if there are too many | |
418 if(_cache.disconnected_slot_count > _cache.connected_slot_count) | |
419 { | |
420 _sig.force_cleanup_connections(_connection_bodies); | |
421 } | |
422 } | |
423 private: | |
424 const slot_call_iterator_cache_type &_cache; | |
425 const signal_type &_sig; | |
426 const connection_list_type *_connection_bodies; | |
427 }; | |
428 | |
429 // clean up disconnected connections | |
430 void nolock_cleanup_connections_from(bool grab_tracked, | |
431 const typename connection_list_type::iterator &begin, unsigned count = 0) const | |
432 { | |
433 BOOST_ASSERT(_shared_state.unique()); | |
434 typename connection_list_type::iterator it; | |
435 unsigned i; | |
436 for(it = begin, i = 0; | |
437 it != _shared_state->connection_bodies().end() && (count == 0 || i < count); | |
438 ++i) | |
439 { | |
440 bool connected; | |
441 { | |
442 unique_lock<connection_body_base> lock(**it); | |
443 if(grab_tracked) | |
444 (*it)->nolock_slot_expired(); | |
445 connected = (*it)->nolock_nograb_connected(); | |
446 }// scoped lock destructs here, safe to erase now | |
447 if(connected == false) | |
448 { | |
449 it = _shared_state->connection_bodies().erase((*it)->group_key(), it); | |
450 }else | |
451 { | |
452 ++it; | |
453 } | |
454 } | |
455 _garbage_collector_it = it; | |
456 } | |
457 // clean up a few connections in constant time | |
458 void nolock_cleanup_connections(bool grab_tracked, unsigned count) const | |
459 { | |
460 BOOST_ASSERT(_shared_state.unique()); | |
461 typename connection_list_type::iterator begin; | |
462 if(_garbage_collector_it == _shared_state->connection_bodies().end()) | |
463 { | |
464 begin = _shared_state->connection_bodies().begin(); | |
465 }else | |
466 { | |
467 begin = _garbage_collector_it; | |
468 } | |
469 nolock_cleanup_connections_from(grab_tracked, begin, count); | |
470 } | |
471 /* Make a new copy of the slot list if it is currently being read somewhere else | |
472 */ | |
473 void nolock_force_unique_connection_list() | |
474 { | |
475 if(_shared_state.unique() == false) | |
476 { | |
477 _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); | |
478 nolock_cleanup_connections_from(true, _shared_state->connection_bodies().begin()); | |
479 }else | |
480 { | |
481 /* We need to try and check more than just 1 connection here to avoid corner | |
482 cases where certain repeated connect/disconnect patterns cause the slot | |
483 list to grow without limit. */ | |
484 nolock_cleanup_connections(true, 2); | |
485 } | |
486 } | |
487 // force a full cleanup of the connection list | |
488 void force_cleanup_connections(const connection_list_type *connection_bodies) const | |
489 { | |
490 unique_lock<mutex_type> list_lock(_mutex); | |
491 // if the connection list passed in as a parameter is no longer in use, | |
492 // we don't need to do any cleanup. | |
493 if(&_shared_state->connection_bodies() != connection_bodies) | |
494 { | |
495 return; | |
496 } | |
497 if(_shared_state.unique() == false) | |
498 { | |
499 _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); | |
500 } | |
501 nolock_cleanup_connections_from(false, _shared_state->connection_bodies().begin()); | |
502 } | |
503 shared_ptr<invocation_state> get_readable_state() const | |
504 { | |
505 unique_lock<mutex_type> list_lock(_mutex); | |
506 return _shared_state; | |
507 } | |
508 connection_body_type create_new_connection(const slot_type &slot) | |
509 { | |
510 nolock_force_unique_connection_list(); | |
511 return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot)); | |
512 } | |
513 void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */) | |
514 { | |
515 disconnect(group); | |
516 } | |
517 template<typename T> | |
518 void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */) | |
519 { | |
520 shared_ptr<invocation_state> local_state = | |
521 get_readable_state(); | |
522 typename connection_list_type::iterator it; | |
523 for(it = local_state->connection_bodies().begin(); | |
524 it != local_state->connection_bodies().end(); ++it) | |
525 { | |
526 unique_lock<connection_body_base> lock(**it); | |
527 if((*it)->slot.slot_function() == slot) | |
528 { | |
529 (*it)->nolock_disconnect(); | |
530 }else | |
531 { | |
532 // check for wrapped extended slot | |
533 bound_extended_slot_function_type *fp; | |
534 fp = (*it)->slot.slot_function().template target<bound_extended_slot_function_type>(); | |
535 if(fp && *fp == slot) | |
536 { | |
537 (*it)->nolock_disconnect(); | |
538 } | |
539 } | |
540 } | |
541 } | |
542 // connect slot | |
543 connection nolock_connect(const slot_type &slot, connect_position position) | |
544 { | |
545 connection_body_type newConnectionBody = | |
546 create_new_connection(slot); | |
547 group_key_type group_key; | |
548 if(position == at_back) | |
549 { | |
550 group_key.first = back_ungrouped_slots; | |
551 _shared_state->connection_bodies().push_back(group_key, newConnectionBody); | |
552 }else | |
553 { | |
554 group_key.first = front_ungrouped_slots; | |
555 _shared_state->connection_bodies().push_front(group_key, newConnectionBody); | |
556 } | |
557 newConnectionBody->set_group_key(group_key); | |
558 return connection(newConnectionBody); | |
559 } | |
560 connection nolock_connect(const group_type &group, | |
561 const slot_type &slot, connect_position position) | |
562 { | |
563 connection_body_type newConnectionBody = | |
564 create_new_connection(slot); | |
565 // update map to first connection body in group if needed | |
566 group_key_type group_key(grouped_slots, group); | |
567 newConnectionBody->set_group_key(group_key); | |
568 if(position == at_back) | |
569 { | |
570 _shared_state->connection_bodies().push_back(group_key, newConnectionBody); | |
571 }else // at_front | |
572 { | |
573 _shared_state->connection_bodies().push_front(group_key, newConnectionBody); | |
574 } | |
575 return connection(newConnectionBody); | |
576 } | |
577 | |
578 // _shared_state is mutable so we can do force_cleanup_connections during a const invocation | |
579 mutable shared_ptr<invocation_state> _shared_state; | |
580 mutable typename connection_list_type::iterator _garbage_collector_it; | |
581 // connection list mutex must never be locked when attempting a blocking lock on a slot, | |
582 // or you could deadlock. | |
583 mutable mutex_type _mutex; | |
584 }; | |
585 | |
586 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
587 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); | |
588 } | |
589 | |
590 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
591 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); | |
592 | |
593 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
594 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
595 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base, | |
596 public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE | |
597 (typename detail::result_type_wrapper<typename Combiner::result_type>::type) | |
598 { | |
599 typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
600 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class; | |
601 public: | |
602 typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
603 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type; | |
604 friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
605 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>; | |
606 | |
607 typedef SlotFunction slot_function_type; | |
608 // typedef slotN<Signature, SlotFunction> slot_type; | |
609 typedef typename impl_class::slot_type slot_type; | |
610 typedef typename impl_class::extended_slot_function_type extended_slot_function_type; | |
611 typedef typename impl_class::extended_slot_type extended_slot_type; | |
612 typedef typename slot_function_type::result_type slot_result_type; | |
613 typedef Combiner combiner_type; | |
614 typedef typename impl_class::result_type result_type; | |
615 typedef Group group_type; | |
616 typedef GroupCompare group_compare_type; | |
617 typedef typename impl_class::slot_call_iterator | |
618 slot_call_iterator; | |
619 typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type; | |
620 | |
621 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
622 | |
623 // typedef Tn argn_type; | |
624 #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \ | |
625 typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type); | |
626 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~) | |
627 #undef BOOST_SIGNALS2_MISC_STATEMENT | |
628 #if BOOST_SIGNALS2_NUM_ARGS == 1 | |
629 typedef arg1_type argument_type; | |
630 #elif BOOST_SIGNALS2_NUM_ARGS == 2 | |
631 typedef arg1_type first_argument_type; | |
632 typedef arg2_type second_argument_type; | |
633 #endif | |
634 | |
635 template<unsigned n> class arg : public | |
636 detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
637 <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) | |
638 BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)> | |
639 {}; | |
640 | |
641 BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS); | |
642 | |
643 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
644 | |
645 template<unsigned n> class arg | |
646 { | |
647 public: | |
648 typedef typename detail::variadic_arg_type<n, Args...>::type type; | |
649 }; | |
650 BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args)); | |
651 | |
652 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
653 | |
654 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(), | |
655 const group_compare_type &group_compare = group_compare_type()): | |
656 _pimpl(new impl_class(combiner_arg, group_compare)) | |
657 {}; | |
658 virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)() | |
659 { | |
660 disconnect_all_slots(); | |
661 } | |
662 connection connect(const slot_type &slot, connect_position position = at_back) | |
663 { | |
664 return (*_pimpl).connect(slot, position); | |
665 } | |
666 connection connect(const group_type &group, | |
667 const slot_type &slot, connect_position position = at_back) | |
668 { | |
669 return (*_pimpl).connect(group, slot, position); | |
670 } | |
671 connection connect_extended(const extended_slot_type &slot, connect_position position = at_back) | |
672 { | |
673 return (*_pimpl).connect_extended(slot, position); | |
674 } | |
675 connection connect_extended(const group_type &group, | |
676 const extended_slot_type &slot, connect_position position = at_back) | |
677 { | |
678 return (*_pimpl).connect_extended(group, slot, position); | |
679 } | |
680 void disconnect_all_slots() | |
681 { | |
682 (*_pimpl).disconnect_all_slots(); | |
683 } | |
684 void disconnect(const group_type &group) | |
685 { | |
686 (*_pimpl).disconnect(group); | |
687 } | |
688 template <typename T> | |
689 void disconnect(const T &slot) | |
690 { | |
691 (*_pimpl).disconnect(slot); | |
692 } | |
693 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) | |
694 { | |
695 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
696 } | |
697 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
698 { | |
699 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
700 } | |
701 std::size_t num_slots() const | |
702 { | |
703 return (*_pimpl).num_slots(); | |
704 } | |
705 bool empty() const | |
706 { | |
707 return (*_pimpl).empty(); | |
708 } | |
709 combiner_type combiner() const | |
710 { | |
711 return (*_pimpl).combiner(); | |
712 } | |
713 void set_combiner(const combiner_type &combiner_arg) | |
714 { | |
715 return (*_pimpl).set_combiner(combiner_arg); | |
716 } | |
717 void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) | |
718 { | |
719 using std::swap; | |
720 swap(_pimpl, other._pimpl); | |
721 } | |
722 protected: | |
723 virtual shared_ptr<void> lock_pimpl() const | |
724 { | |
725 return _pimpl; | |
726 } | |
727 private: | |
728 shared_ptr<impl_class> | |
729 _pimpl; | |
730 }; | |
731 | |
732 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
733 // free swap function for signalN classes, findable by ADL | |
734 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
735 void swap( | |
736 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1, | |
737 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) | |
738 { | |
739 sig1.swap(sig2); | |
740 } | |
741 #endif | |
742 | |
743 namespace detail | |
744 { | |
745 // wrapper class for storing other signals as slots with automatic lifetime tracking | |
746 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
747 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); | |
748 | |
749 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> | |
750 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
751 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION | |
752 { | |
753 public: | |
754 typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
755 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type | |
756 result_type; | |
757 | |
758 BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
759 (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
760 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> | |
761 &signal): | |
762 _weak_pimpl(signal._pimpl) | |
763 {} | |
764 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) | |
765 { | |
766 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
767 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > | |
768 shared_pimpl(_weak_pimpl.lock()); | |
769 if(shared_pimpl == 0) boost::throw_exception(expired_slot()); | |
770 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
771 } | |
772 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const | |
773 { | |
774 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
775 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > | |
776 shared_pimpl(_weak_pimpl.lock()); | |
777 if(shared_pimpl == 0) boost::throw_exception(expired_slot()); | |
778 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); | |
779 } | |
780 private: | |
781 boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) | |
782 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl; | |
783 }; | |
784 | |
785 #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
786 template<int arity, typename Signature> | |
787 class extended_signature: public variadic_extended_signature<Signature> | |
788 {}; | |
789 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
790 template<int arity, typename Signature> | |
791 class extended_signature; | |
792 // partial template specialization | |
793 template<typename Signature> | |
794 class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature> | |
795 { | |
796 public: | |
797 // typename function_traits<Signature>::result_type ( | |
798 // const boost::signals2::connection &, | |
799 // typename function_traits<Signature>::arg1_type, | |
800 // typename function_traits<Signature>::arg2_type, | |
801 // ..., | |
802 // typename function_traits<Signature>::argn_type) | |
803 #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \ | |
804 typename function_traits<Signature>::result_type ( \ | |
805 const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \ | |
806 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) ) | |
807 typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type; | |
808 #undef BOOST_SIGNALS2_EXT_SIGNATURE | |
809 }; | |
810 | |
811 template<unsigned arity, typename Signature, typename Combiner, | |
812 typename Group, typename GroupCompare, typename SlotFunction, | |
813 typename ExtendedSlotFunction, typename Mutex> | |
814 class signalN; | |
815 // partial template specialization | |
816 template<typename Signature, typename Combiner, typename Group, | |
817 typename GroupCompare, typename SlotFunction, | |
818 typename ExtendedSlotFunction, typename Mutex> | |
819 class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group, | |
820 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> | |
821 { | |
822 public: | |
823 typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)< | |
824 BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature), | |
825 Combiner, Group, | |
826 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type; | |
827 }; | |
828 | |
829 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
830 | |
831 } // namespace detail | |
832 } // namespace signals2 | |
833 } // namespace boost | |
834 | |
835 #undef BOOST_SIGNALS2_NUM_ARGS | |
836 #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION |