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
56namespace 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

source code of boost/boost/signals/signal_template.hpp