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