// 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 // $Id$ #include #include #include #include //*********************************************************** //#include #include #define BOOST_CHECK(exp) \ ( (exp) \ ? static_cast(0) \ : report_error(#exp,__FILE__,__LINE__) ) #define BOOST_ERROR(x) std::cout << x << "\n" inline void report_error( const char* msg, const char* file, int line, bool is_msg = false ) { std::cout << file << "(" << line << "): "; if( is_msg ) std::cout << msg; else std::cout << "test " << msg << " failed"; std::cout << std::endl; } //*********************************************************** #define TEST_LOKI_FUNCTION #ifndef TEST_LOKI_FUNCTION #include using namespace boost; #else #define BOOST_FUNCTION_TARGET_FIX(x) x #define LOKI_CLASS_LEVEL_THREADING // disable to see "static instantiation order fiasco" crash #define LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT #include using namespace Loki; #define function Function #endif #ifndef LOKI_FUNCTORS_ARE_COMPARABLE using namespace std; int global_int; struct write_five_obj{void operator()() const {global_int = 5;}}; #ifndef TEST_LOKI_FUNCTION struct write_three_obj{int operator()() const {global_int = 3; return 7;}}; #else struct write_three_obj{void operator()() const {global_int = 3;}}; #endif 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; }; function static_func(write_five); static void test_static_function() { static_func(); } static void test_zero_args() { typedef function func_void_type; write_five_obj five; write_three_obj three; // Default construction func_void_type v1; BOOST_CHECK(v1.empty()); // Assignment to an empty function v1 = five; BOOST_CHECK(v1 != 0); // Invocation of a function global_int = 0; v1(); BOOST_CHECK(global_int == 5); // clear() method v1.clear(); BOOST_CHECK(v1 == 0); // 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(0 == v1); // Assignment to an empty function from a free function v1 = BOOST_FUNCTION_TARGET_FIX(&) write_five; BOOST_CHECK(0 != v1); // Invocation global_int = 0; v1(); BOOST_CHECK(global_int == 5); // Assignment to a non-empty function from a free function v1 = BOOST_FUNCTION_TARGET_FIX(&) 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 = (BOOST_FUNCTION_TARGET_FIX(&) 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 = BOOST_FUNCTION_TARGET_FIX(&) 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 = BOOST_FUNCTION_TARGET_FIX(&) 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 write_const_1_nonconst_2 one_or_two; const function v7(one_or_two); function 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); BOOST_CHECK(0 == v9); // Test return values typedef function func_int_type; generate_five_obj gen_five; generate_three_obj gen_three; 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 function 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; function f1(neg); BOOST_CHECK(f1(5) == -5); function id(&identity_str); BOOST_CHECK(id("str") == "str"); function id2(&identity_str); BOOST_CHECK(id2("foo") == "foo"); add_to_obj add_to(5); function f2(add_to); BOOST_CHECK(f2(3) == 8); const function cf2(add_to); BOOST_CHECK(cf2(3) == 8); } static void test_two_args() { function cat(&string_cat); BOOST_CHECK(cat("str", "ing") == "string"); function sum(&sum_ints); BOOST_CHECK(sum(2, 3) == 5); } static void test_emptiness() { function f1; BOOST_CHECK(f1.empty()); function f2; f2 = f1; BOOST_CHECK(f2.empty()); function 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() { #ifndef TEST_LOKI_FUNCTION boost::function f1(&X::twice); X one(1); X five(5); BOOST_CHECK(f1(&one) == 2); BOOST_CHECK(f1(&five) == 10); #else X one(1); X five(5); Loki::Function f1(&one,&X::twice); BOOST_CHECK(f1() == 2); f1 = Loki::Function(&five,&X::twice); BOOST_CHECK(f1() == 10); #endif #ifndef TEST_LOKI_FUNCTION boost::function f1_2; f1_2 = &X::twice; BOOST_CHECK(f1_2(&one) == 2); BOOST_CHECK(f1_2(&five) == 10); #else Loki::Function f1_2(&one,&X::twice); BOOST_CHECK(f1_2() == 2); f1_2 = Loki::function(&five,&X::twice); BOOST_CHECK(f1_2() == 10); #endif #ifndef TEST_LOKI_FUNCTION boost::function f2(&X::plus); BOOST_CHECK(f2(one, 3) == 4); BOOST_CHECK(f2(five, 4) == 9); #else Loki::Function f2(&one,&X::plus); BOOST_CHECK(f2(3) == 4); f2 = Loki::Function(&five,&X::plus); BOOST_CHECK(f2(4) == 9); #endif } 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 runtime_error("But this CAN'T throw"); } add_with_throw_on_copy& operator=(const add_with_throw_on_copy&) { throw runtime_error("But this CAN'T throw"); } }; static void test_ref() { add_with_throw_on_copy atc; try { #ifndef TEST_LOKI_FUNCTION boost::function f(ref(atc)); BOOST_CHECK(f(1, 3) == 4); #else //TODO: implement Loki::Ref //Loki::Function f(Loki::ref(atc)); //BOOST_CHECK(f(1, 3) == 4); #endif } catch(runtime_error e) { #ifndef TEST_LOKI_FUNCTION BOOST_ERROR("Nonthrowing constructor threw an exception"); #endif } } static void test_exception() { function f; try { f(5, 4); BOOST_CHECK(false); } catch(bad_function_call) { // okay } } typedef function< void * (void * reader) > reader_type; typedef std::pair mapped_type; static void test_implicit() { mapped_type m; m = mapped_type(); } static void test_call_obj(function f) { assert(!f.empty()); } static void test_call_cref(const function& f) { assert(!f.empty()); } static void test_call() { test_call_obj(std::plus()); test_call_cref(std::plus()); } int main() { test_static_function(); test_zero_args(); test_one_arg(); test_two_args(); test_emptiness(); test_member_functions(); test_ref(); test_exception(); test_implicit(); test_call(); #if defined(__BORLANDC__) || defined(_MSC_VER) system("PAUSE"); #endif return 0; } #else // #ifndef LOKI_FUNCTORS_ARE_COMPARABLE int main() { return 0; } #endif