]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Signals library |
2 | ||
3 | // Copyright Frank Mori Hess 2008-2009. | |
4 | // Copyright Douglas Gregor 2001-2003. | |
5 | // | |
6 | // Use, modification and | |
7 | // distribution is subject to the Boost Software License, Version | |
8 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
9 | // http://www.boost.org/LICENSE_1_0.txt) | |
10 | ||
11 | // For more information, see http://www.boost.org | |
12 | ||
b32b8144 | 13 | #include <boost/bind.hpp> |
7c673cae FG |
14 | #include <boost/optional.hpp> |
15 | #include <boost/test/minimal.hpp> | |
16 | #include <boost/signals2.hpp> | |
17 | #include <functional> | |
18 | #include <iostream> | |
19 | #include <typeinfo> | |
20 | ||
21 | template<typename T> | |
22 | struct max_or_default { | |
23 | typedef T result_type; | |
24 | template<typename InputIterator> | |
25 | typename InputIterator::value_type | |
26 | operator()(InputIterator first, InputIterator last) const | |
27 | { | |
28 | boost::optional<T> max; | |
29 | for (; first != last; ++first) | |
30 | { | |
31 | try | |
32 | { | |
33 | if(!max) max = *first; | |
34 | else max = (*first > max.get())? *first : max; | |
35 | } | |
36 | catch(const boost::bad_weak_ptr &) | |
37 | {} | |
38 | } | |
39 | if(max) return max.get(); | |
40 | return T(); | |
41 | } | |
42 | }; | |
43 | ||
44 | struct make_int { | |
45 | make_int(int n, int cn) : N(n), CN(cn) {} | |
46 | ||
47 | int operator()() { return N; } | |
48 | int operator()() const { return CN; } | |
49 | ||
50 | int N; | |
51 | int CN; | |
52 | }; | |
53 | ||
54 | template<int N> | |
55 | struct make_increasing_int { | |
56 | make_increasing_int() : n(N) {} | |
57 | ||
58 | int operator()() const { return n++; } | |
59 | ||
60 | mutable int n; | |
61 | }; | |
62 | ||
63 | static void | |
64 | test_zero_args() | |
65 | { | |
66 | make_int i42(42, 41); | |
67 | make_int i2(2, 1); | |
68 | make_int i72(72, 71); | |
69 | make_int i63(63, 63); | |
70 | make_int i62(62, 61); | |
71 | ||
72 | { | |
73 | boost::signals2::signal<int (), max_or_default<int> > s0; | |
74 | ||
75 | std::cout << "sizeof(signal) = " << sizeof(s0) << std::endl; | |
76 | boost::signals2::connection c2 = s0.connect(i2); | |
77 | boost::signals2::connection c72 = s0.connect(72, i72); | |
78 | boost::signals2::connection c62 = s0.connect(60, i62); | |
79 | boost::signals2::connection c42 = s0.connect(i42); | |
80 | ||
81 | BOOST_CHECK(s0() == 72); | |
82 | ||
83 | s0.disconnect(72); | |
84 | BOOST_CHECK(s0() == 62); | |
85 | ||
86 | c72.disconnect(); // Double-disconnect should be safe | |
87 | BOOST_CHECK(s0() == 62); | |
88 | ||
89 | s0.disconnect(72); // Triple-disconect should be safe | |
90 | BOOST_CHECK(s0() == 62); | |
91 | ||
92 | // Also connect 63 in the same group as 62 | |
93 | s0.connect(60, i63); | |
94 | BOOST_CHECK(s0() == 63); | |
95 | ||
96 | // Disconnect all of the 60's | |
97 | s0.disconnect(60); | |
98 | BOOST_CHECK(s0() == 42); | |
99 | ||
100 | c42.disconnect(); | |
101 | BOOST_CHECK(s0() == 2); | |
102 | ||
103 | c2.disconnect(); | |
104 | BOOST_CHECK(s0() == 0); | |
105 | } | |
106 | ||
107 | { | |
108 | boost::signals2::signal<int (), max_or_default<int> > s0; | |
109 | boost::signals2::connection c2 = s0.connect(i2); | |
110 | boost::signals2::connection c72 = s0.connect(i72); | |
111 | boost::signals2::connection c62 = s0.connect(i62); | |
112 | boost::signals2::connection c42 = s0.connect(i42); | |
113 | ||
114 | const boost::signals2::signal<int (), max_or_default<int> >& cs0 = s0; | |
115 | BOOST_CHECK(cs0() == 72); | |
116 | } | |
117 | ||
118 | { | |
119 | make_increasing_int<7> i7; | |
120 | make_increasing_int<10> i10; | |
121 | ||
122 | boost::signals2::signal<int (), max_or_default<int> > s0; | |
123 | boost::signals2::connection c7 = s0.connect(i7); | |
124 | boost::signals2::connection c10 = s0.connect(i10); | |
125 | ||
126 | BOOST_CHECK(s0() == 10); | |
127 | BOOST_CHECK(s0() == 11); | |
128 | } | |
129 | } | |
130 | ||
131 | static void | |
132 | test_one_arg() | |
133 | { | |
134 | boost::signals2::signal<int (int value), max_or_default<int> > s1; | |
135 | ||
136 | s1.connect(std::negate<int>()); | |
b32b8144 | 137 | s1.connect(boost::bind(std::multiplies<int>(), 2, _1)); |
7c673cae FG |
138 | |
139 | BOOST_CHECK(s1(1) == 2); | |
140 | BOOST_CHECK(s1(-1) == 1); | |
141 | } | |
142 | ||
143 | static void | |
144 | test_signal_signal_connect() | |
145 | { | |
146 | typedef boost::signals2::signal<int (int value), max_or_default<int> > signal_type; | |
147 | signal_type s1; | |
148 | ||
149 | s1.connect(std::negate<int>()); | |
150 | ||
151 | BOOST_CHECK(s1(3) == -3); | |
152 | ||
153 | { | |
154 | signal_type s2; | |
155 | s1.connect(s2); | |
b32b8144 FG |
156 | s2.connect(boost::bind(std::multiplies<int>(), 2, _1)); |
157 | s2.connect(boost::bind(std::multiplies<int>(), -3, _1)); | |
7c673cae FG |
158 | |
159 | BOOST_CHECK(s2(-3) == 9); | |
160 | BOOST_CHECK(s1(3) == 6); | |
161 | } // s2 goes out of scope and disconnects | |
162 | BOOST_CHECK(s1(3) == -3); | |
163 | } | |
164 | ||
165 | template<typename ResultType> | |
166 | ResultType disconnecting_slot(const boost::signals2::connection &conn, int) | |
167 | { | |
168 | conn.disconnect(); | |
169 | return ResultType(); | |
170 | } | |
171 | ||
172 | #ifdef BOOST_NO_VOID_RETURNS | |
173 | template<> | |
174 | void disconnecting_slot<void>(const boost::signals2::connection &conn, int) | |
175 | { | |
176 | conn.disconnect(); | |
177 | return; | |
178 | } | |
179 | #endif | |
180 | ||
181 | template<typename ResultType> | |
182 | void test_extended_slot() | |
183 | { | |
184 | { | |
185 | typedef boost::signals2::signal<ResultType (int)> signal_type; | |
186 | typedef typename signal_type::extended_slot_type slot_type; | |
187 | signal_type sig; | |
188 | // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer | |
189 | ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; | |
190 | slot_type myslot(fp); | |
191 | sig.connect_extended(myslot); | |
192 | BOOST_CHECK(sig.num_slots() == 1); | |
193 | sig(0); | |
194 | BOOST_CHECK(sig.num_slots() == 0); | |
195 | } | |
196 | { // test 0 arg signal | |
197 | typedef boost::signals2::signal<ResultType ()> signal_type; | |
198 | typedef typename signal_type::extended_slot_type slot_type; | |
199 | signal_type sig; | |
200 | // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer | |
201 | ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; | |
202 | slot_type myslot(fp, _1, 0); | |
203 | sig.connect_extended(myslot); | |
204 | BOOST_CHECK(sig.num_slots() == 1); | |
205 | sig(); | |
206 | BOOST_CHECK(sig.num_slots() == 0); | |
207 | } | |
208 | // test disconnection by slot | |
209 | { | |
210 | typedef boost::signals2::signal<ResultType (int)> signal_type; | |
211 | typedef typename signal_type::extended_slot_type slot_type; | |
212 | signal_type sig; | |
213 | // attempting to work around msvc 7.1 bug by explicitly assigning to a function pointer | |
214 | ResultType (*fp)(const boost::signals2::connection &conn, int) = &disconnecting_slot<ResultType>; | |
215 | slot_type myslot(fp); | |
216 | sig.connect_extended(myslot); | |
217 | BOOST_CHECK(sig.num_slots() == 1); | |
218 | sig.disconnect(fp); | |
219 | BOOST_CHECK(sig.num_slots() == 0); | |
220 | } | |
221 | } | |
222 | ||
223 | void increment_arg(int &value) | |
224 | { | |
225 | ++value; | |
226 | } | |
227 | ||
228 | static void | |
229 | test_reference_args() | |
230 | { | |
231 | typedef boost::signals2::signal<void (int &)> signal_type; | |
232 | signal_type s1; | |
233 | ||
234 | s1.connect(&increment_arg); | |
235 | int value = 0; | |
236 | s1(value); | |
237 | BOOST_CHECK(value == 1); | |
238 | } | |
239 | ||
240 | static void | |
241 | test_typedefs_etc() | |
242 | { | |
243 | typedef boost::signals2::signal<int (double, long)> signal_type; | |
244 | typedef signal_type::slot_type slot_type; | |
245 | ||
246 | BOOST_CHECK(typeid(signal_type::slot_result_type) == typeid(int)); | |
247 | BOOST_CHECK(typeid(signal_type::result_type) == typeid(boost::optional<int>)); | |
248 | BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(double)); | |
249 | BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(long)); | |
250 | BOOST_CHECK(typeid(signal_type::arg<0>::type) == typeid(signal_type::first_argument_type)); | |
251 | BOOST_CHECK(typeid(signal_type::arg<1>::type) == typeid(signal_type::second_argument_type)); | |
252 | BOOST_CHECK(typeid(signal_type::signature_type) == typeid(int (double, long))); | |
253 | BOOST_CHECK(signal_type::arity == 2); | |
254 | ||
255 | BOOST_CHECK(typeid(slot_type::result_type) == typeid(signal_type::slot_result_type)); | |
256 | BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(signal_type::arg<0>::type)); | |
257 | BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(signal_type::arg<1>::type)); | |
258 | BOOST_CHECK(typeid(slot_type::arg<0>::type) == typeid(slot_type::first_argument_type)); | |
259 | BOOST_CHECK(typeid(slot_type::arg<1>::type) == typeid(slot_type::second_argument_type)); | |
260 | BOOST_CHECK(typeid(slot_type::signature_type) == typeid(signal_type::signature_type)); | |
261 | BOOST_CHECK(slot_type::arity == signal_type::arity); | |
262 | ||
263 | typedef boost::signals2::signal<void (short)> unary_signal_type; | |
264 | BOOST_CHECK(typeid(unary_signal_type::slot_result_type) == typeid(void)); | |
265 | BOOST_CHECK(typeid(unary_signal_type::argument_type) == typeid(short)); | |
266 | BOOST_CHECK(typeid(unary_signal_type::slot_type::argument_type) == typeid(short)); | |
267 | } | |
268 | ||
269 | class dummy_combiner | |
270 | { | |
271 | public: | |
272 | typedef int result_type; | |
273 | ||
274 | dummy_combiner(result_type return_value): _return_value(return_value) | |
275 | {} | |
276 | template<typename SlotIterator> | |
277 | result_type operator()(SlotIterator, SlotIterator) | |
278 | { | |
279 | return _return_value; | |
280 | } | |
281 | private: | |
282 | result_type _return_value; | |
283 | }; | |
284 | ||
285 | static void | |
286 | test_set_combiner() | |
287 | { | |
288 | typedef boost::signals2::signal<int (), dummy_combiner> signal_type; | |
289 | signal_type sig(dummy_combiner(0)); | |
290 | BOOST_CHECK(sig() == 0); | |
291 | BOOST_CHECK(sig.combiner()(0,0) == 0); | |
292 | sig.set_combiner(dummy_combiner(1)); | |
293 | BOOST_CHECK(sig() == 1); | |
294 | BOOST_CHECK(sig.combiner()(0,0) == 1); | |
295 | } | |
296 | ||
297 | static void | |
298 | test_swap() | |
299 | { | |
300 | typedef boost::signals2::signal<int (), dummy_combiner> signal_type; | |
301 | signal_type sig1(dummy_combiner(1)); | |
302 | BOOST_CHECK(sig1() == 1); | |
303 | signal_type sig2(dummy_combiner(2)); | |
304 | BOOST_CHECK(sig2() == 2); | |
305 | ||
306 | sig1.swap(sig2); | |
307 | BOOST_CHECK(sig1() == 2); | |
308 | BOOST_CHECK(sig2() == 1); | |
309 | ||
310 | using std::swap; | |
311 | swap(sig1, sig2); | |
312 | BOOST_CHECK(sig1() == 1); | |
313 | BOOST_CHECK(sig2() == 2); | |
314 | } | |
315 | ||
316 | void test_move() | |
317 | { | |
318 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
319 | typedef boost::signals2::signal<int (), dummy_combiner> signal_type; | |
320 | signal_type sig1(dummy_combiner(1)); | |
321 | BOOST_CHECK(sig1() == 1); | |
322 | signal_type sig2(dummy_combiner(2)); | |
323 | BOOST_CHECK(sig2() == 2); | |
324 | ||
325 | sig1 = std::move(sig2); | |
326 | BOOST_CHECK(sig1() == 2); | |
327 | ||
328 | signal_type sig3(std::move(sig1)); | |
329 | BOOST_CHECK(sig3() == 2); | |
330 | #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) | |
331 | } | |
332 | ||
333 | int | |
334 | test_main(int, char* []) | |
335 | { | |
336 | test_zero_args(); | |
337 | test_one_arg(); | |
338 | test_signal_signal_connect(); | |
339 | test_extended_slot<void>(); | |
340 | test_extended_slot<int>(); | |
341 | test_reference_args(); | |
342 | test_typedefs_etc(); | |
343 | test_set_combiner(); | |
344 | test_swap(); | |
345 | test_move(); | |
346 | return 0; | |
347 | } |