]> git.lyx.org Git - lyx.git/blob - 3rdparty/boost/boost/signals2/detail/signal_template.hpp
Update to boost 1.72
[lyx.git] / 3rdparty / 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