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