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