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
27namespace 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_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
44 {
45 return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
46 BOOST_SIGNALS2_FORWARDED_ARGS(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_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
60 {
61 func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
62 BOOST_SIGNALS2_FORWARDED_ARGS(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_FORWARD_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_FORWARDED_ARGS(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_FORWARD_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_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
104 }
105 template<typename T>
106 bool contains(const T &other) const
107 {
108 return _fun.contains(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_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
120 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
121 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
122
123 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
124 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
125 {
126 public:
127 typedef SlotFunction slot_function_type;
128 // typedef slotN<Signature, SlotFunction> slot_type;
129 typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
130 <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS),
131 slot_function_type> slot_type;
132 typedef ExtendedSlotFunction extended_slot_function_type;
133 // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type;
134 typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type;
135 typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type;
136 private:
137#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
138 class slot_invoker;
139#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
140 typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker;
141#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
142 typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type;
143 typedef typename group_key<Group>::type group_key_type;
144 typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type;
145 typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
146 typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type>
147 bound_extended_slot_function_type;
148 public:
149 typedef Combiner combiner_type;
150 typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type;
151 typedef Group group_type;
152 typedef GroupCompare group_compare_type;
153 typedef typename detail::slot_call_iterator_t<slot_invoker,
154 typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator;
155 typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
156 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type;
157
158 BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg,
159 const group_compare_type &group_compare):
160 _shared_state(boost::make_shared<invocation_state>(connection_list_type(group_compare), combiner_arg)),
161 _garbage_collector_it(_shared_state->connection_bodies().end()),
162 _mutex(new mutex_type())
163 {}
164 // connect slot
165 connection connect(const slot_type &slot, connect_position position = at_back)
166 {
167 garbage_collecting_lock<mutex_type> lock(*_mutex);
168 return nolock_connect(lock, slot, position);
169 }
170 connection connect(const group_type &group,
171 const slot_type &slot, connect_position position = at_back)
172 {
173 garbage_collecting_lock<mutex_type> lock(*_mutex);
174 return nolock_connect(lock, group, slot, position);
175 }
176 // connect extended slot
177 connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back)
178 {
179 garbage_collecting_lock<mutex_type> lock(*_mutex);
180 bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
181 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
182 connection conn = nolock_connect(lock, slot, position);
183 bound_slot.set_connection(conn);
184 return conn;
185 }
186 connection connect_extended(const group_type &group,
187 const extended_slot_type &ext_slot, connect_position position = at_back)
188 {
189 garbage_collecting_lock<Mutex> lock(*_mutex);
190 bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
191 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
192 connection conn = nolock_connect(lock, group, slot, position);
193 bound_slot.set_connection(conn);
194 return conn;
195 }
196 // disconnect slot(s)
197 void disconnect_all_slots()
198 {
199 shared_ptr<invocation_state> local_state =
200 get_readable_state();
201 typename connection_list_type::iterator it;
202 for(it = local_state->connection_bodies().begin();
203 it != local_state->connection_bodies().end(); ++it)
204 {
205 (*it)->disconnect();
206 }
207 }
208 void disconnect(const group_type &group)
209 {
210 shared_ptr<invocation_state> local_state =
211 get_readable_state();
212 group_key_type group_key(grouped_slots, group);
213 typename connection_list_type::iterator it;
214 typename connection_list_type::iterator end_it =
215 local_state->connection_bodies().upper_bound(group_key);
216 for(it = local_state->connection_bodies().lower_bound(group_key);
217 it != end_it; ++it)
218 {
219 (*it)->disconnect();
220 }
221 }
222 template <typename T>
223 void disconnect(const T &slot)
224 {
225 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
226 do_disconnect(unwrap_ref(slot), is_group());
227 }
228 // emit signal
229 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
230 {
231 shared_ptr<invocation_state> local_state;
232 typename connection_list_type::iterator it;
233 {
234 garbage_collecting_lock<mutex_type> list_lock(*_mutex);
235 // only clean up if it is safe to do so
236 if(_shared_state.unique())
237 nolock_cleanup_connections(lock&: list_lock, grab_tracked: false, count: 1);
238 /* Make a local copy of _shared_state while holding mutex, so we are
239 thread safe against the combiner or connection list getting modified
240 during invocation. */
241 local_state = _shared_state;
242 }
243 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
244 slot_call_iterator_cache_type cache(invoker);
245 invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
246 return detail::combiner_invoker<typename combiner_type::result_type>()
247 (
248 local_state->combiner(),
249 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
250 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
251 );
252 }
253 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
254 {
255 shared_ptr<invocation_state> local_state;
256 typename connection_list_type::iterator it;
257 {
258 garbage_collecting_lock<mutex_type> list_lock(*_mutex);
259 // only clean up if it is safe to do so
260 if(_shared_state.unique())
261 nolock_cleanup_connections(lock&: list_lock, grab_tracked: false, count: 1);
262 /* Make a local copy of _shared_state while holding mutex, so we are
263 thread safe against the combiner or connection list getting modified
264 during invocation. */
265 local_state = _shared_state;
266 }
267 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
268 slot_call_iterator_cache_type cache(invoker);
269 invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
270 return detail::combiner_invoker<typename combiner_type::result_type>()
271 (
272 local_state->combiner(),
273 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
274 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
275 );
276 }
277 std::size_t num_slots() const
278 {
279 shared_ptr<invocation_state> local_state =
280 get_readable_state();
281 typename connection_list_type::iterator it;
282 std::size_t count = 0;
283 for(it = local_state->connection_bodies().begin();
284 it != local_state->connection_bodies().end(); ++it)
285 {
286 if((*it)->connected()) ++count;
287 }
288 return count;
289 }
290 bool empty() const
291 {
292 shared_ptr<invocation_state> local_state =
293 get_readable_state();
294 typename connection_list_type::iterator it;
295 for(it = local_state->connection_bodies().begin();
296 it != local_state->connection_bodies().end(); ++it)
297 {
298 if((*it)->connected()) return false;
299 }
300 return true;
301 }
302 combiner_type combiner() const
303 {
304 unique_lock<mutex_type> lock(*_mutex);
305 return _shared_state->combiner();
306 }
307 void set_combiner(const combiner_type &combiner_arg)
308 {
309 unique_lock<mutex_type> lock(*_mutex);
310 if(_shared_state.unique())
311 _shared_state->combiner() = combiner_arg;
312 else
313 _shared_state = boost::make_shared<invocation_state>(*_shared_state, combiner_arg);
314 }
315 private:
316 typedef Mutex mutex_type;
317
318 // slot_invoker is passed to slot_call_iterator_t to run slots
319#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
320 class slot_invoker
321 {
322 public:
323 typedef nonvoid_slot_result_type result_type;
324// typename add_reference<Tn>::type
325#define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \
326 typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type
327// typename add_reference<Tn>::type argn
328#define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \
329 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \
330 BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~)
331// typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn
332#define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \
333 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~)
334 slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :)
335#undef BOOST_SIGNALS2_ADD_REF_ARGS
336
337// m_argn
338#define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n))
339// m_argn ( argn )
340#define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
341 BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) )
342// m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn)
343 BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
344#undef BOOST_SIGNALS2_MISC_STATEMENT
345 {}
346 result_type operator ()(const connection_body_type &connectionBody) const
347 {
348 return m_invoke<typename slot_type::result_type>(connectionBody);
349 }
350 private:
351 // declare assignment operator private since this class might have reference or const members
352 slot_invoker & operator=(const slot_invoker &);
353
354#define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \
355 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ;
356 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~)
357#undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT
358#undef BOOST_SIGNALS2_ADD_REF_ARG
359#undef BOOST_SIGNALS2_ADD_REF_TYPE
360
361// m_arg1, m_arg2, ..., m_argn
362#define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~)
363 template<typename SlotResultType>
364 result_type m_invoke(const connection_body_type &connectionBody,
365 typename boost::enable_if<boost::is_void<SlotResultType> >::type * = 0) const
366 {
367 connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
368 return void_type();
369 }
370 template<typename SlotResultType>
371 result_type m_invoke(const connection_body_type &connectionBody,
372 typename boost::disable_if<boost::is_void<SlotResultType> >::type * = 0) const
373 {
374 return connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
375 }
376 };
377#undef BOOST_SIGNALS2_M_ARG_NAMES
378#undef BOOST_SIGNALS2_M_ARG_NAME
379
380#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
381 // a struct used to optimize (minimize) the number of shared_ptrs that need to be created
382 // inside operator()
383 class invocation_state
384 {
385 public:
386 invocation_state(const connection_list_type &connections_in,
387 const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)),
388 _combiner(new combiner_type(combiner_in))
389 {}
390 invocation_state(const invocation_state &other, const connection_list_type &connections_in):
391 _connection_bodies(new connection_list_type(connections_in)),
392 _combiner(other._combiner)
393 {}
394 invocation_state(const invocation_state &other, const combiner_type &combiner_in):
395 _connection_bodies(other._connection_bodies),
396 _combiner(new combiner_type(combiner_in))
397 {}
398 connection_list_type & connection_bodies() { return *_connection_bodies; }
399 const connection_list_type & connection_bodies() const { return *_connection_bodies; }
400 combiner_type & combiner() { return *_combiner; }
401 const combiner_type & combiner() const { return *_combiner; }
402 private:
403 invocation_state(const invocation_state &);
404
405 shared_ptr<connection_list_type> _connection_bodies;
406 shared_ptr<combiner_type> _combiner;
407 };
408 // Destructor of invocation_janitor does some cleanup when a signal invocation completes.
409 // Code can't be put directly in signal's operator() due to complications from void return types.
410 class invocation_janitor: noncopyable
411 {
412 public:
413 typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type;
414 invocation_janitor
415 (
416 const slot_call_iterator_cache_type &cache,
417 const signal_type &sig,
418 const connection_list_type *connection_bodies
419 ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies)
420 {}
421 ~invocation_janitor()
422 {
423 // force a full cleanup of disconnected slots if there are too many
424 if(_cache.disconnected_slot_count > _cache.connected_slot_count)
425 {
426 _sig.force_cleanup_connections(_connection_bodies);
427 }
428 }
429 private:
430 const slot_call_iterator_cache_type &_cache;
431 const signal_type &_sig;
432 const connection_list_type *_connection_bodies;
433 };
434
435 // clean up disconnected connections
436 void nolock_cleanup_connections_from(garbage_collecting_lock<mutex_type> &lock,
437 bool grab_tracked,
438 const typename connection_list_type::iterator &begin, unsigned count = 0) const
439 {
440 BOOST_ASSERT(_shared_state.unique());
441 typename connection_list_type::iterator it;
442 unsigned i;
443 for(it = begin, i = 0;
444 it != _shared_state->connection_bodies().end() && (count == 0 || i < count);
445 ++i)
446 {
447 bool connected;
448 if(grab_tracked)
449 (*it)->disconnect_expired_slot(lock);
450 connected = (*it)->nolock_nograb_connected();
451 if(connected == false)
452 {
453 it = _shared_state->connection_bodies().erase((*it)->group_key(), it);
454 }else
455 {
456 ++it;
457 }
458 }
459 _garbage_collector_it = it;
460 }
461 // clean up a few connections in constant time
462 void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock,
463 bool grab_tracked, unsigned count) const
464 {
465 BOOST_ASSERT(_shared_state.unique());
466 typename connection_list_type::iterator begin;
467 if(_garbage_collector_it == _shared_state->connection_bodies().end())
468 {
469 begin = _shared_state->connection_bodies().begin();
470 }else
471 {
472 begin = _garbage_collector_it;
473 }
474 nolock_cleanup_connections_from(lock, grab_tracked, begin, count);
475 }
476 /* Make a new copy of the slot list if it is currently being read somewhere else
477 */
478 void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock)
479 {
480 if(_shared_state.unique() == false)
481 {
482 _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
483 nolock_cleanup_connections_from(lock, grab_tracked: true, begin: _shared_state->connection_bodies().begin());
484 }else
485 {
486 /* We need to try and check more than just 1 connection here to avoid corner
487 cases where certain repeated connect/disconnect patterns cause the slot
488 list to grow without limit. */
489 nolock_cleanup_connections(lock, grab_tracked: true, count: 2);
490 }
491 }
492 // force a full cleanup of the connection list
493 void force_cleanup_connections(const connection_list_type *connection_bodies) const
494 {
495 garbage_collecting_lock<mutex_type> list_lock(*_mutex);
496 // if the connection list passed in as a parameter is no longer in use,
497 // we don't need to do any cleanup.
498 if(&_shared_state->connection_bodies() != connection_bodies)
499 {
500 return;
501 }
502 if(_shared_state.unique() == false)
503 {
504 _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
505 }
506 nolock_cleanup_connections_from(lock&: list_lock, grab_tracked: false, begin: _shared_state->connection_bodies().begin());
507 }
508 shared_ptr<invocation_state> get_readable_state() const
509 {
510 unique_lock<mutex_type> list_lock(*_mutex);
511 return _shared_state;
512 }
513 connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock,
514 const slot_type &slot)
515 {
516 nolock_force_unique_connection_list(lock);
517 return boost::make_shared<connection_body<group_key_type, slot_type, Mutex> >(slot, _mutex);
518 }
519 void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */)
520 {
521 disconnect(group);
522 }
523 template<typename T>
524 void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
525 {
526 shared_ptr<invocation_state> local_state =
527 get_readable_state();
528 typename connection_list_type::iterator it;
529 for(it = local_state->connection_bodies().begin();
530 it != local_state->connection_bodies().end(); ++it)
531 {
532 garbage_collecting_lock<connection_body_base> lock(**it);
533 if((*it)->nolock_nograb_connected() == false) continue;
534 if((*it)->slot().slot_function().contains(slot))
535 {
536 (*it)->nolock_disconnect(lock);
537 }else
538 { // check for wrapped extended slot
539 bound_extended_slot_function_type *fp;
540 fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>();
541 if(fp && fp->contains(slot))
542 {
543 (*it)->nolock_disconnect(lock);
544 }else
545 { // check for wrapped signal
546 weak_signal_type *fp;
547 fp = (*it)->slot().slot_function().template target<weak_signal_type>();
548 if(fp && fp->contains(slot))
549 {
550 (*it)->nolock_disconnect(lock);
551 }
552 }
553 }
554 }
555 }
556 // connect slot
557 connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
558 const slot_type &slot, connect_position position)
559 {
560 connection_body_type newConnectionBody =
561 create_new_connection(lock, slot);
562 group_key_type group_key;
563 if(position == at_back)
564 {
565 group_key.first = back_ungrouped_slots;
566 _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
567 }else
568 {
569 group_key.first = front_ungrouped_slots;
570 _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
571 }
572 newConnectionBody->set_group_key(group_key);
573 return connection(newConnectionBody);
574 }
575 connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
576 const group_type &group,
577 const slot_type &slot, connect_position position)
578 {
579 connection_body_type newConnectionBody =
580 create_new_connection(lock, slot);
581 // update map to first connection body in group if needed
582 group_key_type group_key(grouped_slots, group);
583 newConnectionBody->set_group_key(group_key);
584 if(position == at_back)
585 {
586 _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
587 }else // at_front
588 {
589 _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
590 }
591 return connection(newConnectionBody);
592 }
593
594 // _shared_state is mutable so we can do force_cleanup_connections during a const invocation
595 mutable shared_ptr<invocation_state> _shared_state;
596 mutable typename connection_list_type::iterator _garbage_collector_it;
597 // connection list mutex must never be locked when attempting a blocking lock on a slot,
598 // or you could deadlock.
599 const boost::shared_ptr<mutex_type> _mutex;
600 };
601
602 }
603
604 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)>
605 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
606
607 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
608 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
609 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base,
610 public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE
611 {
612 typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
613 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class;
614 public:
615 typedef typename impl_class::weak_signal_type weak_signal_type;
616 friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
617 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>;
618
619 typedef SlotFunction slot_function_type;
620 // typedef slotN<Signature, SlotFunction> slot_type;
621 typedef typename impl_class::slot_type slot_type;
622 typedef typename impl_class::extended_slot_function_type extended_slot_function_type;
623 typedef typename impl_class::extended_slot_type extended_slot_type;
624 typedef typename slot_function_type::result_type slot_result_type;
625 typedef Combiner combiner_type;
626 typedef typename impl_class::result_type result_type;
627 typedef Group group_type;
628 typedef GroupCompare group_compare_type;
629 typedef typename impl_class::slot_call_iterator
630 slot_call_iterator;
631 typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type;
632
633#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
634
635// typedef Tn argn_type;
636#define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
637 typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
638 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
639#undef BOOST_SIGNALS2_MISC_STATEMENT
640#if BOOST_SIGNALS2_NUM_ARGS == 1
641 typedef arg1_type argument_type;
642#elif BOOST_SIGNALS2_NUM_ARGS == 2
643 typedef arg1_type first_argument_type;
644 typedef arg2_type second_argument_type;
645#endif
646
647 template<unsigned n> class arg : public
648 detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
649 <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
650 BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)>
651 {};
652
653 BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS);
654
655#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
656
657 template<unsigned n> class arg
658 {
659 public:
660 typedef typename detail::variadic_arg_type<n, Args...>::type type;
661 };
662 BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args));
663
664#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
665
666 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(),
667 const group_compare_type &group_compare = group_compare_type()):
668 _pimpl(new impl_class(combiner_arg, group_compare))
669 {}
670 virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)()
671 {
672 }
673
674 //move support
675#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
676 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
677 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && other) BOOST_NOEXCEPT
678 {
679 using std::swap;
680 swap(_pimpl, other._pimpl);
681 }
682
683 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) &
684 operator=(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && rhs) BOOST_NOEXCEPT
685 {
686 if(this == &rhs)
687 {
688 return *this;
689 }
690 _pimpl.reset();
691 using std::swap;
692 swap(_pimpl, rhs._pimpl);
693 return *this;
694 }
695#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
696
697 connection connect(const slot_type &slot, connect_position position = at_back)
698 {
699 return (*_pimpl).connect(slot, position);
700 }
701 connection connect(const group_type &group,
702 const slot_type &slot, connect_position position = at_back)
703 {
704 return (*_pimpl).connect(group, slot, position);
705 }
706 connection connect_extended(const extended_slot_type &slot, connect_position position = at_back)
707 {
708 return (*_pimpl).connect_extended(slot, position);
709 }
710 connection connect_extended(const group_type &group,
711 const extended_slot_type &slot, connect_position position = at_back)
712 {
713 return (*_pimpl).connect_extended(group, slot, position);
714 }
715 void disconnect_all_slots()
716 {
717 (*_pimpl).disconnect_all_slots();
718 }
719 void disconnect(const group_type &group)
720 {
721 (*_pimpl).disconnect(group);
722 }
723 template <typename T>
724 void disconnect(const T &slot)
725 {
726 (*_pimpl).disconnect(slot);
727 }
728 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
729 {
730 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
731 }
732 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
733 {
734 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
735 }
736 std::size_t num_slots() const
737 {
738 return (*_pimpl).num_slots();
739 }
740 bool empty() const
741 {
742 return (*_pimpl).empty();
743 }
744 combiner_type combiner() const
745 {
746 return (*_pimpl).combiner();
747 }
748 void set_combiner(const combiner_type &combiner_arg)
749 {
750 return (*_pimpl).set_combiner(combiner_arg);
751 }
752 void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT
753 {
754 using std::swap;
755 swap(_pimpl, other._pimpl);
756 }
757 bool operator==(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) const
758 {
759 return _pimpl.get() == other._pimpl.get();
760 }
761 protected:
762 virtual shared_ptr<void> lock_pimpl() const
763 {
764 return _pimpl;
765 }
766 private:
767 // explicit private copy constructor to avoid compiler trying to do implicit conversions to signal
768 explicit BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
769 const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT
770 {
771 // noncopyable
772 BOOST_ASSERT(false);
773 }
774
775 shared_ptr<impl_class>
776 _pimpl;
777 };
778
779#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
780 // free swap function for signalN classes, findable by ADL
781 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
782 void swap(
783 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1,
784 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) BOOST_NOEXCEPT
785 {
786 sig1.swap(sig2);
787 }
788#endif
789
790 namespace detail
791 {
792 // wrapper class for storing other signals as slots with automatic lifetime tracking
793 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
794 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
795
796 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
797 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
798 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
799 {
800 public:
801 typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
802 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type
803 result_type;
804
805 BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
806 (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
807 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>
808 &signal):
809 _weak_pimpl(signal._pimpl)
810 {}
811 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
812 {
813 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
814 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
815 shared_pimpl(_weak_pimpl.lock());
816 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
817 }
818 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
819 {
820 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
821 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
822 shared_pimpl(_weak_pimpl.lock());
823 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
824 }
825 bool contains(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
826 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &signal) const
827 {
828 return _weak_pimpl.lock().get() == signal._pimpl.get();
829 }
830 template <typename T>
831 bool contains(const T&) const
832 {
833 return false;
834 }
835 private:
836 boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
837 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl;
838 };
839
840#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
841 template<int arity, typename Signature>
842 class extended_signature: public variadic_extended_signature<Signature>
843 {};
844#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
845 template<int arity, typename Signature>
846 class extended_signature;
847 // partial template specialization
848 template<typename Signature>
849 class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature>
850 {
851 public:
852// typename function_traits<Signature>::result_type (
853// const boost::signals2::connection &,
854// typename function_traits<Signature>::arg1_type,
855// typename function_traits<Signature>::arg2_type,
856// ...,
857// typename function_traits<Signature>::argn_type)
858#define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \
859 typename function_traits<Signature>::result_type ( \
860 const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \
861 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) )
862 typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type;
863#undef BOOST_SIGNALS2_EXT_SIGNATURE
864 };
865
866 template<unsigned arity, typename Signature, typename Combiner,
867 typename Group, typename GroupCompare, typename SlotFunction,
868 typename ExtendedSlotFunction, typename Mutex>
869 class signalN;
870 // partial template specialization
871 template<typename Signature, typename Combiner, typename Group,
872 typename GroupCompare, typename SlotFunction,
873 typename ExtendedSlotFunction, typename Mutex>
874 class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group,
875 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex>
876 {
877 public:
878 typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)<
879 BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature),
880 Combiner, Group,
881 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type;
882 };
883
884#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
885
886 } // namespace detail
887 } // namespace signals2
888} // namespace boost
889
890#undef BOOST_SIGNALS2_NUM_ARGS
891#undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION
892

source code of boost/libs/signals2/include/boost/signals2/detail/signal_template.hpp