diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 35afa16..2cc6bf6 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 @@ -625,7 +628,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 +641,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 +659,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 +705,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_template.hpp b/include/boost/function/function_template.hpp index 584abe9..23687b4 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -678,6 +678,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 +762,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 @@ -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 @@ -947,9 +970,12 @@ namespace boost { #endif if (!f.empty()) { this->vtable = f.vtable; - f.vtable->manager(f.functor, this->functor, - boost::detail::function::move_functor_tag); - f.vtable = 0; + 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(); @@ -979,13 +1005,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