]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/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_SIGNAL_FUNCTION_N_HEADER 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(in_slot.get_slot_function(), stored_group(), | |
277 | 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(in_slot.get_slot_function(), group, | |
305 | 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 |