In common.h, define func_lib for function objects. In configure.ac, define HAVE_STD_FUNCTION and HAVE_BOOST_FUNCTION. Include function headers in ndnboost.
diff --git a/libs/function/test/function_test.cpp b/libs/function/test/function_test.cpp
new file mode 100644
index 0000000..b1c7cb8
--- /dev/null
+++ b/libs/function/test/function_test.cpp
@@ -0,0 +1,798 @@
+// 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 <boost/test/minimal.hpp>
+#include <boost/function.hpp>
+#include <functional>
+#include <string>
+#include <utility>
+
+using ndnboost::function;
+using std::string;
+
+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 function<void ()> 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<void ()> v7(one_or_two);
+ function<void ()> 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<int ()> 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<long ()> 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()
+{
+ std::negate<int> neg;
+
+ function<int (int)> f1(neg);
+ BOOST_CHECK(f1(5) == -5);
+
+ function<string (string)> id(&identity_str);
+ BOOST_CHECK(id("str") == "str");
+
+ function<string (const char*)> id2(&identity_str);
+ BOOST_CHECK(id2("foo") == "foo");
+
+ add_to_obj add_to(5);
+ function<int (int)> f2(add_to);
+ BOOST_CHECK(f2(3) == 8);
+
+ const function<int (int)> cf2(add_to);
+ BOOST_CHECK(cf2(3) == 8);
+}
+
+static void
+test_two_args()
+{
+ function<string (const string&, const string&)> cat(&string_cat);
+ BOOST_CHECK(cat("str", "ing") == "string");
+
+ function<int (short, short)> sum(&sum_ints);
+ BOOST_CHECK(sum(2, 3) == 5);
+}
+
+static void
+test_emptiness()
+{
+ function<float ()> f1;
+ BOOST_CHECK(f1.empty());
+
+ function<float ()> f2;
+ f2 = f1;
+ BOOST_CHECK(f2.empty());
+
+ function<double ()> 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()
+{
+ ndnboost::function<int (X*)> f1(&X::twice);
+
+ X one(1);
+ X five(5);
+
+ BOOST_CHECK(f1(&one) == 2);
+ BOOST_CHECK(f1(&five) == 10);
+
+ ndnboost::function<int (X*)> f1_2;
+ f1_2 = &X::twice;
+
+ BOOST_CHECK(f1_2(&one) == 2);
+ BOOST_CHECK(f1_2(&five) == 10);
+
+ ndnboost::function<int (X&, int)> 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 {
+ ndnboost::function<int (int, int)> f(ndnboost::ref(atc));
+ BOOST_CHECK(f(1, 3) == 4);
+ }
+ catch(std::runtime_error e) {
+ BOOST_ERROR("Nonthrowing constructor threw an exception");
+ }
+}
+
+static void dummy() {}
+
+static void test_empty_ref()
+{
+ ndnboost::function<void()> f1;
+ ndnboost::function<void()> f2(ndnboost::ref(f1));
+
+ try {
+ f2();
+ BOOST_ERROR("Exception didn't throw for reference to empty function.");
+ }
+ catch(std::runtime_error e) {}
+
+ f1 = dummy;
+
+ try {
+ f2();
+ }
+ catch(std::runtime_error e) {
+ BOOST_ERROR("Error calling referenced function.");
+ }
+}
+
+
+static void test_exception()
+{
+ ndnboost::function<int (int, int)> f;
+ try {
+ f(5, 4);
+ BOOST_CHECK(false);
+ }
+ catch(ndnboost::bad_function_call) {
+ // okay
+ }
+}
+
+typedef ndnboost::function< void * (void * reader) > reader_type;
+typedef std::pair<int, reader_type> mapped_type;
+
+static void test_implicit()
+{
+ mapped_type m;
+ m = mapped_type();
+}
+
+static void test_call_obj(ndnboost::function<int (int, int)> f)
+{
+ BOOST_CHECK(!f.empty());
+}
+
+static void test_call_cref(const ndnboost::function<int (int, int)>& f)
+{
+ BOOST_CHECK(!f.empty());
+}
+
+static void test_call()
+{
+ test_call_obj(std::plus<int>());
+ test_call_cref(std::plus<int>());
+}
+
+struct big_aggregating_structure {
+ int disable_small_objects_optimizations[32];
+
+ big_aggregating_structure()
+ {
+ ++ global_int;
+ }
+
+ big_aggregating_structure(const big_aggregating_structure&)
+ {
+ ++ global_int;
+ }
+
+ ~big_aggregating_structure()
+ {
+ -- global_int;
+ }
+
+ void operator()()
+ {
+ ++ global_int;
+ }
+
+ void operator()(int)
+ {
+ ++ global_int;
+ }
+};
+
+template <class FunctionT>
+static void test_move_semantics()
+{
+ typedef FunctionT f1_type;
+
+ big_aggregating_structure obj;
+
+ f1_type f1 = obj;
+ global_int = 0;
+ f1();
+
+ BOOST_CHECK(!f1.empty());
+ BOOST_CHECK(global_int == 1);
+
+#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
+ // Testing rvalue constructors
+ f1_type f2(static_cast<f1_type&&>(f1));
+ BOOST_CHECK(f1.empty());
+ BOOST_CHECK(!f2.empty());
+ BOOST_CHECK(global_int == 1);
+ f2();
+ BOOST_CHECK(global_int == 2);
+
+ f1_type f3(static_cast<f1_type&&>(f2));
+ BOOST_CHECK(f1.empty());
+ BOOST_CHECK(f2.empty());
+ BOOST_CHECK(!f3.empty());
+ BOOST_CHECK(global_int == 2);
+ f3();
+ BOOST_CHECK(global_int == 3);
+
+ // Testing move assignment
+ f1_type f4;
+ BOOST_CHECK(f4.empty());
+ f4 = static_cast<f1_type&&>(f3);
+ BOOST_CHECK(f1.empty());
+ BOOST_CHECK(f2.empty());
+ BOOST_CHECK(f3.empty());
+ BOOST_CHECK(!f4.empty());
+ BOOST_CHECK(global_int == 3);
+ f4();
+ BOOST_CHECK(global_int == 4);
+
+ // Testing self move assignment
+ f4 = static_cast<f1_type&&>(f4);
+ BOOST_CHECK(!f4.empty());
+ BOOST_CHECK(global_int == 4);
+
+ // Testing, that no memory leaked when assigning to nonempty function
+ f4 = obj;
+ BOOST_CHECK(!f4.empty());
+ BOOST_CHECK(global_int == 4);
+ f1_type f5 = obj;
+ BOOST_CHECK(global_int == 5);
+ f4 = static_cast<f1_type&&>(f5);
+ BOOST_CHECK(global_int == 4);
+
+#endif
+}
+
+int test_main(int, char* [])
+{
+ test_zero_args();
+ test_one_arg();
+ test_two_args();
+ test_emptiness();
+ test_member_functions();
+ test_ref();
+ test_empty_ref();
+ test_exception();
+ test_implicit();
+ test_call();
+ test_move_semantics<function<void()> >();
+ test_move_semantics<ndnboost::function0<void> >();
+
+ return 0;
+}