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