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