1 | // Boost.Function library |
2 | |
3 | // Copyright Douglas Gregor 2001-2003. 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 | #if defined(__clang__) && defined(__has_warning) |
11 | # if __has_warning( "-Wself-assign-overloaded" ) |
12 | # pragma clang diagnostic ignored "-Wself-assign-overloaded" |
13 | # endif |
14 | #endif |
15 | |
16 | #include <boost/function.hpp> |
17 | #include <boost/core/lightweight_test.hpp> |
18 | #include <functional> |
19 | #include <cassert> |
20 | #include <string> |
21 | |
22 | #define BOOST_CHECK BOOST_TEST |
23 | |
24 | using namespace boost; |
25 | using std::string; |
26 | using std::negate; |
27 | |
28 | int global_int; |
29 | |
30 | struct write_five_obj { void operator()() const { global_int = 5; } }; |
31 | struct write_three_obj { int operator()() const { global_int = 3; return 7; }}; |
32 | static void write_five() { global_int = 5; } |
33 | static void write_three() { global_int = 3; } |
34 | struct generate_five_obj { int operator()() const { return 5; } }; |
35 | struct generate_three_obj { int operator()() const { return 3; } }; |
36 | static int generate_five() { return 5; } |
37 | static int generate_three() { return 3; } |
38 | static string identity_str(const string& s) { return s; } |
39 | static string string_cat(const string& s1, const string& s2) { return s1+s2; } |
40 | static int sum_ints(int x, int y) { return x+y; } |
41 | |
42 | struct write_const_1_nonconst_2 |
43 | { |
44 | void operator()() { global_int = 2; } |
45 | void operator()() const { global_int = 1; } |
46 | }; |
47 | |
48 | struct add_to_obj |
49 | { |
50 | add_to_obj(int v) : value(v) {} |
51 | |
52 | int operator()(int x) const { return value + x; } |
53 | |
54 | int value; |
55 | }; |
56 | |
57 | static void |
58 | test_zero_args() |
59 | { |
60 | typedef function0<void> func_void_type; |
61 | |
62 | write_five_obj five = write_five_obj(); // Initialization for Borland C++ 5.5 |
63 | write_three_obj three = write_three_obj(); // Ditto |
64 | |
65 | // Default construction |
66 | func_void_type v1; |
67 | BOOST_CHECK(v1.empty()); |
68 | |
69 | // Assignment to an empty function |
70 | v1 = five; |
71 | BOOST_CHECK(!v1.empty()); |
72 | |
73 | // Invocation of a function |
74 | global_int = 0; |
75 | v1(); |
76 | BOOST_CHECK(global_int == 5); |
77 | |
78 | // clear() method |
79 | v1.clear(); |
80 | BOOST_CHECK(!v1); |
81 | |
82 | // Assignment to an empty function |
83 | v1 = three; |
84 | BOOST_CHECK(!v1.empty()); |
85 | |
86 | // Invocation and self-assignment |
87 | global_int = 0; |
88 | v1 = v1; |
89 | v1(); |
90 | BOOST_CHECK(global_int == 3); |
91 | |
92 | // Assignment to a non-empty function |
93 | v1 = five; |
94 | |
95 | // Invocation and self-assignment |
96 | global_int = 0; |
97 | v1 = (v1); |
98 | v1(); |
99 | BOOST_CHECK(global_int == 5); |
100 | |
101 | // clear |
102 | v1 = 0; |
103 | BOOST_CHECK(v1.empty()); |
104 | |
105 | // Assignment to an empty function from a free function |
106 | v1 = &write_five; |
107 | BOOST_CHECK(!v1.empty()); |
108 | |
109 | // Invocation |
110 | global_int = 0; |
111 | v1(); |
112 | BOOST_CHECK(global_int == 5); |
113 | |
114 | // Assignment to a non-empty function from a free function |
115 | v1 = &write_three; |
116 | BOOST_CHECK(!v1.empty()); |
117 | |
118 | // Invocation |
119 | global_int = 0; |
120 | v1(); |
121 | BOOST_CHECK(global_int == 3); |
122 | |
123 | // Assignment |
124 | v1 = five; |
125 | BOOST_CHECK(!v1.empty()); |
126 | |
127 | // Invocation |
128 | global_int = 0; |
129 | v1(); |
130 | BOOST_CHECK(global_int == 5); |
131 | |
132 | // Assignment to a non-empty function from a free function |
133 | v1 = write_three; |
134 | BOOST_CHECK(!v1.empty()); |
135 | |
136 | // Invocation |
137 | global_int = 0; |
138 | v1(); |
139 | BOOST_CHECK(global_int == 3); |
140 | |
141 | // Construction from another function (that is empty) |
142 | v1.clear(); |
143 | func_void_type v2(v1); |
144 | BOOST_CHECK(!v2? true : false); |
145 | |
146 | // Assignment to an empty function |
147 | v2 = three; |
148 | BOOST_CHECK(!v2.empty()); |
149 | |
150 | // Invocation |
151 | global_int = 0; |
152 | v2(); |
153 | BOOST_CHECK(global_int == 3); |
154 | |
155 | // Assignment to a non-empty function |
156 | v2 = (five); |
157 | |
158 | // Invocation |
159 | global_int = 0; |
160 | v2(); |
161 | BOOST_CHECK(global_int == 5); |
162 | |
163 | v2.clear(); |
164 | BOOST_CHECK(v2.empty()); |
165 | |
166 | // Assignment to an empty function from a free function |
167 | v2 = (&write_five); |
168 | BOOST_CHECK(v2? true : false); |
169 | |
170 | // Invocation |
171 | global_int = 0; |
172 | v2(); |
173 | BOOST_CHECK(global_int == 5); |
174 | |
175 | // Assignment to a non-empty function from a free function |
176 | v2 = &write_three; |
177 | BOOST_CHECK(!v2.empty()); |
178 | |
179 | // Invocation |
180 | global_int = 0; |
181 | v2(); |
182 | BOOST_CHECK(global_int == 3); |
183 | |
184 | // Swapping |
185 | v1 = five; |
186 | swap(f1&: v1, f2&: v2); |
187 | v2(); |
188 | BOOST_CHECK(global_int == 5); |
189 | v1(); |
190 | BOOST_CHECK(global_int == 3); |
191 | swap(f1&: v1, f2&: v2); |
192 | v1.clear(); |
193 | |
194 | // Assignment |
195 | v2 = five; |
196 | BOOST_CHECK(!v2.empty()); |
197 | |
198 | // Invocation |
199 | global_int = 0; |
200 | v2(); |
201 | BOOST_CHECK(global_int == 5); |
202 | |
203 | // Assignment to a non-empty function from a free function |
204 | v2 = &write_three; |
205 | BOOST_CHECK(!v2.empty()); |
206 | |
207 | // Invocation |
208 | global_int = 0; |
209 | v2(); |
210 | BOOST_CHECK(global_int == 3); |
211 | |
212 | // Assignment to a function from an empty function |
213 | v2 = v1; |
214 | BOOST_CHECK(v2.empty()); |
215 | |
216 | // Assignment to a function from a function with a functor |
217 | v1 = three; |
218 | v2 = v1; |
219 | BOOST_CHECK(!v1.empty()); |
220 | BOOST_CHECK(!v2.empty()); |
221 | |
222 | // Invocation |
223 | global_int = 0; |
224 | v1(); |
225 | BOOST_CHECK(global_int == 3); |
226 | global_int = 0; |
227 | v2(); |
228 | BOOST_CHECK(global_int == 3); |
229 | |
230 | // Assign to a function from a function with a function |
231 | v2 = &write_five; |
232 | v1 = v2; |
233 | BOOST_CHECK(!v1.empty()); |
234 | BOOST_CHECK(!v2.empty()); |
235 | global_int = 0; |
236 | v1(); |
237 | BOOST_CHECK(global_int == 5); |
238 | global_int = 0; |
239 | v2(); |
240 | BOOST_CHECK(global_int == 5); |
241 | |
242 | // Construct a function given another function containing a function |
243 | func_void_type v3(v1); |
244 | |
245 | // Invocation of a function |
246 | global_int = 0; |
247 | v3(); |
248 | BOOST_CHECK(global_int == 5); |
249 | |
250 | // clear() method |
251 | v3.clear(); |
252 | BOOST_CHECK(!v3? true : false); |
253 | |
254 | // Assignment to an empty function |
255 | v3 = three; |
256 | BOOST_CHECK(!v3.empty()); |
257 | |
258 | // Invocation |
259 | global_int = 0; |
260 | v3(); |
261 | BOOST_CHECK(global_int == 3); |
262 | |
263 | // Assignment to a non-empty function |
264 | v3 = five; |
265 | |
266 | // Invocation |
267 | global_int = 0; |
268 | v3(); |
269 | BOOST_CHECK(global_int == 5); |
270 | |
271 | // clear() |
272 | v3.clear(); |
273 | BOOST_CHECK(v3.empty()); |
274 | |
275 | // Assignment to an empty function from a free function |
276 | v3 = &write_five; |
277 | BOOST_CHECK(!v3.empty()); |
278 | |
279 | // Invocation |
280 | global_int = 0; |
281 | v3(); |
282 | BOOST_CHECK(global_int == 5); |
283 | |
284 | // Assignment to a non-empty function from a free function |
285 | v3 = &write_three; |
286 | BOOST_CHECK(!v3.empty()); |
287 | |
288 | // Invocation |
289 | global_int = 0; |
290 | v3(); |
291 | BOOST_CHECK(global_int == 3); |
292 | |
293 | // Assignment |
294 | v3 = five; |
295 | BOOST_CHECK(!v3.empty()); |
296 | |
297 | // Invocation |
298 | global_int = 0; |
299 | v3(); |
300 | BOOST_CHECK(global_int == 5); |
301 | |
302 | // Construction of a function from a function containing a functor |
303 | func_void_type v4(v3); |
304 | |
305 | // Invocation of a function |
306 | global_int = 0; |
307 | v4(); |
308 | BOOST_CHECK(global_int == 5); |
309 | |
310 | // clear() method |
311 | v4.clear(); |
312 | BOOST_CHECK(v4.empty()); |
313 | |
314 | // Assignment to an empty function |
315 | v4 = three; |
316 | BOOST_CHECK(!v4.empty()); |
317 | |
318 | // Invocation |
319 | global_int = 0; |
320 | v4(); |
321 | BOOST_CHECK(global_int == 3); |
322 | |
323 | // Assignment to a non-empty function |
324 | v4 = five; |
325 | |
326 | // Invocation |
327 | global_int = 0; |
328 | v4(); |
329 | BOOST_CHECK(global_int == 5); |
330 | |
331 | // clear() |
332 | v4.clear(); |
333 | BOOST_CHECK(v4.empty()); |
334 | |
335 | // Assignment to an empty function from a free function |
336 | v4 = &write_five; |
337 | BOOST_CHECK(!v4.empty()); |
338 | |
339 | // Invocation |
340 | global_int = 0; |
341 | v4(); |
342 | BOOST_CHECK(global_int == 5); |
343 | |
344 | // Assignment to a non-empty function from a free function |
345 | v4 = &write_three; |
346 | BOOST_CHECK(!v4.empty()); |
347 | |
348 | // Invocation |
349 | global_int = 0; |
350 | v4(); |
351 | BOOST_CHECK(global_int == 3); |
352 | |
353 | // Assignment |
354 | v4 = five; |
355 | BOOST_CHECK(!v4.empty()); |
356 | |
357 | // Invocation |
358 | global_int = 0; |
359 | v4(); |
360 | BOOST_CHECK(global_int == 5); |
361 | |
362 | // Construction of a function from a functor |
363 | func_void_type v5(five); |
364 | |
365 | // Invocation of a function |
366 | global_int = 0; |
367 | v5(); |
368 | BOOST_CHECK(global_int == 5); |
369 | |
370 | // clear() method |
371 | v5.clear(); |
372 | BOOST_CHECK(v5.empty()); |
373 | |
374 | // Assignment to an empty function |
375 | v5 = three; |
376 | BOOST_CHECK(!v5.empty()); |
377 | |
378 | // Invocation |
379 | global_int = 0; |
380 | v5(); |
381 | BOOST_CHECK(global_int == 3); |
382 | |
383 | // Assignment to a non-empty function |
384 | v5 = five; |
385 | |
386 | // Invocation |
387 | global_int = 0; |
388 | v5(); |
389 | BOOST_CHECK(global_int == 5); |
390 | |
391 | // clear() |
392 | v5.clear(); |
393 | BOOST_CHECK(v5.empty()); |
394 | |
395 | // Assignment to an empty function from a free function |
396 | v5 = &write_five; |
397 | BOOST_CHECK(!v5.empty()); |
398 | |
399 | // Invocation |
400 | global_int = 0; |
401 | v5(); |
402 | BOOST_CHECK(global_int == 5); |
403 | |
404 | // Assignment to a non-empty function from a free function |
405 | v5 = &write_three; |
406 | BOOST_CHECK(!v5.empty()); |
407 | |
408 | // Invocation |
409 | global_int = 0; |
410 | v5(); |
411 | BOOST_CHECK(global_int == 3); |
412 | |
413 | // Assignment |
414 | v5 = five; |
415 | BOOST_CHECK(!v5.empty()); |
416 | |
417 | // Invocation |
418 | global_int = 0; |
419 | v5(); |
420 | BOOST_CHECK(global_int == 5); |
421 | |
422 | // Construction of a function from a function |
423 | func_void_type v6(&write_five); |
424 | |
425 | // Invocation of a function |
426 | global_int = 0; |
427 | v6(); |
428 | BOOST_CHECK(global_int == 5); |
429 | |
430 | // clear() method |
431 | v6.clear(); |
432 | BOOST_CHECK(v6.empty()); |
433 | |
434 | // Assignment to an empty function |
435 | v6 = three; |
436 | BOOST_CHECK(!v6.empty()); |
437 | |
438 | // Invocation |
439 | global_int = 0; |
440 | v6(); |
441 | BOOST_CHECK(global_int == 3); |
442 | |
443 | // Assignment to a non-empty function |
444 | v6 = five; |
445 | |
446 | // Invocation |
447 | global_int = 0; |
448 | v6(); |
449 | BOOST_CHECK(global_int == 5); |
450 | |
451 | // clear() |
452 | v6.clear(); |
453 | BOOST_CHECK(v6.empty()); |
454 | |
455 | // Assignment to an empty function from a free function |
456 | v6 = &write_five; |
457 | BOOST_CHECK(!v6.empty()); |
458 | |
459 | // Invocation |
460 | global_int = 0; |
461 | v6(); |
462 | BOOST_CHECK(global_int == 5); |
463 | |
464 | // Assignment to a non-empty function from a free function |
465 | v6 = &write_three; |
466 | BOOST_CHECK(!v6.empty()); |
467 | |
468 | // Invocation |
469 | global_int = 0; |
470 | v6(); |
471 | BOOST_CHECK(global_int == 3); |
472 | |
473 | // Assignment |
474 | v6 = five; |
475 | BOOST_CHECK(!v6.empty()); |
476 | |
477 | // Invocation |
478 | global_int = 0; |
479 | v6(); |
480 | BOOST_CHECK(global_int == 5); |
481 | |
482 | // Const vs. non-const |
483 | // Initialization for Borland C++ 5.5 |
484 | write_const_1_nonconst_2 one_or_two = write_const_1_nonconst_2(); |
485 | const function0<void> v7(one_or_two); |
486 | function0<void> v8(one_or_two); |
487 | |
488 | global_int = 0; |
489 | v7(); |
490 | BOOST_CHECK(global_int == 2); |
491 | |
492 | global_int = 0; |
493 | v8(); |
494 | BOOST_CHECK(global_int == 2); |
495 | |
496 | // Test construction from 0 and comparison to 0 |
497 | func_void_type v9(0); |
498 | BOOST_CHECK(v9 == 0); |
499 | # if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540 || defined(BOOST_STRICT_CONFIG) |
500 | BOOST_CHECK(0 == v9); |
501 | #else |
502 | BOOST_CHECK(v9.empty()); |
503 | #endif |
504 | |
505 | // Test return values |
506 | typedef function0<int> func_int_type; |
507 | // Initialization for Borland C++ 5.5 |
508 | generate_five_obj gen_five = generate_five_obj(); |
509 | generate_three_obj gen_three = generate_three_obj(); |
510 | func_int_type i0(gen_five); |
511 | |
512 | BOOST_CHECK(i0() == 5); |
513 | i0 = gen_three; |
514 | BOOST_CHECK(i0() == 3); |
515 | i0 = &generate_five; |
516 | BOOST_CHECK(i0() == 5); |
517 | i0 = &generate_three; |
518 | BOOST_CHECK(i0() == 3); |
519 | BOOST_CHECK(i0? true : false); |
520 | i0.clear(); |
521 | BOOST_CHECK(!i0? true : false); |
522 | |
523 | // Test return values with compatible types |
524 | typedef function0<long> func_long_type; |
525 | func_long_type i1(gen_five); |
526 | |
527 | BOOST_CHECK(i1() == 5); |
528 | i1 = gen_three; |
529 | BOOST_CHECK(i1() == 3); |
530 | i1 = &generate_five; |
531 | BOOST_CHECK(i1() == 5); |
532 | i1 = &generate_three; |
533 | BOOST_CHECK(i1() == 3); |
534 | BOOST_CHECK(i1? true : false); |
535 | i1.clear(); |
536 | BOOST_CHECK(!i1? true : false); |
537 | } |
538 | |
539 | static void |
540 | test_one_arg() |
541 | { |
542 | negate<int> neg = negate<int>(); // Initialization for Borland C++ 5.5 |
543 | |
544 | function1<int, int> f1(neg); |
545 | BOOST_CHECK(f1(5) == -5); |
546 | |
547 | function1<string, string> id(&identity_str); |
548 | BOOST_CHECK(id("str" ) == "str" ); |
549 | |
550 | function1<std::string, const char*> id2(&identity_str); |
551 | BOOST_CHECK(id2("foo" ) == "foo" ); |
552 | |
553 | add_to_obj add_to(5); |
554 | function1<int, int> f2(add_to); |
555 | BOOST_CHECK(f2(3) == 8); |
556 | |
557 | const function1<int, int> cf2(add_to); |
558 | BOOST_CHECK(cf2(3) == 8); |
559 | } |
560 | |
561 | static void |
562 | test_two_args() |
563 | { |
564 | function2<string, const string&, const string&> cat(&string_cat); |
565 | BOOST_CHECK(cat("str" , "ing" ) == "string" ); |
566 | |
567 | function2<int, short, short> sum(&sum_ints); |
568 | BOOST_CHECK(sum(2, 3) == 5); |
569 | } |
570 | |
571 | static void |
572 | test_emptiness() |
573 | { |
574 | function0<float> f1; |
575 | BOOST_CHECK(f1.empty()); |
576 | |
577 | function0<float> f2; |
578 | f2 = f1; |
579 | BOOST_CHECK(f2.empty()); |
580 | |
581 | function0<double> f3; |
582 | f3 = f2; |
583 | BOOST_CHECK(f3.empty()); |
584 | } |
585 | |
586 | struct X { |
587 | X(int v) : value(v) {} |
588 | |
589 | int twice() const { return 2*value; } |
590 | int plus(int v) { return value + v; } |
591 | |
592 | int value; |
593 | }; |
594 | |
595 | static void |
596 | test_member_functions() |
597 | { |
598 | |
599 | boost::function1<int, X*> f1(&X::twice); |
600 | |
601 | X one(1); |
602 | X five(5); |
603 | |
604 | BOOST_CHECK(f1(&one) == 2); |
605 | BOOST_CHECK(f1(&five) == 10); |
606 | |
607 | boost::function1<int, X*> f1_2; |
608 | f1_2 = &X::twice; |
609 | |
610 | BOOST_CHECK(f1_2(&one) == 2); |
611 | BOOST_CHECK(f1_2(&five) == 10); |
612 | |
613 | boost::function2<int, X&, int> f2(&X::plus); |
614 | BOOST_CHECK(f2(one, 3) == 4); |
615 | BOOST_CHECK(f2(five, 4) == 9); |
616 | } |
617 | |
618 | struct add_with_throw_on_copy { |
619 | int operator()(int x, int y) const { return x+y; } |
620 | |
621 | add_with_throw_on_copy() {} |
622 | |
623 | add_with_throw_on_copy(const add_with_throw_on_copy&) |
624 | { |
625 | throw std::runtime_error("But this CAN'T throw" ); |
626 | } |
627 | |
628 | add_with_throw_on_copy& operator=(const add_with_throw_on_copy&) |
629 | { |
630 | throw std::runtime_error("But this CAN'T throw" ); |
631 | } |
632 | }; |
633 | |
634 | static void |
635 | test_ref() |
636 | { |
637 | add_with_throw_on_copy atc; |
638 | try { |
639 | boost::function2<int, int, int> f(ref(t&: atc)); |
640 | BOOST_CHECK(f(1, 3) == 4); |
641 | } |
642 | catch(std::runtime_error const&) { |
643 | BOOST_ERROR("Nonthrowing constructor threw an exception" ); |
644 | } |
645 | } |
646 | |
647 | static unsigned construction_count = 0; |
648 | static unsigned destruction_count = 0; |
649 | |
650 | struct MySmallFunctor { |
651 | MySmallFunctor() { ++construction_count; } |
652 | MySmallFunctor(const MySmallFunctor &) { ++construction_count; } |
653 | ~MySmallFunctor() { ++destruction_count; } |
654 | int operator()() { return 0; } |
655 | }; |
656 | |
657 | struct MyLargeFunctor { |
658 | MyLargeFunctor() { ++construction_count; } |
659 | MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; } |
660 | ~MyLargeFunctor() { ++destruction_count; } |
661 | int operator()() { return 0; } |
662 | |
663 | float data[128]; |
664 | }; |
665 | |
666 | void test_construct_destroy_count() |
667 | { |
668 | { |
669 | boost::function0<int> f; |
670 | boost::function0<int> g; |
671 | f = MySmallFunctor(); |
672 | g = MySmallFunctor(); |
673 | f.swap(other&: g); |
674 | } |
675 | |
676 | // MySmallFunctor objects should be constructed as many times as |
677 | // they are destroyed. |
678 | BOOST_CHECK(construction_count == destruction_count); |
679 | |
680 | construction_count = 0; |
681 | destruction_count = 0; |
682 | { |
683 | boost::function0<int> f; |
684 | boost::function0<int> g; |
685 | f = MyLargeFunctor(); |
686 | g = MyLargeFunctor(); |
687 | f.swap(other&: g); |
688 | } |
689 | |
690 | // MyLargeFunctor objects should be constructed as many times as |
691 | // they are destroyed. |
692 | BOOST_CHECK(construction_count == destruction_count); |
693 | } |
694 | |
695 | int main() |
696 | { |
697 | test_zero_args(); |
698 | test_one_arg(); |
699 | test_two_args(); |
700 | test_emptiness(); |
701 | test_member_functions(); |
702 | test_ref(); |
703 | test_construct_destroy_count(); |
704 | return boost::report_errors(); |
705 | } |
706 | |