? libs/function/test/.gdb_history ? libs/function/test/a.out ? libs/function/test/performance.cpp ? libs/function/test/size.cpp Index: boost/function/function_base.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/function/function_base.hpp,v retrieving revision 1.82 diff -u -r1.82 function_base.hpp --- boost/function/function_base.hpp 30 Dec 2005 02:31:51 -0000 1.82 +++ boost/function/function_base.hpp 7 Jan 2006 18:00:05 -0000 @@ -1,6 +1,6 @@ // Boost.Function library -// Copyright Douglas Gregor 2001-2004. Use, modification and +// Copyright Douglas Gregor 2001-2006. 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) @@ -19,10 +19,10 @@ #include #include #include -#include #include -#include +#include #include +#include #ifndef BOOST_NO_SFINAE # include "boost/utility/enable_if.hpp" #else @@ -105,41 +105,35 @@ namespace boost { namespace detail { namespace function { + class X; + /** - * A union of a function pointer and a void pointer. This is necessary - * because 5.2.10/6 allows reinterpret_cast<> to safely cast between - * function pointer types and 5.2.9/10 allows static_cast<> to safely - * cast between a void pointer and an object pointer. But it is not legal - * to cast between a function pointer and a void* (in either direction), - * so function requires a union of the two. */ - union any_pointer + * A buffer used to store small function objects in + * boost::function. It is a union containing function pointers, + * object pointers, and a structure that resembles a bound + * member function pointer. + */ + union function_buffer { + // For pointers to function objects void* obj_ptr; + + // For pointers to std::type_info objects + // (get_functor_type_tag, check_functor_type_tag). const void* const_obj_ptr; - void (*func_ptr)(); - char data[1]; - }; - inline any_pointer make_any_pointer(void* o) - { - any_pointer p; - p.obj_ptr = o; - return p; - } + // For function pointers of all kinds + mutable void (*func_ptr)(); - inline any_pointer make_any_pointer(const void* o) - { - any_pointer p; - p.const_obj_ptr = o; - return p; - } + // For bound member pointers + struct bound_memfunc_ptr_t { + void (X::*memfunc_ptr)(int); + void* obj_ptr; + } bound_memfunc_ptr; - inline any_pointer make_any_pointer(void (*f)()) - { - any_pointer p; - p.func_ptr = f; - return p; - } + // To relax aliasing constraints + mutable char data; + }; /** * The unusable class is a placeholder for unused function arguments @@ -169,7 +163,8 @@ enum functor_manager_operation_type { clone_functor_tag, destroy_functor_tag, - check_functor_type_tag + check_functor_type_tag, + get_functor_type_tag }; // Tags used to decide between different types of functions @@ -177,58 +172,80 @@ struct function_obj_tag {}; struct member_ptr_tag {}; struct function_obj_ref_tag {}; - struct stateless_function_obj_tag {}; template class get_function_tag { - typedef typename ct_if<(is_pointer::value), - function_ptr_tag, - function_obj_tag>::type ptr_or_obj_tag; - - typedef typename ct_if<(is_member_pointer::value), - member_ptr_tag, - ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag; - - typedef typename ct_if<(is_reference_wrapper::value), - function_obj_ref_tag, - ptr_or_obj_or_mem_tag>::type or_ref_tag; + typedef typename mpl::if_c<(is_pointer::value), + function_ptr_tag, + function_obj_tag>::type ptr_or_obj_tag; + + typedef typename mpl::if_c<(is_member_pointer::value), + member_ptr_tag, + ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag; + + typedef typename mpl::if_c<(is_reference_wrapper::value), + function_obj_ref_tag, + ptr_or_obj_or_mem_tag>::type or_ref_tag; public: - typedef typename ct_if<(is_stateless::value), - stateless_function_obj_tag, - or_ref_tag>::type type; + typedef or_ref_tag type; }; // The trivial manager does nothing but return the same pointer (if we // are cloning) or return the null pointer (if we are deleting). template - struct trivial_manager + struct reference_manager { - static inline any_pointer - get(any_pointer f, functor_manager_operation_type op) + static inline void + get(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { switch (op) { - case clone_functor_tag: return f; + case clone_functor_tag: + out_buffer.obj_ptr = in_buffer.obj_ptr; + return; case destroy_functor_tag: - return make_any_pointer(reinterpret_cast(0)); + out_buffer.obj_ptr = 0; + return; case check_functor_type_tag: { - std::type_info* t = static_cast(f.obj_ptr); - return BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(F), *t)? - f - : make_any_pointer(reinterpret_cast(0)); + // DPG TBD: Since we're only storing a pointer, it's + // possible that the user could ask for a base class or + // derived class. Is that okay? + const std::type_info& check_type = + *static_cast(out_buffer.const_obj_ptr); + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))) + out_buffer.obj_ptr = in_buffer.obj_ptr; + else + out_buffer.obj_ptr = 0; } - } + return; - // Clears up a warning with GCC 3.2.3 - return make_any_pointer(reinterpret_cast(0)); + case get_functor_type_tag: + out_buffer.const_obj_ptr = &typeid(F); + return; + } } }; /** + * Determine if boost::function can use the small-object + * optimization with the function object type F. + */ + template + struct function_allows_small_object_optimization + { + BOOST_STATIC_CONSTANT + (bool, + value = ((sizeof(F) <= sizeof(function_buffer) && + (alignment_of::value + % alignment_of::value == 0)))); + }; + + /** * The functor_manager class contains a static function "manage" which * can clone or destroy the given function/function object pointer. */ @@ -239,30 +256,58 @@ typedef Functor functor_type; // For function pointers, the manager is trivial - static inline any_pointer - manager(any_pointer function_ptr, - functor_manager_operation_type op, - function_ptr_tag) + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, function_ptr_tag) { if (op == clone_functor_tag) - return function_ptr; - else - return make_any_pointer(static_cast(0)); + out_buffer.func_ptr = in_buffer.func_ptr; + else if (op == destroy_functor_tag) + out_buffer.func_ptr = 0; + else /* op == check_functor_type_tag */ { + const std::type_info& check_type = + *static_cast(out_buffer.const_obj_ptr); + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + out_buffer.obj_ptr = &in_buffer.func_ptr; + else + out_buffer.obj_ptr = 0; + } } - // For function object pointers, we clone the pointer to each - // function has its own version. - static inline any_pointer - manager(any_pointer function_obj_ptr, - functor_manager_operation_type op, - function_obj_tag) + // Function objects that fit in the small-object buffer. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, mpl::true_) + { + if (op == clone_functor_tag) { + const functor_type* in_functor = + reinterpret_cast(&in_buffer.data); + new ((void*)&out_buffer.data) functor_type(*in_functor); + } else if (op == destroy_functor_tag) { + functor_type* out_functor = + reinterpret_cast(&out_buffer.data); + out_functor->~functor_type(); + } else /* op == check_functor_type_tag */ { + const std::type_info& check_type = + *static_cast(out_buffer.const_obj_ptr); + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + out_buffer.obj_ptr = &in_buffer.data; + else + out_buffer.obj_ptr = 0; + } + } + + // Function objects that require heap allocation + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, mpl::false_) { #ifndef BOOST_NO_STD_ALLOCATOR - typedef typename Allocator::template rebind::other - allocator_type; - typedef typename allocator_type::pointer pointer_type; + typedef typename Allocator::template rebind::other + allocator_type; + typedef typename allocator_type::pointer pointer_type; #else - typedef functor_type* pointer_type; + typedef functor_type* pointer_type; #endif // BOOST_NO_STD_ALLOCATOR # ifndef BOOST_NO_STD_ALLOCATOR @@ -270,8 +315,8 @@ # endif // BOOST_NO_STD_ALLOCATOR if (op == clone_functor_tag) { - functor_type* f = - static_cast(function_obj_ptr.obj_ptr); + const functor_type* f = + static_cast(in_buffer.obj_ptr); // Clone the functor # ifndef BOOST_NO_STD_ALLOCATOR @@ -283,12 +328,11 @@ # else functor_type* new_f = new functor_type(*f); # endif // BOOST_NO_STD_ALLOCATOR - return make_any_pointer(static_cast(new_f)); - } - else { + out_buffer.obj_ptr = new_f; + } else if (op == destroy_functor_tag) { /* Cast from the void pointer to the functor pointer type */ functor_type* f = - reinterpret_cast(function_obj_ptr.obj_ptr); + static_cast(out_buffer.obj_ptr); # ifndef BOOST_NO_STD_ALLOCATOR /* Cast from the functor pointer type to the allocator's pointer @@ -301,26 +345,43 @@ # else delete f; # endif // BOOST_NO_STD_ALLOCATOR - - return make_any_pointer(static_cast(0)); + out_buffer.obj_ptr = 0; + } else /* op == check_functor_type_tag */ { + const std::type_info& check_type = + *static_cast(out_buffer.const_obj_ptr); + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + out_buffer.obj_ptr = in_buffer.obj_ptr; + else + out_buffer.obj_ptr = 0; } } + + // For function objects, we determine whether the function + // object can use the small-object optimization buffer or + // whether we need to allocate it on the heap. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, function_obj_tag) + { + manager(in_buffer, out_buffer, op, + mpl::bool_<(function_allows_small_object_optimization::value)>()); + } + public: /* Dispatch to an appropriate manager based on whether we have a function pointer or a function object pointer. */ - static any_pointer - manage(any_pointer functor_ptr, functor_manager_operation_type op) + static inline void + manage(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { - if (op == check_functor_type_tag) { - std::type_info* type = - static_cast(functor_ptr.obj_ptr); - return (BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(Functor), *type)? - functor_ptr - : make_any_pointer(reinterpret_cast(0))); - } - else { - typedef typename get_function_tag::type tag_type; - return manager(functor_ptr, op, tag_type()); + typedef typename get_function_tag::type tag_type; + switch (op) { + case get_functor_type_tag: + out_buffer.const_obj_ptr = &typeid(functor_type); + return; + + default: + return manager(in_buffer, out_buffer, op, tag_type()); } } }; @@ -394,7 +455,9 @@ struct vtable_base { vtable_base() : manager(0) { } - any_pointer (*manager)(any_pointer, functor_manager_operation_type); + void (*manager)(const function_buffer& in_buffer, + function_buffer& out_buffer, + functor_manager_operation_type op); }; } // end namespace function } // end namespace detail @@ -408,27 +471,32 @@ class function_base { public: - function_base() : vtable(0) - { - functor.obj_ptr = 0; - } + function_base() : vtable(0) { } - // Is this function empty? + /** Determine if the function is empty (i.e., has no target). */ bool empty() const { return !vtable; } + /** Retrieve the type of the stored function object, or typeid(void) + if this is empty. */ + const std::type_info& target_type() + { + if (!vtable) return typeid(void); + + detail::function::function_buffer type; + vtable->manager(functor, type, detail::function::get_functor_type_tag); + return *static_cast(type.const_obj_ptr); + } + template Functor* target() { if (!vtable) return 0; - detail::function::any_pointer result = - vtable->manager(detail::function::make_any_pointer(&typeid(Functor)), - detail::function::check_functor_type_tag); - if (!result.obj_ptr) return 0; - else { - typedef typename detail::function::get_function_tag::type tag; - return get_functor_pointer(tag(), 0); - } + detail::function::function_buffer type_result; + type_result.const_obj_ptr = &typeid(Functor); + vtable->manager(functor, type_result, + detail::function::check_functor_type_tag); + return static_cast(type_result.obj_ptr); } template @@ -440,19 +508,11 @@ { if (!vtable) return 0; - detail::function::any_pointer result = - vtable->manager(detail::function::make_any_pointer(&typeid(Functor)), - detail::function::check_functor_type_tag); - if (!result.obj_ptr) return 0; - else { - typedef typename detail::function::get_function_tag::type tag; - -#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) - return get_functor_pointer(tag(), 0, (Functor*)0); -#else - return get_functor_pointer(tag(), 0); -#endif - } + detail::function::function_buffer type_result; + type_result.const_obj_ptr = &typeid(Functor); + vtable->manager(functor, type_result, + detail::function::check_functor_type_tag); + return static_cast(type_result.obj_ptr); } template @@ -495,41 +555,7 @@ public: // should be protected, but GCC 2.95.3 will fail to allow access detail::function::vtable_base* vtable; - detail::function::any_pointer functor; - -private: - template -#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) - Functor* get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0) -#else - Functor* get_functor_pointer(detail::function::function_ptr_tag, int) -#endif - { return reinterpret_cast(&functor.func_ptr); } - - template -#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) - Functor* get_functor_pointer(Tag, long, Functor * = 0) -#else - Functor* get_functor_pointer(Tag, long) -#endif - { return static_cast(functor.obj_ptr); } - - template - const Functor* -#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) - get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0) const -#else - get_functor_pointer(detail::function::function_ptr_tag, int) const -#endif - { return reinterpret_cast(&functor.func_ptr); } - - template -#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300) - const Functor* get_functor_pointer(Tag, long, Functor * = 0) const -#else - const Functor* get_functor_pointer(Tag, long) const -#endif - { return static_cast(functor.const_obj_ptr); } + mutable detail::function::function_buffer functor; }; /** Index: boost/function/function_template.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/function/function_template.hpp,v retrieving revision 1.84 diff -u -r1.84 function_template.hpp --- boost/function/function_template.hpp 30 Dec 2005 02:31:51 -0000 1.84 +++ boost/function/function_template.hpp 7 Jan 2006 18:00:06 -0000 @@ -1,6 +1,6 @@ // Boost.Function library -// Copyright Douglas Gregor 2001-2003. Use, modification and +// Copyright Douglas Gregor 2001-2006. 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) @@ -50,16 +50,16 @@ BOOST_JOIN(function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER \ - BOOST_JOIN(stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER \ - BOOST_JOIN(stateless_void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_FUNCTION_REF_INVOKER \ + BOOST_JOIN(function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER \ + BOOST_JOIN(void_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_INVOKER \ BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER \ - BOOST_JOIN(get_stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER \ + BOOST_JOIN(get_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VTABLE BOOST_JOIN(basic_vtable,BOOST_FUNCTION_NUM_ARGS) #ifndef BOOST_NO_VOID_RETURNS @@ -80,7 +80,7 @@ > struct BOOST_FUNCTION_FUNCTION_INVOKER { - static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA + static R invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionPtr f = reinterpret_cast(function_ptr.func_ptr); @@ -96,7 +96,7 @@ struct BOOST_FUNCTION_VOID_FUNCTION_INVOKER { static BOOST_FUNCTION_VOID_RETURN_TYPE - invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA + invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { @@ -112,11 +112,15 @@ > struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER { - static R invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA + static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { - FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr); + FunctionObj* f; + if (function_allows_small_object_optimization::value) + f = reinterpret_cast(&function_obj_ptr.data); + else + f = reinterpret_cast(function_obj_ptr.obj_ptr); return (*f)(BOOST_FUNCTION_ARGS); } }; @@ -129,11 +133,15 @@ struct BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER { static BOOST_FUNCTION_VOID_RETURN_TYPE - invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA + invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { - FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr); + FunctionObj* f; + if (function_allows_small_object_optimization::value) + f = reinterpret_cast(&function_obj_ptr.data); + else + f = reinterpret_cast(function_obj_ptr.obj_ptr); BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS)); } }; @@ -143,12 +151,15 @@ typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > - struct BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER + struct BOOST_FUNCTION_FUNCTION_REF_INVOKER { - static R invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) + static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA + BOOST_FUNCTION_PARMS) + { - FunctionObj f = FunctionObj(); - return f(BOOST_FUNCTION_ARGS); + FunctionObj* f = + reinterpret_cast(function_obj_ptr.obj_ptr); + return (*f)(BOOST_FUNCTION_ARGS); } }; @@ -157,14 +168,16 @@ typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > - struct BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER + struct BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER { static BOOST_FUNCTION_VOID_RETURN_TYPE - invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) + invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA + BOOST_FUNCTION_PARMS) { - FunctionObj f = FunctionObj(); - BOOST_FUNCTION_RETURN(f(BOOST_FUNCTION_ARGS)); + FunctionObj* f = + reinterpret_cast(function_obj_ptr.obj_ptr); + BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS)); } }; @@ -175,7 +188,7 @@ > struct BOOST_FUNCTION_GET_FUNCTION_INVOKER { - typedef typename ct_if<(is_void::value), + typedef typename mpl::if_c<(is_void::value), BOOST_FUNCTION_VOID_FUNCTION_INVOKER< FunctionPtr, R BOOST_FUNCTION_COMMA @@ -196,7 +209,7 @@ > struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER { - typedef typename ct_if<(is_void::value), + typedef typename mpl::if_c<(is_void::value), BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA @@ -215,15 +228,15 @@ typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > - struct BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER + struct BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER { - typedef typename ct_if<(is_void::value), - BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER< + typedef typename mpl::if_c<(is_void::value), + BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >, - BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER< + BOOST_FUNCTION_FUNCTION_REF_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS @@ -244,7 +257,7 @@ typedef typename function_return_type::type result_type; #endif // BOOST_NO_VOID_RETURNS - typedef result_type (*invoker_type)(any_pointer + typedef result_type (*invoker_type)(function_buffer& BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS); @@ -255,16 +268,16 @@ } template - bool assign_to(F f, any_pointer& functor) + bool assign_to(F f, function_buffer& functor) { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); } - void clear(any_pointer& functor) + void clear(function_buffer& functor) { if (manager) - functor = manager(functor, destroy_functor_tag); + manager(functor, functor, destroy_functor_tag); } private: @@ -291,14 +304,14 @@ } template - bool assign_to(FunctionPtr f, any_pointer& functor, function_ptr_tag) + bool + assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) { this->clear(functor); if (f) { // should be a reinterpret cast, but some compilers insist // on giving cv-qualifiers to free functions - functor = manager(make_any_pointer((void (*)())(f)), - clone_functor_tag); + functor.func_ptr = (void (*)())(f); return true; } else { return false; @@ -310,12 +323,18 @@ template void init(MemberPtr f, member_ptr_tag) { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. this->init(mem_fn(f)); } template - bool assign_to(MemberPtr f, any_pointer& functor, member_ptr_tag) + bool assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. if (f) { this->assign_to(mem_fn(f), functor); return true; @@ -325,7 +344,7 @@ } #endif // BOOST_FUNCTION_NUM_ARGS > 0 - // Stateful function objects + // Function objects template void init(FunctionObj f, function_obj_tag) { @@ -340,24 +359,42 @@ manager = &functor_manager::manage; } + // Assign to a function object using the small object optimization template - bool assign_to(FunctionObj f, any_pointer& functor, function_obj_tag) + void + assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) + { + new ((void*)&functor.data) FunctionObj(f); + } + + // Assign to a function object allocated on the heap. + template + void + assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) { - if (!boost::detail::function::has_empty_target(boost::addressof(f))) { #ifndef BOOST_NO_STD_ALLOCATOR - typedef typename Allocator::template rebind::other - rebound_allocator_type; - typedef typename rebound_allocator_type::pointer pointer_type; - rebound_allocator_type allocator; - pointer_type copy = allocator.allocate(1); - allocator.construct(copy, f); + typedef typename Allocator::template rebind::other + allocator_type; + typedef typename allocator_type::pointer pointer_type; + + allocator_type allocator; + pointer_type copy = allocator.allocate(1); + allocator.construct(copy, f); + + // Get back to the original pointer type + functor.obj_ptr = static_cast(copy); +# else + functor.obj_ptr = new FunctionObj(f); +# endif // BOOST_NO_STD_ALLOCATOR + } - // Get back to the original pointer type - FunctionObj* new_f = static_cast(copy); -#else - FunctionObj* new_f = new FunctionObj(f); -#endif // BOOST_NO_STD_ALLOCATOR - functor = make_any_pointer(static_cast(new_f)); + template + bool + assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) + { + if (!boost::detail::function::has_empty_target(boost::addressof(f))) { + assign_functor(f, functor, + mpl::bool_<(function_allows_small_object_optimization::value)>()); return true; } else { return false; @@ -369,7 +406,7 @@ void init(const reference_wrapper& f, function_obj_ref_tag) { - typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS @@ -377,46 +414,20 @@ actual_invoker_type; invoker = &actual_invoker_type::invoke; - manager = &trivial_manager::get; + manager = &reference_manager::get; } template bool - assign_to(const reference_wrapper& f, any_pointer& functor, - function_obj_ref_tag) + assign_to(const reference_wrapper& f, + function_buffer& functor, function_obj_ref_tag) { if (!boost::detail::function::has_empty_target(f.get_pointer())) { - functor = manager(make_any_pointer( - const_cast(f.get_pointer())), - clone_functor_tag); - return true; - } else { - return false; - } - } - - // Stateless function object - template - void - init(FunctionObj, stateless_function_obj_tag) - { - typedef - typename BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER< - FunctionObj, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type actual_invoker_type; - invoker = &actual_invoker_type::invoke; - manager = &trivial_manager::get; - } - - template - bool - assign_to(FunctionObj f, any_pointer& functor, - stateless_function_obj_tag) - { - if (!boost::detail::function::has_empty_target(boost::addressof(f))) { - functor = make_any_pointer(this); + // DPG TBD: We might need to detect constness of + // FunctionObj to assign into obj_ptr or const_obj_ptr to + // be truly legit, but no platform in existence makes + // const void* different from void*. + functor.const_obj_ptr = f.get_pointer(); return true; } else { return false; @@ -539,7 +550,13 @@ #endif operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { - self_type(f).swap(*this); + this->clear(); + try { + this->assign_to(f); + } catch (...) { + vtable = 0; + throw; + } return *this; } @@ -564,7 +581,13 @@ if (&f == this) return *this; - self_type(f).swap(*this); + this->clear(); + try { + this->assign_to_own(f); + } catch (...) { + vtable = 0; + throw; + } return *this; } @@ -573,8 +596,9 @@ if (&other == this) return; - std::swap(this->functor, other.functor); - std::swap(this->vtable, other.vtable); + BOOST_FUNCTION_FUNCTION tmp = *this; + *this = other; + other = tmp; } // Clear out a target, if there is one @@ -610,9 +634,8 @@ { if (!f.empty()) { this->vtable = f.vtable; - this->functor = - f.vtable->manager(f.functor, - boost::detail::function::clone_functor_tag); + f.vtable->manager(f.functor, this->functor, + boost::detail::function::clone_functor_tag); } } @@ -779,11 +802,11 @@ #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER -#undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER -#undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER +#undef BOOST_FUNCTION_FUNCTION_REF_INVOKER +#undef BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER -#undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER +#undef BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER #undef BOOST_FUNCTION_TEMPLATE_PARMS #undef BOOST_FUNCTION_TEMPLATE_ARGS Index: libs/function/test/allocator_test.cpp =================================================================== RCS file: /cvsroot/boost/boost/libs/function/test/allocator_test.cpp,v retrieving revision 1.12 diff -u -r1.12 allocator_test.cpp --- libs/function/test/allocator_test.cpp 10 May 2005 13:30:26 -0000 1.12 +++ libs/function/test/allocator_test.cpp 7 Jan 2006 18:00:06 -0000 @@ -45,7 +45,7 @@ { int operator()(int x, int y) const { return x + y; } - int unused_state_data; + int unused_state_data[32]; }; static int do_minus(int x, int y) { return x-y; } @@ -54,7 +54,7 @@ { void operator()() const {} - int unused_state_data; + int unused_state_data[32]; }; static void do_nothing() {} Index: libs/function/test/stateless_test.cpp =================================================================== RCS file: /cvsroot/boost/boost/libs/function/test/stateless_test.cpp,v retrieving revision 1.12 diff -u -r1.12 stateless_test.cpp --- libs/function/test/stateless_test.cpp 25 Jul 2004 02:51:52 -0000 1.12 +++ libs/function/test/stateless_test.cpp 7 Jan 2006 18:00:06 -0000 @@ -14,22 +14,20 @@ struct stateless_integer_add { int operator()(int x, int y) const { return x+y; } - void* operator new(std::size_t, stateless_integer_add*) + void* operator new(std::size_t) { throw std::runtime_error("Cannot allocate a stateless_integer_add"); } - void operator delete(void*, stateless_integer_add*) throw() + void* operator new(std::size_t, void* p) { + return p; } -}; -namespace boost { - template<> - struct is_stateless { - BOOST_STATIC_CONSTANT(bool, value = true); - }; -} + void operator delete(void*) throw() + { + } +}; int test_main(int, char*[]) {