diff --git a/doc/tutorial.xml b/doc/tutorial.xml index d369392..1e2eba8 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -35,12 +35,12 @@ form to use for your compiler. - GNU C++ 2.95.x, 3.0.x, 3.1.x + GNU C++ 2.95.x, 3.0.x and later verseions Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 Compaq's cxx 6.2 - Microsoft Visual C++ 7.1 + Microsoft Visual C++ 7.1 and later versions diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 0628ae7..c4663c3 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -42,7 +45,7 @@ #endif // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info. -#ifdef BOOST_NO_EXCEPTION_STD_NAMESPACE +#ifdef BOOST_NO_STD_TYPEINFO // Embedded VC++ does not have type_info in namespace std # define BOOST_FUNCTION_STD_NS #else @@ -259,6 +262,12 @@ namespace boost { A(a) { } + + functor_wrapper(const functor_wrapper& f) : + F(static_cast(f)), + A(static_cast(f)) + { + } }; /** @@ -625,7 +634,7 @@ public: if (!vtable) return typeid(void); detail::function::function_buffer type; - vtable->manager(functor, type, detail::function::get_functor_type_tag); + get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); return *type.type.type; } @@ -638,7 +647,7 @@ public: type_result.type.type = &typeid(Functor); type_result.type.const_qualified = is_const::value; type_result.type.volatile_qualified = is_volatile::value; - vtable->manager(functor, type_result, + get_vtable()->manager(functor, type_result, detail::function::check_functor_type_tag); return static_cast(type_result.obj_ptr); } @@ -656,7 +665,7 @@ public: type_result.type.type = &typeid(Functor); type_result.type.const_qualified = true; type_result.type.volatile_qualified = is_volatile::value; - vtable->manager(functor, type_result, + get_vtable()->manager(functor, type_result, detail::function::check_functor_type_tag); // GCC 2.95.3 gets the CV qualifiers wrong here, so we // can't do the static_cast that we should do. @@ -702,6 +711,15 @@ public: #endif public: // should be protected, but GCC 2.95.3 will fail to allow access + detail::function::vtable_base* get_vtable() const { + return reinterpret_cast( + reinterpret_cast(vtable) & ~(std::size_t)0x01); + } + + bool has_trivial_copy_and_destroy() const { + return reinterpret_cast(vtable) & 0x01; + } + detail::function::vtable_base* vtable; mutable detail::function::function_buffer functor; }; diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp index d2f713a..fb318c9 100644 --- a/include/boost/function/function_fwd.hpp +++ b/include/boost/function/function_fwd.hpp @@ -21,7 +21,7 @@ namespace boost { namespace python { namespace objects { #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) + || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX #endif diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 5015e1d..6a99109 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -11,6 +11,7 @@ // Note: this header is a header template and must NOT have multiple-inclusion // protection. #include +#include #if defined(BOOST_MSVC) # pragma warning( push ) @@ -624,14 +625,10 @@ namespace boost { assign_to(const reference_wrapper& f, function_buffer& functor, function_obj_ref_tag) { - if (!boost::detail::function::has_empty_target(f.get_pointer())) { - functor.obj_ref.obj_ptr = (void *)f.get_pointer(); - functor.obj_ref.is_const_qualified = is_const::value; - functor.obj_ref.is_volatile_qualified = is_volatile::value; - return true; - } else { - return false; - } + functor.obj_ref.obj_ptr = (void *)f.get_pointer(); + functor.obj_ref.is_const_qualified = is_const::value; + functor.obj_ref.is_volatile_qualified = is_volatile::value; + return true; } template bool @@ -678,6 +675,11 @@ namespace boost { R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS> vtable_type; + vtable_type* get_vtable() const { + return reinterpret_cast( + reinterpret_cast(vtable) & ~(std::size_t)0x01); + } + struct clear_type {}; public: @@ -757,7 +759,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return static_cast(vtable)->invoker + return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #else @@ -781,24 +783,26 @@ namespace boost { operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { this->clear(); - try { + BOOST_TRY { this->assign_to(f); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END return *this; } template void assign(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a) { this->clear(); - try { + BOOST_TRY{ this->assign_to_a(f,a); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END } #ifndef BOOST_NO_SFINAE @@ -823,12 +827,13 @@ namespace boost { return *this; this->clear(); - try { + BOOST_TRY { this->assign_to_own(f); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END return *this; } @@ -847,7 +852,8 @@ namespace boost { void clear() { if (vtable) { - reinterpret_cast(vtable)->clear(this->functor); + if (!this->has_trivial_copy_and_destroy()) + get_vtable()->clear(this->functor); vtable = 0; } } @@ -876,8 +882,11 @@ namespace boost { { if (!f.empty()) { this->vtable = f.vtable; - f.vtable->manager(f.functor, this->functor, - boost::detail::function::clone_functor_tag); + if (this->has_trivial_copy_and_destroy()) + this->functor = f.functor; + else + get_vtable()->base.manager(f.functor, this->functor, + boost::detail::function::clone_functor_tag); } } @@ -903,8 +912,15 @@ namespace boost { static vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; - else vtable = 0; + if (stored_vtable.assign_to(f, functor)) { + std::size_t value = reinterpret_cast(&stored_vtable.base); + if (boost::has_trivial_copy_constructor::value && + boost::has_trivial_destructor::value && + detail::function::function_allows_small_object_optimization::value) + value |= (std::size_t)0x01; + vtable = reinterpret_cast(value); + } else + vtable = 0; } template @@ -930,8 +946,15 @@ namespace boost { static vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; - if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base; - else vtable = 0; + if (stored_vtable.assign_to_a(f, functor, a)) { + std::size_t value = reinterpret_cast(&stored_vtable.base); + if (boost::has_trivial_copy_constructor::value && + boost::has_trivial_destructor::value && + detail::function::function_allows_small_object_optimization::value) + value |= (std::size_t)0x01; + vtable = reinterpret_cast(value); + } else + vtable = 0; } // Moves the value from the specified argument to *this. If the argument @@ -942,23 +965,23 @@ namespace boost { if (&f == this) return; -#if !defined(BOOST_NO_EXCEPTIONS) - try { -#endif + BOOST_TRY { if (!f.empty()) { this->vtable = f.vtable; - f.vtable->manager(f.functor, this->functor, - boost::detail::function::move_functor_tag); + if (this->has_trivial_copy_and_destroy()) + this->functor = f.functor; + else + get_vtable()->base.manager(f.functor, this->functor, + boost::detail::function::move_functor_tag); f.vtable = 0; -#if !defined(BOOST_NO_EXCEPTIONS) } else { clear(); } - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } -#endif + BOOST_CATCH_END } }; @@ -979,13 +1002,14 @@ namespace boost { template typename BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type - BOOST_FUNCTION_FUNCTION + inline + BOOST_FUNCTION_FUNCTION ::operator()(BOOST_FUNCTION_PARMS) const { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif diff --git a/test/allocator_test.cpp b/test/allocator_test.cpp index 7b35f16..3643b2b 100644 --- a/test/allocator_test.cpp +++ b/test/allocator_test.cpp @@ -128,6 +128,10 @@ test_main(int, char*[]) BOOST_CHECK(dealloc_count == 0); fv.assign( &do_nothing, std::allocator() ); fv.clear(); + + function0 fv2; + fv.assign(&do_nothing, std::allocator() ); + fv2.assign(fv, std::allocator() ); return 0; } diff --git a/test/function_test.cpp b/test/function_test.cpp index 9870ac7..65d6e58 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -13,8 +13,8 @@ #include #include -using namespace boost; -using namespace std; +using boost::function; +using std::string; int global_int; @@ -525,7 +525,7 @@ test_zero_args() static void test_one_arg() { - negate neg; + std::negate neg; function f1(neg); BOOST_CHECK(f1(5) == -5); @@ -607,12 +607,12 @@ struct add_with_throw_on_copy { add_with_throw_on_copy(const add_with_throw_on_copy&) { - throw runtime_error("But this CAN'T throw"); + throw std::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"); + throw std::runtime_error("But this CAN'T throw"); } }; @@ -621,14 +621,38 @@ test_ref() { add_with_throw_on_copy atc; try { - boost::function f(ref(atc)); + boost::function f(boost::ref(atc)); BOOST_CHECK(f(1, 3) == 4); } - catch(runtime_error e) { + catch(std::runtime_error e) { BOOST_ERROR("Nonthrowing constructor threw an exception"); } } +static void dummy() {} + +static void test_empty_ref() +{ + boost::function f1; + boost::function f2(boost::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() { boost::function f; @@ -674,6 +698,7 @@ int test_main(int, char* []) test_emptiness(); test_member_functions(); test_ref(); + test_empty_ref(); test_exception(); test_implicit(); test_call(); diff --git a/test/lambda_test.cpp b/test/lambda_test.cpp index 97fa7f8..2abca54 100644 --- a/test/lambda_test.cpp +++ b/test/lambda_test.cpp @@ -15,21 +15,21 @@ #include #include -using namespace std; -using namespace boost; -using namespace boost::lambda; - static unsigned func_impl(int arg1, bool arg2, double arg3) { + using namespace std; return abs (static_cast((arg2 ? arg1 : 2 * arg1) * arg3)); } int test_main(int, char*[]) { + using boost::function; + using namespace boost::lambda; + function f1 = bind(func_impl, 15, _1, _2); - function f2 = bind(f1, false, _1); - function f3 = bind(f2, 4.0); + function f2 = boost::lambda::bind(f1, false, _1); + function f3 = boost::lambda::bind(f2, 4.0); f3();