|
1 // Boost.Signals library |
|
2 |
|
3 // Copyright Douglas Gregor 2001-2004. Use, modification and |
|
4 // distribution is subject to the Boost Software License, Version |
|
5 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
6 // http://www.boost.org/LICENSE_1_0.txt) |
|
7 |
|
8 // For more information, see http://www.boost.org |
|
9 |
|
10 // This file intentionally does not have include guards, because it is meant |
|
11 // to be included multiple times (one for each signalN class). The |
|
12 // BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED macro merely serves to |
|
13 // suppress reinclusion of the files that this header depends on. |
|
14 |
|
15 #ifndef BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
16 #define BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
17 # include <boost/config.hpp> |
|
18 # include <boost/signals/connection.hpp> |
|
19 # include <boost/utility.hpp> |
|
20 # include <boost/ref.hpp> |
|
21 # include <boost/signals/slot.hpp> |
|
22 # include <boost/last_value.hpp> |
|
23 # include <boost/signals/detail/signal_base.hpp> |
|
24 # include <boost/signals/detail/slot_call_iterator.hpp> |
|
25 # include <boost/mpl/bool.hpp> |
|
26 # include <boost/type_traits/is_convertible.hpp> |
|
27 # include <cassert> |
|
28 # include <functional> |
|
29 # include <memory> |
|
30 #endif // !BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
31 |
|
32 #ifdef BOOST_HAS_ABI_HEADERS |
|
33 # include BOOST_ABI_PREFIX |
|
34 #endif |
|
35 |
|
36 // Include the appropriate functionN header |
|
37 #define BOOST_SIGNAL_FUNCTION_N_HEADER BOOST_JOIN(<boost/function/function,BOOST_SIGNALS_NUM_ARGS.hpp>) |
|
38 #include BOOST_SIGNAL_FUNCTION_N_HEADER |
|
39 |
|
40 // Determine if a comma should follow a listing of the arguments/parameters |
|
41 #if BOOST_SIGNALS_NUM_ARGS == 0 |
|
42 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
43 #else |
|
44 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS , |
|
45 #endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
46 |
|
47 // Define class names used |
|
48 #define BOOST_SIGNALS_SIGNAL BOOST_JOIN(signal,BOOST_SIGNALS_NUM_ARGS) |
|
49 #define BOOST_SIGNALS_FUNCTION BOOST_JOIN(function,BOOST_SIGNALS_NUM_ARGS) |
|
50 #define BOOST_SIGNALS_ARGS_STRUCT BOOST_JOIN(args,BOOST_SIGNALS_NUM_ARGS) |
|
51 #define BOOST_SIGNALS_CALL_BOUND BOOST_JOIN(call_bound,BOOST_SIGNALS_NUM_ARGS) |
|
52 |
|
53 // Define commonly-used instantiations |
|
54 #define BOOST_SIGNALS_ARGS_STRUCT_INST \ |
|
55 BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS> |
|
56 |
|
57 namespace boost { |
|
58 namespace BOOST_SIGNALS_NAMESPACE { |
|
59 namespace detail { |
|
60 // Holds the arguments for a bound slot call in a single place |
|
61 template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
62 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
63 typename Dummy = int> |
|
64 struct BOOST_SIGNALS_ARGS_STRUCT { |
|
65 BOOST_SIGNALS_ARGS_STRUCT(BOOST_SIGNALS_COPY_PARMS) |
|
66 BOOST_SIGNALS_INIT_ARGS |
|
67 { |
|
68 } |
|
69 |
|
70 BOOST_SIGNALS_ARGS_AS_MEMBERS |
|
71 }; |
|
72 |
|
73 // Function object that calls the function object given to it, passing |
|
74 // the bound arguments along to that underlying function object |
|
75 template<typename R> |
|
76 struct BOOST_SIGNALS_CALL_BOUND { |
|
77 template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
78 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
79 typename F> |
|
80 struct caller { |
|
81 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* |
|
82 args_type; |
|
83 |
|
84 args_type args; |
|
85 |
|
86 typedef R result_type; |
|
87 |
|
88 caller() {} |
|
89 caller(args_type a) : args(a) {} |
|
90 |
|
91 template<typename Pair> |
|
92 R operator()(const Pair& slot) const |
|
93 { |
|
94 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); |
|
95 return (*target)(BOOST_SIGNALS_BOUND_ARGS); |
|
96 } |
|
97 }; |
|
98 }; |
|
99 |
|
100 template<> |
|
101 struct BOOST_SIGNALS_CALL_BOUND<void> { |
|
102 template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
103 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
104 typename F> |
|
105 struct caller { |
|
106 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* |
|
107 args_type; |
|
108 |
|
109 args_type args; |
|
110 |
|
111 typedef unusable result_type; |
|
112 |
|
113 caller(args_type a) : args(a) {} |
|
114 |
|
115 template<typename Pair> |
|
116 unusable operator()(const Pair& slot) const |
|
117 { |
|
118 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); |
|
119 (*target)(BOOST_SIGNALS_BOUND_ARGS); |
|
120 return unusable(); |
|
121 } |
|
122 }; |
|
123 }; |
|
124 } // namespace detail |
|
125 } // namespace BOOST_SIGNALS_NAMESPACE |
|
126 |
|
127 // The actual signalN class |
|
128 template< |
|
129 typename R, |
|
130 BOOST_SIGNALS_TEMPLATE_PARMS |
|
131 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
132 typename Combiner = last_value<R>, |
|
133 typename Group = int, |
|
134 typename GroupCompare = std::less<Group>, |
|
135 typename SlotFunction = BOOST_SIGNALS_FUNCTION< |
|
136 R BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
137 BOOST_SIGNALS_TEMPLATE_ARGS> |
|
138 > |
|
139 class BOOST_SIGNALS_SIGNAL : |
|
140 public BOOST_SIGNALS_NAMESPACE::detail::signal_base, // management of slot list |
|
141 public BOOST_SIGNALS_NAMESPACE::trackable // signals are trackable |
|
142 { |
|
143 public: |
|
144 // The slot function type |
|
145 typedef SlotFunction slot_function_type; |
|
146 |
|
147 // Result type of a slot |
|
148 typedef typename BOOST_SIGNALS_NAMESPACE::detail::slot_result_type<R>::type |
|
149 slot_result_type; |
|
150 |
|
151 // Argument types |
|
152 BOOST_SIGNALS_ARG_TYPES |
|
153 |
|
154 #if BOOST_SIGNALS_NUM_ARGS == 1 |
|
155 typedef T1 argument_type; |
|
156 #elif BOOST_SIGNALS_NUM_ARGS == 2 |
|
157 typedef T1 first_argument_type; |
|
158 typedef T2 second_argument_type; |
|
159 #endif |
|
160 |
|
161 private: |
|
162 // The real slot name comparison object type |
|
163 typedef BOOST_SIGNALS_NAMESPACE::detail::group_bridge_compare<GroupCompare, Group> |
|
164 real_group_compare_type; |
|
165 |
|
166 // The function object passed to the slot call iterator that will call |
|
167 // the underlying slot function with its arguments bound |
|
168 typedef BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND<R> |
|
169 outer_bound_slot_caller; |
|
170 typedef typename outer_bound_slot_caller::template |
|
171 caller<BOOST_SIGNALS_TEMPLATE_ARGS |
|
172 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
173 slot_function_type> |
|
174 call_bound_slot; |
|
175 |
|
176 public: |
|
177 // Combiner's result type |
|
178 typedef typename Combiner::result_type result_type; |
|
179 |
|
180 // Combiner type |
|
181 typedef Combiner combiner_type; |
|
182 |
|
183 // Slot type |
|
184 typedef slot<slot_function_type> slot_type; |
|
185 |
|
186 // Slot name type and comparison |
|
187 typedef Group group_type; |
|
188 typedef GroupCompare group_compare_type; |
|
189 |
|
190 typedef BOOST_SIGNALS_NAMESPACE::detail::slot_call_iterator< |
|
191 call_bound_slot, iterator> slot_call_iterator; |
|
192 |
|
193 explicit |
|
194 BOOST_SIGNALS_SIGNAL(const Combiner& c = Combiner(), |
|
195 const GroupCompare& comp = GroupCompare()) : |
|
196 BOOST_SIGNALS_NAMESPACE::detail::signal_base(real_group_compare_type(comp), |
|
197 c) |
|
198 { |
|
199 } |
|
200 |
|
201 // Connect a slot to this signal |
|
202 BOOST_SIGNALS_NAMESPACE::connection |
|
203 connect(const slot_type&, |
|
204 BOOST_SIGNALS_NAMESPACE::connect_position at |
|
205 = BOOST_SIGNALS_NAMESPACE::at_back); |
|
206 |
|
207 |
|
208 BOOST_SIGNALS_NAMESPACE::connection |
|
209 connect(const group_type&, const slot_type&, |
|
210 BOOST_SIGNALS_NAMESPACE::connect_position at |
|
211 = BOOST_SIGNALS_NAMESPACE::at_back); |
|
212 |
|
213 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
214 // MSVC 6.0 and 7.0 don't handle the is_convertible test well |
|
215 void disconnect(const group_type& group) |
|
216 { |
|
217 impl->disconnect(group); |
|
218 } |
|
219 #else |
|
220 template<typename T> |
|
221 void disconnect(const T& t) |
|
222 { |
|
223 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group; |
|
224 this->do_disconnect(t, is_group()); |
|
225 } |
|
226 |
|
227 private: |
|
228 // Disconnect a named slot |
|
229 void do_disconnect(const group_type& group, mpl::bool_<true>) |
|
230 { |
|
231 impl->disconnect(group); |
|
232 } |
|
233 |
|
234 template<typename Function> |
|
235 void do_disconnect(const Function& f, mpl::bool_<false>) |
|
236 { |
|
237 // Notify the slot handling code that we are iterating through the slots |
|
238 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
239 |
|
240 for (iterator i = impl->slots_.begin(); i != impl->slots_.end(); ++i) { |
|
241 slot_function_type& s = *unsafe_any_cast<slot_function_type>(&i->second); |
|
242 if (s == f) i->first.disconnect(); |
|
243 } |
|
244 } |
|
245 #endif |
|
246 |
|
247 public: |
|
248 |
|
249 // Emit the signal |
|
250 result_type operator()(BOOST_SIGNALS_PARMS); |
|
251 result_type operator()(BOOST_SIGNALS_PARMS) const; |
|
252 |
|
253 Combiner& combiner() |
|
254 { return *unsafe_any_cast<Combiner>(&impl->combiner_); } |
|
255 |
|
256 const Combiner& combiner() const |
|
257 { return *unsafe_any_cast<const Combiner>(&impl->combiner_); } |
|
258 }; |
|
259 |
|
260 template< |
|
261 typename R, |
|
262 BOOST_SIGNALS_TEMPLATE_PARMS |
|
263 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
264 typename Combiner, |
|
265 typename Group, |
|
266 typename GroupCompare, |
|
267 typename SlotFunction |
|
268 > |
|
269 BOOST_SIGNALS_NAMESPACE::connection |
|
270 BOOST_SIGNALS_SIGNAL< |
|
271 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
272 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
273 Combiner, Group, GroupCompare, SlotFunction |
|
274 >::connect(const slot_type& in_slot, |
|
275 BOOST_SIGNALS_NAMESPACE::connect_position at) |
|
276 { |
|
277 using boost::BOOST_SIGNALS_NAMESPACE::detail::stored_group; |
|
278 |
|
279 // If the slot has been disconnected, just return a disconnected |
|
280 // connection |
|
281 if (!in_slot.is_active()) { |
|
282 return BOOST_SIGNALS_NAMESPACE::connection(); |
|
283 } |
|
284 |
|
285 return impl->connect_slot(in_slot.get_slot_function(), stored_group(), |
|
286 in_slot.get_data(), at); |
|
287 } |
|
288 |
|
289 template< |
|
290 typename R, |
|
291 BOOST_SIGNALS_TEMPLATE_PARMS |
|
292 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
293 typename Combiner, |
|
294 typename Group, |
|
295 typename GroupCompare, |
|
296 typename SlotFunction |
|
297 > |
|
298 BOOST_SIGNALS_NAMESPACE::connection |
|
299 BOOST_SIGNALS_SIGNAL< |
|
300 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
301 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
302 Combiner, Group, GroupCompare, SlotFunction |
|
303 >::connect(const group_type& group, |
|
304 const slot_type& in_slot, |
|
305 BOOST_SIGNALS_NAMESPACE::connect_position at) |
|
306 { |
|
307 // If the slot has been disconnected, just return a disconnected |
|
308 // connection |
|
309 if (!in_slot.is_active()) { |
|
310 return BOOST_SIGNALS_NAMESPACE::connection(); |
|
311 } |
|
312 |
|
313 return impl->connect_slot(in_slot.get_slot_function(), group, |
|
314 in_slot.get_data(), at); |
|
315 } |
|
316 |
|
317 template< |
|
318 typename R, |
|
319 BOOST_SIGNALS_TEMPLATE_PARMS |
|
320 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
321 typename Combiner, |
|
322 typename Group, |
|
323 typename GroupCompare, |
|
324 typename SlotFunction |
|
325 > |
|
326 typename BOOST_SIGNALS_SIGNAL< |
|
327 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
328 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
329 Combiner, Group, GroupCompare, SlotFunction>::result_type |
|
330 BOOST_SIGNALS_SIGNAL< |
|
331 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
332 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
333 Combiner, Group, GroupCompare, SlotFunction |
|
334 >::operator()(BOOST_SIGNALS_PARMS) |
|
335 { |
|
336 // Notify the slot handling code that we are making a call |
|
337 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
338 |
|
339 // Construct a function object that will call the underlying slots |
|
340 // with the given arguments. |
|
341 #if BOOST_SIGNALS_NUM_ARGS == 0 |
|
342 BOOST_SIGNALS_ARGS_STRUCT_INST args; |
|
343 #else |
|
344 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); |
|
345 #endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
346 call_bound_slot f(&args); |
|
347 |
|
348 typedef typename call_bound_slot::result_type result_type; |
|
349 optional<result_type> cache; |
|
350 // Let the combiner call the slots via a pair of input iterators |
|
351 return combiner()(slot_call_iterator(notification.impl->slots_.begin(), |
|
352 impl->slots_.end(), f, cache), |
|
353 slot_call_iterator(notification.impl->slots_.end(), |
|
354 impl->slots_.end(), f, cache)); |
|
355 } |
|
356 |
|
357 template< |
|
358 typename R, |
|
359 BOOST_SIGNALS_TEMPLATE_PARMS |
|
360 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
361 typename Combiner, |
|
362 typename Group, |
|
363 typename GroupCompare, |
|
364 typename SlotFunction |
|
365 > |
|
366 typename BOOST_SIGNALS_SIGNAL< |
|
367 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
368 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
369 Combiner, Group, GroupCompare, SlotFunction>::result_type |
|
370 BOOST_SIGNALS_SIGNAL< |
|
371 R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
372 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
373 Combiner, Group, GroupCompare, SlotFunction |
|
374 >::operator()(BOOST_SIGNALS_PARMS) const |
|
375 { |
|
376 // Notify the slot handling code that we are making a call |
|
377 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
378 |
|
379 // Construct a function object that will call the underlying slots |
|
380 // with the given arguments. |
|
381 #if BOOST_SIGNALS_NUM_ARGS == 0 |
|
382 BOOST_SIGNALS_ARGS_STRUCT_INST args; |
|
383 #else |
|
384 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); |
|
385 #endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
386 |
|
387 call_bound_slot f(&args); |
|
388 |
|
389 typedef typename call_bound_slot::result_type result_type; |
|
390 optional<result_type> cache; |
|
391 |
|
392 // Let the combiner call the slots via a pair of input iterators |
|
393 return combiner()(slot_call_iterator(notification.impl->slots_.begin(), |
|
394 impl->slots_.end(), f, cache), |
|
395 slot_call_iterator(notification.impl->slots_.end(), |
|
396 impl->slots_.end(), f, cache)); |
|
397 } |
|
398 } // namespace boost |
|
399 |
|
400 #undef BOOST_SIGNAL_FUNCTION_N_HEADER |
|
401 #undef BOOST_SIGNALS_ARGS_STRUCT_INST |
|
402 #undef BOOST_SIGNALS_CALL_BOUND |
|
403 #undef BOOST_SIGNALS_ARGS_STRUCT |
|
404 #undef BOOST_SIGNALS_FUNCTION |
|
405 #undef BOOST_SIGNALS_SIGNAL |
|
406 #undef BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
407 |
|
408 #ifdef BOOST_HAS_ABI_HEADERS |
|
409 # include BOOST_ABI_SUFFIX |
|
410 #endif |