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