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 <string>
20#include <utility>
21
22#define BOOST_CHECK BOOST_TEST
23
24using boost::function;
25using std::string;
26
27int global_int;
28
29struct write_five_obj { void operator()() const { global_int = 5; } };
30struct write_three_obj { int operator()() const { global_int = 3; return 7; }};
31static void write_five() { global_int = 5; }
32static void write_three() { global_int = 3; }
33struct generate_five_obj { int operator()() const { return 5; } };
34struct generate_three_obj { int operator()() const { return 3; } };
35static int generate_five() { return 5; }
36static int generate_three() { return 3; }
37static string identity_str(const string& s) { return s; }
38static string string_cat(const string& s1, const string& s2) { return s1+s2; }
39static int sum_ints(int x, int y) { return x+y; }
40
41struct write_const_1_nonconst_2
42{
43 void operator()() { global_int = 2; }
44 void operator()() const { global_int = 1; }
45};
46
47struct add_to_obj
48{
49 add_to_obj(int v) : value(v) {}
50
51 int operator()(int x) const { return value + x; }
52
53 int value;
54};
55
56static void
57test_zero_args()
58{
59 typedef function<void ()> func_void_type;
60
61 write_five_obj five;
62 write_three_obj three;
63
64 // Default construction
65 func_void_type v1;
66 BOOST_CHECK(v1.empty());
67
68 // Assignment to an empty function
69 v1 = five;
70 BOOST_CHECK(v1 != 0);
71
72 // Invocation of a function
73 global_int = 0;
74 v1();
75 BOOST_CHECK(global_int == 5);
76
77 // clear() method
78 v1.clear();
79 BOOST_CHECK(v1 == 0);
80
81 // Assignment to an empty function
82 v1 = three;
83 BOOST_CHECK(!v1.empty());
84
85 // Invocation and self-assignment
86 global_int = 0;
87 v1 = v1;
88 v1();
89 BOOST_CHECK(global_int == 3);
90
91 // Assignment to a non-empty function
92 v1 = five;
93
94 // Invocation and self-assignment
95 global_int = 0;
96 v1 = (v1);
97 v1();
98 BOOST_CHECK(global_int == 5);
99
100 // clear
101 v1 = 0;
102 BOOST_CHECK(0 == v1);
103
104 // Assignment to an empty function from a free function
105 v1 = BOOST_FUNCTION_TARGET_FIX(&) write_five;
106 BOOST_CHECK(0 != v1);
107
108 // Invocation
109 global_int = 0;
110 v1();
111 BOOST_CHECK(global_int == 5);
112
113 // Assignment to a non-empty function from a free function
114 v1 = BOOST_FUNCTION_TARGET_FIX(&) write_three;
115 BOOST_CHECK(!v1.empty());
116
117 // Invocation
118 global_int = 0;
119 v1();
120 BOOST_CHECK(global_int == 3);
121
122 // Assignment
123 v1 = five;
124 BOOST_CHECK(!v1.empty());
125
126 // Invocation
127 global_int = 0;
128 v1();
129 BOOST_CHECK(global_int == 5);
130
131 // Assignment to a non-empty function from a free function
132 v1 = &write_three;
133 BOOST_CHECK(!v1.empty());
134
135 // Invocation
136 global_int = 0;
137 v1();
138 BOOST_CHECK(global_int == 3);
139
140 // Construction from another function (that is empty)
141 v1.clear();
142 func_void_type v2(v1);
143 BOOST_CHECK(!v2? true : false);
144
145 // Assignment to an empty function
146 v2 = three;
147 BOOST_CHECK(!v2.empty());
148
149 // Invocation
150 global_int = 0;
151 v2();
152 BOOST_CHECK(global_int == 3);
153
154 // Assignment to a non-empty function
155 v2 = (five);
156
157 // Invocation
158 global_int = 0;
159 v2();
160 BOOST_CHECK(global_int == 5);
161
162 v2.clear();
163 BOOST_CHECK(v2.empty());
164
165 // Assignment to an empty function from a free function
166 v2 = (BOOST_FUNCTION_TARGET_FIX(&) write_five);
167 BOOST_CHECK(v2? true : false);
168
169 // Invocation
170 global_int = 0;
171 v2();
172 BOOST_CHECK(global_int == 5);
173
174 // Assignment to a non-empty function from a free function
175 v2 = BOOST_FUNCTION_TARGET_FIX(&) write_three;
176 BOOST_CHECK(!v2.empty());
177
178 // Invocation
179 global_int = 0;
180 v2();
181 BOOST_CHECK(global_int == 3);
182
183 // Swapping
184 v1 = five;
185 swap(f1&: v1, f2&: v2);
186 v2();
187 BOOST_CHECK(global_int == 5);
188 v1();
189 BOOST_CHECK(global_int == 3);
190 swap(f1&: v1, f2&: v2);
191 v1.clear();
192
193 // Assignment
194 v2 = five;
195 BOOST_CHECK(!v2.empty());
196
197 // Invocation
198 global_int = 0;
199 v2();
200 BOOST_CHECK(global_int == 5);
201
202 // Assignment to a non-empty function from a free function
203 v2 = &write_three;
204 BOOST_CHECK(!v2.empty());
205
206 // Invocation
207 global_int = 0;
208 v2();
209 BOOST_CHECK(global_int == 3);
210
211 // Assignment to a function from an empty function
212 v2 = v1;
213 BOOST_CHECK(v2.empty());
214
215 // Assignment to a function from a function with a functor
216 v1 = three;
217 v2 = v1;
218 BOOST_CHECK(!v1.empty());
219 BOOST_CHECK(!v2.empty());
220
221 // Invocation
222 global_int = 0;
223 v1();
224 BOOST_CHECK(global_int == 3);
225 global_int = 0;
226 v2();
227 BOOST_CHECK(global_int == 3);
228
229 // Assign to a function from a function with a function
230 v2 = BOOST_FUNCTION_TARGET_FIX(&) write_five;
231 v1 = v2;
232 BOOST_CHECK(!v1.empty());
233 BOOST_CHECK(!v2.empty());
234 global_int = 0;
235 v1();
236 BOOST_CHECK(global_int == 5);
237 global_int = 0;
238 v2();
239 BOOST_CHECK(global_int == 5);
240
241 // Construct a function given another function containing a function
242 func_void_type v3(v1);
243
244 // Invocation of a function
245 global_int = 0;
246 v3();
247 BOOST_CHECK(global_int == 5);
248
249 // clear() method
250 v3.clear();
251 BOOST_CHECK(!v3? true : false);
252
253 // Assignment to an empty function
254 v3 = three;
255 BOOST_CHECK(!v3.empty());
256
257 // Invocation
258 global_int = 0;
259 v3();
260 BOOST_CHECK(global_int == 3);
261
262 // Assignment to a non-empty function
263 v3 = five;
264
265 // Invocation
266 global_int = 0;
267 v3();
268 BOOST_CHECK(global_int == 5);
269
270 // clear()
271 v3.clear();
272 BOOST_CHECK(v3.empty());
273
274 // Assignment to an empty function from a free function
275 v3 = &write_five;
276 BOOST_CHECK(!v3.empty());
277
278 // Invocation
279 global_int = 0;
280 v3();
281 BOOST_CHECK(global_int == 5);
282
283 // Assignment to a non-empty function from a free function
284 v3 = &write_three;
285 BOOST_CHECK(!v3.empty());
286
287 // Invocation
288 global_int = 0;
289 v3();
290 BOOST_CHECK(global_int == 3);
291
292 // Assignment
293 v3 = five;
294 BOOST_CHECK(!v3.empty());
295
296 // Invocation
297 global_int = 0;
298 v3();
299 BOOST_CHECK(global_int == 5);
300
301 // Construction of a function from a function containing a functor
302 func_void_type v4(v3);
303
304 // Invocation of a function
305 global_int = 0;
306 v4();
307 BOOST_CHECK(global_int == 5);
308
309 // clear() method
310 v4.clear();
311 BOOST_CHECK(v4.empty());
312
313 // Assignment to an empty function
314 v4 = three;
315 BOOST_CHECK(!v4.empty());
316
317 // Invocation
318 global_int = 0;
319 v4();
320 BOOST_CHECK(global_int == 3);
321
322 // Assignment to a non-empty function
323 v4 = five;
324
325 // Invocation
326 global_int = 0;
327 v4();
328 BOOST_CHECK(global_int == 5);
329
330 // clear()
331 v4.clear();
332 BOOST_CHECK(v4.empty());
333
334 // Assignment to an empty function from a free function
335 v4 = &write_five;
336 BOOST_CHECK(!v4.empty());
337
338 // Invocation
339 global_int = 0;
340 v4();
341 BOOST_CHECK(global_int == 5);
342
343 // Assignment to a non-empty function from a free function
344 v4 = &write_three;
345 BOOST_CHECK(!v4.empty());
346
347 // Invocation
348 global_int = 0;
349 v4();
350 BOOST_CHECK(global_int == 3);
351
352 // Assignment
353 v4 = five;
354 BOOST_CHECK(!v4.empty());
355
356 // Invocation
357 global_int = 0;
358 v4();
359 BOOST_CHECK(global_int == 5);
360
361 // Construction of a function from a functor
362 func_void_type v5(five);
363
364 // Invocation of a function
365 global_int = 0;
366 v5();
367 BOOST_CHECK(global_int == 5);
368
369 // clear() method
370 v5.clear();
371 BOOST_CHECK(v5.empty());
372
373 // Assignment to an empty function
374 v5 = three;
375 BOOST_CHECK(!v5.empty());
376
377 // Invocation
378 global_int = 0;
379 v5();
380 BOOST_CHECK(global_int == 3);
381
382 // Assignment to a non-empty function
383 v5 = five;
384
385 // Invocation
386 global_int = 0;
387 v5();
388 BOOST_CHECK(global_int == 5);
389
390 // clear()
391 v5.clear();
392 BOOST_CHECK(v5.empty());
393
394 // Assignment to an empty function from a free function
395 v5 = &write_five;
396 BOOST_CHECK(!v5.empty());
397
398 // Invocation
399 global_int = 0;
400 v5();
401 BOOST_CHECK(global_int == 5);
402
403 // Assignment to a non-empty function from a free function
404 v5 = &write_three;
405 BOOST_CHECK(!v5.empty());
406
407 // Invocation
408 global_int = 0;
409 v5();
410 BOOST_CHECK(global_int == 3);
411
412 // Assignment
413 v5 = five;
414 BOOST_CHECK(!v5.empty());
415
416 // Invocation
417 global_int = 0;
418 v5();
419 BOOST_CHECK(global_int == 5);
420
421 // Construction of a function from a function
422 func_void_type v6(&write_five);
423
424 // Invocation of a function
425 global_int = 0;
426 v6();
427 BOOST_CHECK(global_int == 5);
428
429 // clear() method
430 v6.clear();
431 BOOST_CHECK(v6.empty());
432
433 // Assignment to an empty function
434 v6 = three;
435 BOOST_CHECK(!v6.empty());
436
437 // Invocation
438 global_int = 0;
439 v6();
440 BOOST_CHECK(global_int == 3);
441
442 // Assignment to a non-empty function
443 v6 = five;
444
445 // Invocation
446 global_int = 0;
447 v6();
448 BOOST_CHECK(global_int == 5);
449
450 // clear()
451 v6.clear();
452 BOOST_CHECK(v6.empty());
453
454 // Assignment to an empty function from a free function
455 v6 = &write_five;
456 BOOST_CHECK(!v6.empty());
457
458 // Invocation
459 global_int = 0;
460 v6();
461 BOOST_CHECK(global_int == 5);
462
463 // Assignment to a non-empty function from a free function
464 v6 = &write_three;
465 BOOST_CHECK(!v6.empty());
466
467 // Invocation
468 global_int = 0;
469 v6();
470 BOOST_CHECK(global_int == 3);
471
472 // Assignment
473 v6 = five;
474 BOOST_CHECK(!v6.empty());
475
476 // Invocation
477 global_int = 0;
478 v6();
479 BOOST_CHECK(global_int == 5);
480
481 // Const vs. non-const
482 write_const_1_nonconst_2 one_or_two;
483 const function<void ()> v7(one_or_two);
484 function<void ()> v8(one_or_two);
485
486 global_int = 0;
487 v7();
488 BOOST_CHECK(global_int == 2);
489
490 global_int = 0;
491 v8();
492 BOOST_CHECK(global_int == 2);
493
494 // Test construction from 0 and comparison to 0
495 func_void_type v9(0);
496 BOOST_CHECK(v9 == 0);
497 BOOST_CHECK(0 == v9);
498
499 // Test return values
500 typedef function<int ()> func_int_type;
501 generate_five_obj gen_five;
502 generate_three_obj gen_three;
503
504 func_int_type i0(gen_five);
505
506 BOOST_CHECK(i0() == 5);
507 i0 = gen_three;
508 BOOST_CHECK(i0() == 3);
509 i0 = &generate_five;
510 BOOST_CHECK(i0() == 5);
511 i0 = &generate_three;
512 BOOST_CHECK(i0() == 3);
513 BOOST_CHECK(i0? true : false);
514 i0.clear();
515 BOOST_CHECK(!i0? true : false);
516
517 // Test return values with compatible types
518 typedef function<long ()> func_long_type;
519 func_long_type i1(gen_five);
520
521 BOOST_CHECK(i1() == 5);
522 i1 = gen_three;
523 BOOST_CHECK(i1() == 3);
524 i1 = &generate_five;
525 BOOST_CHECK(i1() == 5);
526 i1 = &generate_three;
527 BOOST_CHECK(i1() == 3);
528 BOOST_CHECK(i1? true : false);
529 i1.clear();
530 BOOST_CHECK(!i1? true : false);
531}
532
533static void
534test_one_arg()
535{
536 std::negate<int> neg;
537
538 function<int (int)> f1(neg);
539 BOOST_CHECK(f1(5) == -5);
540
541 function<string (string)> id(&identity_str);
542 BOOST_CHECK(id("str") == "str");
543
544 function<string (const char*)> id2(&identity_str);
545 BOOST_CHECK(id2("foo") == "foo");
546
547 add_to_obj add_to(5);
548 function<int (int)> f2(add_to);
549 BOOST_CHECK(f2(3) == 8);
550
551 const function<int (int)> cf2(add_to);
552 BOOST_CHECK(cf2(3) == 8);
553}
554
555static void
556test_two_args()
557{
558 function<string (const string&, const string&)> cat(&string_cat);
559 BOOST_CHECK(cat("str", "ing") == "string");
560
561 function<int (short, short)> sum(&sum_ints);
562 BOOST_CHECK(sum(2, 3) == 5);
563}
564
565static void
566test_emptiness()
567{
568 function<float ()> f1;
569 BOOST_CHECK(f1.empty());
570
571 function<float ()> f2;
572 f2 = f1;
573 BOOST_CHECK(f2.empty());
574
575 function<double ()> f3;
576 f3 = f2;
577 BOOST_CHECK(f3.empty());
578}
579
580struct X {
581 X(int v) : value(v) {}
582
583 int twice() const { return 2*value; }
584 int plus(int v) { return value + v; }
585
586 int value;
587};
588
589static void
590test_member_functions()
591{
592 boost::function<int (X*)> f1(&X::twice);
593
594 X one(1);
595 X five(5);
596
597 BOOST_CHECK(f1(&one) == 2);
598 BOOST_CHECK(f1(&five) == 10);
599
600 boost::function<int (X*)> f1_2;
601 f1_2 = &X::twice;
602
603 BOOST_CHECK(f1_2(&one) == 2);
604 BOOST_CHECK(f1_2(&five) == 10);
605
606 boost::function<int (X&, int)> f2(&X::plus);
607 BOOST_CHECK(f2(one, 3) == 4);
608 BOOST_CHECK(f2(five, 4) == 9);
609}
610
611struct add_with_throw_on_copy {
612 int operator()(int x, int y) const { return x+y; }
613
614 add_with_throw_on_copy() {}
615
616 add_with_throw_on_copy(const add_with_throw_on_copy&)
617 {
618 throw std::runtime_error("But this CAN'T throw");
619 }
620
621 add_with_throw_on_copy& operator=(const add_with_throw_on_copy&)
622 {
623 throw std::runtime_error("But this CAN'T throw");
624 }
625};
626
627static void
628test_ref()
629{
630 add_with_throw_on_copy atc;
631 try {
632 boost::function<int (int, int)> f(boost::ref(t&: atc));
633 BOOST_CHECK(f(1, 3) == 4);
634 }
635 catch(std::runtime_error const&) {
636 BOOST_ERROR("Nonthrowing constructor threw an exception");
637 }
638}
639
640#if BOOST_WORKAROUND(BOOST_GCC, >= 70000 && BOOST_GCC < 80000) && __cplusplus >= 201700
641
642// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81311
643#pragma message("Skipping test_empty_ref on g++ 7 -std=c++17")
644
645static void test_empty_ref()
646{
647}
648
649#else
650
651static void dummy() {}
652
653static void test_empty_ref()
654{
655 boost::function<void()> f1;
656 boost::function<void()> f2(boost::ref(t&: f1));
657
658 try {
659 f2();
660 BOOST_ERROR("Exception didn't throw for reference to empty function.");
661 }
662 catch(std::runtime_error const&) {}
663
664 f1 = dummy;
665
666 try {
667 f2();
668 }
669 catch(std::runtime_error const&) {
670 BOOST_ERROR("Error calling referenced function.");
671 }
672}
673
674#endif
675
676
677static void test_exception()
678{
679 boost::function<int (int, int)> f;
680 try {
681 f(5, 4);
682 BOOST_CHECK(false);
683 }
684 catch(boost::bad_function_call const&) {
685 // okay
686 }
687}
688
689typedef boost::function< void * (void * reader) > reader_type;
690typedef std::pair<int, reader_type> mapped_type;
691
692static void test_implicit()
693{
694 mapped_type m;
695 m = mapped_type();
696}
697
698static void test_call_obj(boost::function<int (int, int)> f)
699{
700 BOOST_CHECK(!f.empty());
701}
702
703static void test_call_cref(const boost::function<int (int, int)>& f)
704{
705 BOOST_CHECK(!f.empty());
706}
707
708static void test_call()
709{
710 test_call_obj(f: std::plus<int>());
711 test_call_cref(f: std::plus<int>());
712}
713
714struct big_aggregating_structure {
715 int disable_small_objects_optimizations[32];
716
717 big_aggregating_structure()
718 {
719 ++ global_int;
720 }
721
722 big_aggregating_structure(const big_aggregating_structure&)
723 {
724 ++ global_int;
725 }
726
727 ~big_aggregating_structure()
728 {
729 -- global_int;
730 }
731
732 void operator()()
733 {
734 ++ global_int;
735 }
736
737 void operator()(int)
738 {
739 ++ global_int;
740 }
741};
742
743template <class FunctionT>
744static void test_move_semantics()
745{
746 typedef FunctionT f1_type;
747
748 big_aggregating_structure obj;
749
750 f1_type f1 = obj;
751 global_int = 0;
752 f1();
753
754 BOOST_CHECK(!f1.empty());
755 BOOST_CHECK(global_int == 1);
756
757 // Testing rvalue constructors
758 f1_type f2(static_cast<f1_type&&>(f1));
759 BOOST_CHECK(f1.empty());
760 BOOST_CHECK(!f2.empty());
761 BOOST_CHECK(global_int == 1);
762 f2();
763 BOOST_CHECK(global_int == 2);
764
765 f1_type f3(static_cast<f1_type&&>(f2));
766 BOOST_CHECK(f1.empty());
767 BOOST_CHECK(f2.empty());
768 BOOST_CHECK(!f3.empty());
769 BOOST_CHECK(global_int == 2);
770 f3();
771 BOOST_CHECK(global_int == 3);
772
773 // Testing move assignment
774 f1_type f4;
775 BOOST_CHECK(f4.empty());
776 f4 = static_cast<f1_type&&>(f3);
777 BOOST_CHECK(f1.empty());
778 BOOST_CHECK(f2.empty());
779 BOOST_CHECK(f3.empty());
780 BOOST_CHECK(!f4.empty());
781 BOOST_CHECK(global_int == 3);
782 f4();
783 BOOST_CHECK(global_int == 4);
784
785 // Testing self move assignment
786 f4 = static_cast<f1_type&&>(f4);
787 BOOST_CHECK(!f4.empty());
788 BOOST_CHECK(global_int == 4);
789
790 // Testing, that no memory leaked when assigning to nonempty function
791 f4 = obj;
792 BOOST_CHECK(!f4.empty());
793 BOOST_CHECK(global_int == 4);
794 f1_type f5 = obj;
795 BOOST_CHECK(global_int == 5);
796 f4 = static_cast<f1_type&&>(f5);
797 BOOST_CHECK(global_int == 4);
798}
799
800int main()
801{
802 test_zero_args();
803 test_one_arg();
804 test_two_args();
805 test_emptiness();
806 test_member_functions();
807 test_ref();
808 test_empty_ref();
809 test_exception();
810 test_implicit();
811 test_call();
812 test_move_semantics<function<void()> >();
813 test_move_semantics<boost::function0<void> >();
814
815 return boost::report_errors();
816}
817

source code of boost/libs/function/test/function_test.cpp