// Boost.Function library // Copyright Douglas Gregor 2001-2003. Use, modification and // distribution is subject to the Boost Software License, Version // 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // For more information, see http://www.boost.org #include #include #include #include #include #define BOOST_CHECK BOOST_TEST using namespace boost; using std::string; using std::negate; int global_int; struct write_five_obj { void operator()() const { global_int = 5; } }; struct write_three_obj { int operator()() const { global_int = 3; return 7; }}; static void write_five() { global_int = 5; } static void write_three() { global_int = 3; } struct generate_five_obj { int operator()() const { return 5; } }; struct generate_three_obj { int operator()() const { return 3; } }; static int generate_five() { return 5; } static int generate_three() { return 3; } static string identity_str(const string& s) { return s; } static string string_cat(const string& s1, const string& s2) { return s1+s2; } static int sum_ints(int x, int y) { return x+y; } struct write_const_1_nonconst_2 { void operator()() { global_int = 2; } void operator()() const { global_int = 1; } }; struct add_to_obj { add_to_obj(int v) : value(v) {} int operator()(int x) const { return value + x; } int value; }; static void test_zero_args() { typedef function0 func_void_type; write_five_obj five = write_five_obj(); // Initialization for Borland C++ 5.5 write_three_obj three = write_three_obj(); // Ditto // Default construction func_void_type v1; BOOST_CHECK(v1.empty()); // Assignment to an empty function v1 = five; BOOST_CHECK(!v1.empty()); // Invocation of a function global_int = 0; v1(); BOOST_CHECK(global_int == 5); // clear() method v1.clear(); BOOST_CHECK(!v1); // Assignment to an empty function v1 = three; BOOST_CHECK(!v1.empty()); // Invocation and self-assignment global_int = 0; v1 = v1; v1(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v1 = five; // Invocation and self-assignment global_int = 0; v1 = (v1); v1(); BOOST_CHECK(global_int == 5); // clear v1 = 0; BOOST_CHECK(v1.empty()); // Assignment to an empty function from a free function v1 = &write_five; BOOST_CHECK(!v1.empty()); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v1 = &write_three; BOOST_CHECK(!v1.empty()); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 3); // Assignment v1 = five; BOOST_CHECK(!v1.empty()); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v1 = write_three; BOOST_CHECK(!v1.empty()); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 3); // Construction from another function (that is empty) v1.clear(); func_void_type v2(v1); BOOST_CHECK(!v2? true : false); // Assignment to an empty function v2 = three; BOOST_CHECK(!v2.empty()); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v2 = (five); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 5); v2.clear(); BOOST_CHECK(v2.empty()); // Assignment to an empty function from a free function v2 = (&write_five); BOOST_CHECK(v2? true : false); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v2 = &write_three; BOOST_CHECK(!v2.empty()); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 3); // Swapping v1 = five; swap(v1, v2); v2(); BOOST_CHECK(global_int == 5); v1(); BOOST_CHECK(global_int == 3); swap(v1, v2); v1.clear(); // Assignment v2 = five; BOOST_CHECK(!v2.empty()); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v2 = &write_three; BOOST_CHECK(!v2.empty()); // Invocation global_int = 0; v2(); BOOST_CHECK(global_int == 3); // Assignment to a function from an empty function v2 = v1; BOOST_CHECK(v2.empty()); // Assignment to a function from a function with a functor v1 = three; v2 = v1; BOOST_CHECK(!v1.empty()); BOOST_CHECK(!v2.empty()); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 3); global_int = 0; v2(); BOOST_CHECK(global_int == 3); // Assign to a function from a function with a function v2 = &write_five; v1 = v2; BOOST_CHECK(!v1.empty()); BOOST_CHECK(!v2.empty()); global_int = 0; v1(); BOOST_CHECK(global_int == 5); global_int = 0; v2(); BOOST_CHECK(global_int == 5); // Construct a function given another function containing a function func_void_type v3(v1); // Invocation of a function global_int = 0; v3(); BOOST_CHECK(global_int == 5); // clear() method v3.clear(); BOOST_CHECK(!v3? true : false); // Assignment to an empty function v3 = three; BOOST_CHECK(!v3.empty()); // Invocation global_int = 0; v3(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v3 = five; // Invocation global_int = 0; v3(); BOOST_CHECK(global_int == 5); // clear() v3.clear(); BOOST_CHECK(v3.empty()); // Assignment to an empty function from a free function v3 = &write_five; BOOST_CHECK(!v3.empty()); // Invocation global_int = 0; v3(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v3 = &write_three; BOOST_CHECK(!v3.empty()); // Invocation global_int = 0; v3(); BOOST_CHECK(global_int == 3); // Assignment v3 = five; BOOST_CHECK(!v3.empty()); // Invocation global_int = 0; v3(); BOOST_CHECK(global_int == 5); // Construction of a function from a function containing a functor func_void_type v4(v3); // Invocation of a function global_int = 0; v4(); BOOST_CHECK(global_int == 5); // clear() method v4.clear(); BOOST_CHECK(v4.empty()); // Assignment to an empty function v4 = three; BOOST_CHECK(!v4.empty()); // Invocation global_int = 0; v4(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v4 = five; // Invocation global_int = 0; v4(); BOOST_CHECK(global_int == 5); // clear() v4.clear(); BOOST_CHECK(v4.empty()); // Assignment to an empty function from a free function v4 = &write_five; BOOST_CHECK(!v4.empty()); // Invocation global_int = 0; v4(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v4 = &write_three; BOOST_CHECK(!v4.empty()); // Invocation global_int = 0; v4(); BOOST_CHECK(global_int == 3); // Assignment v4 = five; BOOST_CHECK(!v4.empty()); // Invocation global_int = 0; v4(); BOOST_CHECK(global_int == 5); // Construction of a function from a functor func_void_type v5(five); // Invocation of a function global_int = 0; v5(); BOOST_CHECK(global_int == 5); // clear() method v5.clear(); BOOST_CHECK(v5.empty()); // Assignment to an empty function v5 = three; BOOST_CHECK(!v5.empty()); // Invocation global_int = 0; v5(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v5 = five; // Invocation global_int = 0; v5(); BOOST_CHECK(global_int == 5); // clear() v5.clear(); BOOST_CHECK(v5.empty()); // Assignment to an empty function from a free function v5 = &write_five; BOOST_CHECK(!v5.empty()); // Invocation global_int = 0; v5(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v5 = &write_three; BOOST_CHECK(!v5.empty()); // Invocation global_int = 0; v5(); BOOST_CHECK(global_int == 3); // Assignment v5 = five; BOOST_CHECK(!v5.empty()); // Invocation global_int = 0; v5(); BOOST_CHECK(global_int == 5); // Construction of a function from a function func_void_type v6(&write_five); // Invocation of a function global_int = 0; v6(); BOOST_CHECK(global_int == 5); // clear() method v6.clear(); BOOST_CHECK(v6.empty()); // Assignment to an empty function v6 = three; BOOST_CHECK(!v6.empty()); // Invocation global_int = 0; v6(); BOOST_CHECK(global_int == 3); // Assignment to a non-empty function v6 = five; // Invocation global_int = 0; v6(); BOOST_CHECK(global_int == 5); // clear() v6.clear(); BOOST_CHECK(v6.empty()); // Assignment to an empty function from a free function v6 = &write_five; BOOST_CHECK(!v6.empty()); // Invocation global_int = 0; v6(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v6 = &write_three; BOOST_CHECK(!v6.empty()); // Invocation global_int = 0; v6(); BOOST_CHECK(global_int == 3); // Assignment v6 = five; BOOST_CHECK(!v6.empty()); // Invocation global_int = 0; v6(); BOOST_CHECK(global_int == 5); // Const vs. non-const // Initialization for Borland C++ 5.5 write_const_1_nonconst_2 one_or_two = write_const_1_nonconst_2(); const function0 v7(one_or_two); function0 v8(one_or_two); global_int = 0; v7(); BOOST_CHECK(global_int == 2); global_int = 0; v8(); BOOST_CHECK(global_int == 2); // Test construction from 0 and comparison to 0 func_void_type v9(0); BOOST_CHECK(v9 == 0); # if !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540 || defined(BOOST_STRICT_CONFIG) BOOST_CHECK(0 == v9); #else BOOST_CHECK(v9.empty()); #endif // Test return values typedef function0 func_int_type; // Initialization for Borland C++ 5.5 generate_five_obj gen_five = generate_five_obj(); generate_three_obj gen_three = generate_three_obj(); func_int_type i0(gen_five); BOOST_CHECK(i0() == 5); i0 = gen_three; BOOST_CHECK(i0() == 3); i0 = &generate_five; BOOST_CHECK(i0() == 5); i0 = &generate_three; BOOST_CHECK(i0() == 3); BOOST_CHECK(i0? true : false); i0.clear(); BOOST_CHECK(!i0? true : false); // Test return values with compatible types typedef function0 func_long_type; func_long_type i1(gen_five); BOOST_CHECK(i1() == 5); i1 = gen_three; BOOST_CHECK(i1() == 3); i1 = &generate_five; BOOST_CHECK(i1() == 5); i1 = &generate_three; BOOST_CHECK(i1() == 3); BOOST_CHECK(i1? true : false); i1.clear(); BOOST_CHECK(!i1? true : false); } static void test_one_arg() { negate neg = negate(); // Initialization for Borland C++ 5.5 function1 f1(neg); BOOST_CHECK(f1(5) == -5); function1 id(&identity_str); BOOST_CHECK(id("str") == "str"); function1 id2(&identity_str); BOOST_CHECK(id2("foo") == "foo"); add_to_obj add_to(5); function1 f2(add_to); BOOST_CHECK(f2(3) == 8); const function1 cf2(add_to); BOOST_CHECK(cf2(3) == 8); } static void test_two_args() { function2 cat(&string_cat); BOOST_CHECK(cat("str", "ing") == "string"); function2 sum(&sum_ints); BOOST_CHECK(sum(2, 3) == 5); } static void test_emptiness() { function0 f1; BOOST_CHECK(f1.empty()); function0 f2; f2 = f1; BOOST_CHECK(f2.empty()); function0 f3; f3 = f2; BOOST_CHECK(f3.empty()); } struct X { X(int v) : value(v) {} int twice() const { return 2*value; } int plus(int v) { return value + v; } int value; }; static void test_member_functions() { boost::function1 f1(&X::twice); X one(1); X five(5); BOOST_CHECK(f1(&one) == 2); BOOST_CHECK(f1(&five) == 10); boost::function1 f1_2; f1_2 = &X::twice; BOOST_CHECK(f1_2(&one) == 2); BOOST_CHECK(f1_2(&five) == 10); boost::function2 f2(&X::plus); BOOST_CHECK(f2(one, 3) == 4); BOOST_CHECK(f2(five, 4) == 9); } struct add_with_throw_on_copy { int operator()(int x, int y) const { return x+y; } add_with_throw_on_copy() {} add_with_throw_on_copy(const add_with_throw_on_copy&) { throw std::runtime_error("But this CAN'T throw"); } add_with_throw_on_copy& operator=(const add_with_throw_on_copy&) { throw std::runtime_error("But this CAN'T throw"); } }; static void test_ref() { add_with_throw_on_copy atc; try { boost::function2 f(ref(atc)); BOOST_CHECK(f(1, 3) == 4); } catch(std::runtime_error const&) { BOOST_ERROR("Nonthrowing constructor threw an exception"); } } static unsigned construction_count = 0; static unsigned destruction_count = 0; struct MySmallFunctor { MySmallFunctor() { ++construction_count; } MySmallFunctor(const MySmallFunctor &) { ++construction_count; } ~MySmallFunctor() { ++destruction_count; } int operator()() { return 0; } }; struct MyLargeFunctor { MyLargeFunctor() { ++construction_count; } MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; } ~MyLargeFunctor() { ++destruction_count; } int operator()() { return 0; } float data[128]; }; void test_construct_destroy_count() { { boost::function0 f; boost::function0 g; f = MySmallFunctor(); g = MySmallFunctor(); f.swap(g); } // MySmallFunctor objects should be constructed as many times as // they are destroyed. BOOST_CHECK(construction_count == destruction_count); construction_count = 0; destruction_count = 0; { boost::function0 f; boost::function0 g; f = MyLargeFunctor(); g = MyLargeFunctor(); f.swap(g); } // MyLargeFunctor objects should be constructed as many times as // they are destroyed. BOOST_CHECK(construction_count == destruction_count); } int main() { test_zero_args(); test_one_arg(); test_two_args(); test_emptiness(); test_member_functions(); test_ref(); test_construct_destroy_count(); return boost::report_errors(); }