diff --git a/doc/history.xml b/doc/history.xml index 2af6dd6..eb5a442 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -13,6 +13,22 @@ + Version 1.36.0: + + Boost.Function now implements allocator support + in the same way that is is provided in C++0x, based on C++ + committee + proposal N2308. This + change removes the Allocator + template parameter of boost::function in + favor of a constructor that takes an argument. While this is a + backward-incompatible change, it is likely to affect only a few + users. This change to Function was contributed by Emil + Dotchevski, which also authored the corresponding C++ committee + proposal. + + + Version 1.34.0: Boost.Function now implements a small buffer optimization, which can drastically improve the performance when copying or construction Boost.Function objects storing small function objects. For instance, bind(&X:foo, &x, _1, _2) requires no heap allocation when placed into a Boost.Function object. Note that some exception-safety guarantees have changed: assignment provides the basic exception guarantee and swap() may throw. diff --git a/doc/misc.xml b/doc/misc.xml index 840605d..ef0906c 100644 --- a/doc/misc.xml +++ b/doc/misc.xml @@ -24,7 +24,7 @@ And, of course, function pointers have several advantages over Boost.Function: - Function pointers are smaller (the size of one pointer instead of three) + Function pointers are smaller (the size of one pointer instead of four or more) Function pointers are faster (Boost.Function may require two calls through function pointers) Function pointers are backward-compatible with C libraries. More readable error messages. @@ -37,12 +37,12 @@
Function object wrapper size - Function object wrappers will be the size of two function pointers plus one function pointer or data pointer (whichever is larger). On common 32-bit platforms, this amounts to 12 bytes per wrapper. Additionally, the function object target will be allocated on the heap. + Function object wrappers will be the size of a struct containing a member function pointer and two data pointers. The actual size can vary significantly depending on the underlying platform; on 32-bit Mac OS X with GCC, this amounts to 16 bytes, while it is 32 bytes Windows with Visual C++. Additionally, the function object target may be allocated on the heap, if it cannot be placed into the small-object buffer in the boost::function object.
Copying efficiency - Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using ref) if the cost of this cloning becomes prohibitive. + Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using ref) if the cost of this cloning becomes prohibitive. Small function objects can be stored within the boost::function object itself, improving copying efficiency.
diff --git a/doc/reference.xml b/doc/reference.xml index 54b06e0..3b1faec 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -141,9 +141,6 @@ - - std::allocator<void> - function_base @@ -160,7 +157,6 @@ R - Allocator T1If N == 1 @@ -216,6 +212,19 @@ *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + + F + Allocator + F is a function object Callable from this, Allocator is an allocator. The copy constructor and destructor of Allocator shall not throw. + *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + If memory allocation is required, the given allocator (or a copy of it) will be used to allocate that memory. + + If !this->empty(), destroys the target of this. @@ -324,11 +333,10 @@ - void - functionN<T1, T2, ..., TN, Allocator>& - functionN<T1, T2, ..., TN, Allocator>& + functionN<T1, T2, ..., TN>& + functionN<T1, T2, ..., TN>& f1.swap(f2) @@ -341,11 +349,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -354,12 +361,11 @@ - bool Functor - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& reference_wrapper<Functor> @@ -380,12 +385,11 @@ - bool reference_wrapper<Functor> - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& void - const functionN<T1, T2, ..., TN, Allocator1>& - const functionN<U1, U2, ..., UN, Allocator2>& + const functionN<T1, T2, ..., TN>& + const functionN<U1, U2, ..., UN>& True when f stores an object of @@ -442,11 +444,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -455,12 +456,11 @@ - bool Functor - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& reference_wrapper<Functor> @@ -481,12 +480,11 @@ - bool reference_wrapper<Functor> - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& void - const functionN<T1, T2, ..., TN, Allocator1>& - const functionN<U1, U2, ..., UN, Allocator2>& + const functionN<T1, T2, ..., TN>& + const functionN<U1, U2, ..., UN>& True when f does not store an @@ -543,11 +539,8 @@ Function type R (T1, T2, ..., TN) - - std::allocator<void> - - functionN<R, T1, T2, ..., TN, Allocator> + functionN<R, T1, T2, ..., TN> A generalized function pointer that can be used for callbacks or wrapping function objects. @@ -569,7 +562,6 @@ R - Allocator T1If N == 1 @@ -633,6 +625,19 @@ *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + + F + Allocator + F is a function object Callable from this, Allocator is an allocator. The copy constructor and destructor of Allocator shall not throw. + *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + If memory allocation is required, the given allocator (or a copy of it) will be used to allocate that memory. + + If !this->empty(), destroys the target of this. @@ -745,11 +750,10 @@ void - function<Signature, Allocator>& - function<Signature, Allocator>& + function<Signature>& + function<Signature>& f1.swap(f2) @@ -759,53 +763,47 @@ bool - const function<Signature, Allocator>& + const function<Signature>& Functor bool Functor - const function<Signature, Allocator>& + const function<Signature>& bool - const function<Signature, Allocator>& + const function<Signature>& reference_wrapper<Functor> bool reference_wrapper<Functor> - const function<Signature, Allocator>& + const function<Signature>& void - const function<Signature1, Allocator1>& - const function<Signature2, Allocator2>& + const function<Signature1>& + const function<Signature2>& True when f stores an object of @@ -840,53 +838,47 @@ bool - const function<Signature, Allocator>& + const function<Signature>& Functor bool Functor - const function<Signature, Allocator>& + const function<Signature>& bool - const function<Signature, Allocator>& + const function<Signature>& reference_wrapper<Functor> bool reference_wrapper<Functor> - const function<Signature, Allocator>& + const function<Signature>& void - const function<Signature1, Allocator1>& - const function<Signature2, Allocator2>& + const function<Signature1>& + const function<Signature2>& True when f does not store an diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index ab2b323..53d0f05 100644 --- a/include/boost/function/detail/prologue.hpp +++ b/include/boost/function/detail/prologue.hpp @@ -11,7 +11,7 @@ #define BOOST_FUNCTION_PROLOGUE_HPP # include # include -# include // unary_function, binary_function +# include // unary_function, binary_function # include # include # include @@ -22,4 +22,5 @@ # include # include # include +# include #endif // BOOST_FUNCTION_PROLOGUE_HPP diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index aa7376a..8d46711 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -1,8 +1,9 @@ // Boost.Function library -// 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 +// Copyright Douglas Gregor 2001-2006 +// Copyright Emil Dotchevski 2007 +// 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 @@ -73,7 +74,7 @@ namespace boost { namespace python { namespace objects { #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) + || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX #endif @@ -94,21 +95,12 @@ namespace boost { namespace python { namespace objects { #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) namespace boost { -#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) -// The library shipping with MIPSpro 7.3.1.3m has a broken allocator -class function_base; - -template > +template class function; -#else -template > -class function; -#endif -template -inline void swap(function& f1, - function& f2) +template +inline void swap(function& f1, + function& f2) { f1.swap(f2); } @@ -212,8 +204,8 @@ namespace boost { struct reference_manager { static inline void - manage(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + get(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { switch (op) { case clone_functor_tag: @@ -259,20 +251,29 @@ namespace boost { % alignment_of::value == 0)))); }; + template + struct functor_wrapper: public F, public A + { + functor_wrapper( F f, A a ): + F(f), + A(a) + { + } + }; + /** * The functor_manager class contains a static function "manage" which * can clone or destroy the given function/function object pointer. */ - template - struct functor_manager + template + struct functor_manager_common { - private: typedef Functor functor_type; - // For function pointers, the manager is trivial + // Function pointers static inline void - manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, function_ptr_tag) + manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { if (op == clone_functor_tag) out_buffer.func_ptr = in_buffer.func_ptr; @@ -290,8 +291,8 @@ namespace boost { // 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_) + manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { if (op == clone_functor_tag) { const functor_type* in_functor = @@ -309,57 +310,48 @@ namespace boost { out_buffer.obj_ptr = 0; } } + }; + + template + struct functor_manager + { + private: + typedef Functor functor_type; + + // Function pointers + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, function_ptr_tag) + { + functor_manager_common::manage_ptr(in_buffer,out_buffer,op); + } + + // 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_) + { + functor_manager_common::manage_small(in_buffer,out_buffer,op); + } // 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; -#else - typedef functor_type* pointer_type; -#endif // BOOST_NO_STD_ALLOCATOR - -# ifndef BOOST_NO_STD_ALLOCATOR - allocator_type allocator; -# endif // BOOST_NO_STD_ALLOCATOR - if (op == clone_functor_tag) { + // Clone the functor // GCC 2.95.3 gets the CV qualifiers wrong here, so we // can't do the static_cast that we should do. const functor_type* f = (const functor_type*)(in_buffer.obj_ptr); - - // Clone the functor -# ifndef BOOST_NO_STD_ALLOCATOR - pointer_type copy = allocator.allocate(1); - allocator.construct(copy, *f); - - // Get back to the original pointer type - functor_type* new_f = static_cast(copy); -# else functor_type* new_f = new functor_type(*f); -# endif // BOOST_NO_STD_ALLOCATOR 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 = static_cast(out_buffer.obj_ptr); - -# ifndef BOOST_NO_STD_ALLOCATOR - /* Cast from the functor pointer type to the allocator's pointer - type */ - pointer_type victim = static_cast(f); - - // Destroy and deallocate the functor - allocator.destroy(victim); - allocator.deallocate(victim, 1); -# else delete f; -# endif // BOOST_NO_STD_ALLOCATOR out_buffer.obj_ptr = 0; } else /* op == check_functor_type_tag */ { const BOOST_FUNCTION_STD_NS::type_info& check_type = @@ -382,13 +374,98 @@ namespace boost { mpl::bool_<(function_allows_small_object_optimization::value)>()); } - // For member pointers, we treat them as function objects with - // the small-object optimization always enabled. + public: + /* Dispatch to an appropriate manager based on whether we have a + function pointer or a function object pointer. */ + static inline void + manage(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) + { + 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: + manager(in_buffer, out_buffer, op, tag_type()); + return; + } + } + }; + + template + struct functor_manager_a + { + private: + typedef Functor functor_type; + + // Function pointers static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, member_ptr_tag) + functor_manager_operation_type op, function_ptr_tag) { - manager(in_buffer, out_buffer, op, mpl::true_()); + functor_manager_common::manage_ptr(in_buffer,out_buffer,op); + } + + // 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_) + { + functor_manager_common::manage_small(in_buffer,out_buffer,op); + } + + // 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_) + { + typedef functor_wrapper functor_wrapper_type; + typedef typename Allocator::template rebind::other + wrapper_allocator_type; + typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type; + + if (op == clone_functor_tag) { + // Clone the functor + // GCC 2.95.3 gets the CV qualifiers wrong here, so we + // can't do the static_cast that we should do. + const functor_wrapper_type* f = + (const functor_wrapper_type*)(in_buffer.obj_ptr); + wrapper_allocator_type wrapper_allocator(static_cast(*f)); + wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); + wrapper_allocator.construct(copy, *f); + + // Get back to the original pointer type + functor_wrapper_type* new_f = static_cast(copy); + out_buffer.obj_ptr = new_f; + } else if (op == destroy_functor_tag) { + /* Cast from the void pointer to the functor_wrapper_type */ + functor_wrapper_type* victim = + static_cast(in_buffer.obj_ptr); + wrapper_allocator_type wrapper_allocator(static_cast(*victim)); + wrapper_allocator.destroy(victim); + wrapper_allocator.deallocate(victim,1); + out_buffer.obj_ptr = 0; + } else /* op == check_functor_type_tag */ { + const BOOST_FUNCTION_STD_NS::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: @@ -479,6 +556,7 @@ namespace boost { */ struct vtable_base { + vtable_base() : manager(0) { } void (*manager)(const function_buffer& in_buffer, function_buffer& out_buffer, functor_manager_operation_type op); @@ -580,7 +658,7 @@ public: #endif public: // should be protected, but GCC 2.95.3 will fail to allow access - const detail::function::vtable_base* vtable; + detail::function::vtable_base* vtable; mutable detail::function::function_buffer functor; }; @@ -755,8 +833,4 @@ namespace detail { #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL #undef BOOST_FUNCTION_COMPARE_TYPE_ID -#if defined(BOOST_MSVC) -# pragma warning( pop ) -#endif - #endif // BOOST_FUNCTION_BASE_HEADER diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index ab5c643..a575ebf 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -1,8 +1,9 @@ // Boost.Function library -// 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 +// Copyright Douglas Gregor 2001-2006 +// Copyright Emil Dotchevski 2007 +// 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 @@ -31,13 +32,6 @@ #define BOOST_FUNCTION_ARG_TYPES BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_ARG_TYPE,BOOST_PP_EMPTY) -// Type of the default allocator -#ifndef BOOST_NO_STD_ALLOCATOR -# define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator -#else -# define BOOST_FUNCTION_DEFAULT_ALLOCATOR int -#endif // BOOST_NO_STD_ALLOCATOR - // Comma if nonzero number of arguments #if BOOST_FUNCTION_NUM_ARGS == 0 # define BOOST_FUNCTION_COMMA @@ -59,20 +53,12 @@ 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_MEMBER_INVOKER \ - BOOST_JOIN(member_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_VOID_MEMBER_INVOKER \ - BOOST_JOIN(void_member_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_FUNCTION_REF_INVOKER \ BOOST_JOIN(get_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_GET_MEMBER_INVOKER \ - BOOST_JOIN(get_member_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_GET_INVOKER \ - BOOST_JOIN(get_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VTABLE BOOST_JOIN(basic_vtable,BOOST_FUNCTION_NUM_ARGS) #ifndef BOOST_NO_VOID_RETURNS @@ -194,44 +180,6 @@ namespace boost { } }; -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Handle invocation of member pointers. */ - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_MEMBER_INVOKER - { - static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA - BOOST_FUNCTION_PARMS) - - { - MemberPtr* f = - reinterpret_cast(&function_obj_ptr.data); - return boost::mem_fn(*f)(BOOST_FUNCTION_ARGS); - } - }; - - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_VOID_MEMBER_INVOKER - { - static BOOST_FUNCTION_VOID_RETURN_TYPE - invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA - BOOST_FUNCTION_PARMS) - - { - MemberPtr* f = - reinterpret_cast(&function_obj_ptr.data); - BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS)); - } - }; -#endif - template< typename FunctionPtr, typename R BOOST_FUNCTION_COMMA @@ -295,130 +243,11 @@ namespace boost { >::type type; }; -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Retrieve the appropriate invoker for a member pointer. */ - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_GET_MEMBER_INVOKER - { - typedef typename mpl::if_c<(is_void::value), - BOOST_FUNCTION_VOID_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >, - BOOST_FUNCTION_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - > - >::type type; - }; -#endif - - /* Given the tag returned by get_function_tag, retrieve the - actual invoker that will be used for the given function - object. - - Each specialization contains an "apply" nested class template - that accepts the function object, return type, function - argument types, and allocator. The resulting "apply" class - contains two typedefs, "invoker_type" and "manager_type", - which correspond to the invoker and manager types. */ - template - struct BOOST_FUNCTION_GET_INVOKER { }; - - /* Retrieve the invoker for a function pointer. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< - FunctionPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; - -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Retrieve the invoker for a member pointer. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; -#endif - - /* Retrieve the invoker for a function object. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< - FunctionObj, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; - - /* Retrieve the invoker for a reference to a function object. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER< - typename RefWrapper::type, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef reference_manager manager_type; - }; - }; - /** * vtable for a specific boost::function instance. */ - template - struct BOOST_FUNCTION_VTABLE + template + struct BOOST_FUNCTION_VTABLE : vtable_base { #ifndef BOOST_NO_VOID_RETURNS typedef R result_type; @@ -431,25 +260,80 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_ARGS); template - bool assign_to(const F& f, function_buffer& functor) const + BOOST_FUNCTION_VTABLE(F f) : vtable_base(), invoker(0) + { + init(f); + } + template + BOOST_FUNCTION_VTABLE(F f, Allocator) : vtable_base(), invoker(0) + { + init_a(f); + } + + template + bool assign_to(F f, function_buffer& functor) { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); } - - void clear(function_buffer& functor) const + template + bool assign_to_a(F f, function_buffer& functor, Allocator a) { - if (base.manager) - base.manager(functor, functor, destroy_functor_tag); + typedef typename get_function_tag::type tag; + return assign_to_a(f, functor, a, tag()); } -#ifndef BOOST_NO_PRIVATE_IN_AGGREGATE + + void clear(function_buffer& functor) + { + if (manager) + manager(functor, functor, destroy_functor_tag); + } + private: -#endif + template + void init(F f) + { + typedef typename get_function_tag::type tag; + init(f, tag()); + } + template + void init_a(F f) + { + typedef typename get_function_tag::type tag; + init_a(f, tag()); + } + // Function pointers + template + void init(FunctionPtr /*f*/, function_ptr_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< + FunctionPtr, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager::manage; + } + template + void init_a(FunctionPtr f, function_ptr_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< + FunctionPtr, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager_a::manage; + } + template bool - assign_to(FunctionPtr f, function_buffer& functor, - function_ptr_tag) const + assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) { this->clear(functor); if (f) { @@ -461,17 +345,53 @@ namespace boost { return false; } } + template + bool + assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) + { + return assign_to(f,functor,function_ptr_tag()); + } // Member pointers #if BOOST_FUNCTION_NUM_ARGS > 0 template - bool - assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) const + 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 + void init_a(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_a(mem_fn(f)); + } + + template + 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) { - // Always use the small-object optimization for member - // pointers. - assign_functor(f, functor, mpl::true_()); + this->assign_to(mem_fn(f), functor); + return true; + } else { + return false; + } + } + template + bool assign_to_a(MemberPtr f, function_buffer& functor, Allocator a, 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_a(mem_fn(f), functor, a); return true; } else { return false; @@ -480,41 +400,72 @@ namespace boost { #endif // BOOST_FUNCTION_NUM_ARGS > 0 // Function objects + template + void init(FunctionObj /*f*/, function_obj_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager::manage; + } + template + void init_a(FunctionObj /*f*/, function_obj_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager_a::manage; + } + // Assign to a function object using the small object optimization template void - assign_functor(const FunctionObj& f, function_buffer& functor, - mpl::true_) const + assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) { new ((void*)&functor.data) FunctionObj(f); } + template + void + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) + { + assign_functor(f,functor,mpl::true_()); + } // Assign to a function object allocated on the heap. template void - assign_functor(const FunctionObj& f, function_buffer& functor, - mpl::false_) const + assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) { -#ifndef BOOST_NO_STD_ALLOCATOR - 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 + } + template + void + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) + { + typedef functor_wrapper functor_wrapper_type; + typedef typename Allocator::template rebind::other + wrapper_allocator_type; + typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type; + wrapper_allocator_type wrapper_allocator(a); + wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); + wrapper_allocator.construct(copy, functor_wrapper_type(f,a)); + functor_wrapper_type* new_f = static_cast(copy); + functor.obj_ptr = new_f; } template bool - assign_to(const FunctionObj& f, function_buffer& functor, - function_obj_tag) const + assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor(f, functor, @@ -524,12 +475,45 @@ namespace boost { return false; } } + template + bool + assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) + { + if (!boost::detail::function::has_empty_target(boost::addressof(f))) { + assign_functor_a(f, functor, a, + mpl::bool_<(function_allows_small_object_optimization::value)>()); + return true; + } else { + return false; + } + } // Reference to a function object + template + void + init(const reference_wrapper& /*f*/, function_obj_ref_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &reference_manager::get; + } + template + void + init_a(const reference_wrapper& f, function_obj_ref_tag) + { + init(f,function_obj_ref_tag()); + } + template bool assign_to(const reference_wrapper& f, - function_buffer& functor, function_obj_ref_tag) const + function_buffer& functor, function_obj_ref_tag) { if (!boost::detail::function::has_empty_target(f.get_pointer())) { // DPG TBD: We might need to detect constness of @@ -542,9 +526,15 @@ namespace boost { return false; } } + template + bool + assign_to_a(const reference_wrapper& f, + function_buffer& functor, Allocator, function_obj_ref_tag) + { + return assign_to(f,functor,function_obj_ref_tag()); + } public: - vtable_base base; invoker_type invoker; }; } // end namespace function @@ -552,8 +542,7 @@ namespace boost { template< typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS, - typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR + BOOST_FUNCTION_TEMPLATE_PARMS > class BOOST_FUNCTION_FUNCTION : public function_base @@ -578,7 +567,7 @@ namespace boost { private: typedef boost::detail::function::BOOST_FUNCTION_VTABLE< - R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, Allocator> + R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS> vtable_type; struct clear_type {}; @@ -603,7 +592,6 @@ namespace boost { BOOST_STATIC_CONSTANT(int, arity = BOOST_FUNCTION_NUM_ARGS); BOOST_FUNCTION_ARG_TYPES - typedef Allocator allocator_type; typedef BOOST_FUNCTION_FUNCTION self_type; BOOST_FUNCTION_FUNCTION() : function_base() { } @@ -623,6 +611,19 @@ namespace boost { { this->assign_to(f); } + template + BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a +#ifndef BOOST_NO_SFINAE + ,typename enable_if_c< + (boost::type_traits::ice_not< + (is_integral::value)>::value), + int>::type = 0 +#endif // BOOST_NO_SFINAE + ) : + function_base() + { + this->assign_to_a(f,a); + } #ifndef BOOST_NO_SFINAE BOOST_FUNCTION_FUNCTION(clear_type*) : function_base() { } @@ -648,7 +649,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return static_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #else @@ -672,18 +673,25 @@ namespace boost { operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { this->clear(); -#ifndef BOOST_NO_EXCEPTIONS try { this->assign_to(f); } catch (...) { vtable = 0; throw; } -#else - this->assign_to(f); -#endif return *this; } + template + void assign(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a) + { + this->clear(); + try { + this->assign_to_a(f,a); + } catch (...) { + vtable = 0; + throw; + } + } #ifndef BOOST_NO_SFINAE BOOST_FUNCTION_FUNCTION& operator=(clear_type*) @@ -707,16 +715,12 @@ namespace boost { return *this; this->clear(); -#ifndef BOOST_NO_EXCEPTIONS try { this->assign_to_own(f); } catch (...) { vtable = 0; throw; } -#else - this->assign_to_own(f); -#endif return *this; } @@ -734,7 +738,7 @@ namespace boost { void clear() { if (vtable) { - reinterpret_cast(vtable)->clear(this->functor); + static_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -769,84 +773,64 @@ namespace boost { } template - void assign_to(const Functor& f) + void assign_to(Functor f) { - using detail::function::vtable_base; - - typedef typename detail::function::get_function_tag::type tag; - typedef detail::function::BOOST_FUNCTION_GET_INVOKER get_invoker; - typedef typename get_invoker:: - template apply - handler_type; - - typedef typename handler_type::invoker_type invoker_type; - typedef typename handler_type::manager_type manager_type; - - static const vtable_type stored_vtable = - { { &manager_type::manage }, &invoker_type::invoke }; - - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; + static vtable_type stored_vtable(f); + if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable; + else vtable = 0; + } + template + void assign_to_a(Functor f,Allocator a) + { + static vtable_type stored_vtable(f,a); + if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable; else vtable = 0; } }; - template + template inline void swap(BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator + BOOST_FUNCTION_TEMPLATE_ARGS >& f1, BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS, - Allocator + BOOST_FUNCTION_TEMPLATE_ARGS >& f2) { f1.swap(f2); } #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - template + template typename BOOST_FUNCTION_FUNCTION< - R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, - Allocator>::result_type - BOOST_FUNCTION_FUNCTION + R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type + BOOST_FUNCTION_FUNCTION ::operator()(BOOST_FUNCTION_PARMS) const { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return static_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif // Poison comparisons between boost::function objects of the same type. -template +template void operator==(const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&, + BOOST_FUNCTION_TEMPLATE_ARGS>&, const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&); -template + BOOST_FUNCTION_TEMPLATE_ARGS>&); +template void operator!=(const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&, + BOOST_FUNCTION_TEMPLATE_ARGS>&, const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&); + BOOST_FUNCTION_TEMPLATE_ARGS>& ); #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) @@ -857,20 +841,16 @@ template -class function - : public BOOST_FUNCTION_FUNCTION + BOOST_FUNCTION_TEMPLATE_PARMS> +class function + : public BOOST_FUNCTION_FUNCTION { - typedef BOOST_FUNCTION_FUNCTION base_type; + typedef BOOST_FUNCTION_FUNCTION base_type; typedef function self_type; struct clear_type {}; public: - typedef typename base_type::allocator_type allocator_type; function() : base_type() {} @@ -886,6 +866,18 @@ public: base_type(f) { } + template + function(Functor f, Allocator a +#ifndef BOOST_NO_SFINAE + ,typename enable_if_c< + (boost::type_traits::ice_not< + (is_integral::value)>::value), + int>::type = 0 +#endif + ) : + base_type(f,a) + { + } #ifndef BOOST_NO_SFINAE function(clear_type*) : base_type() {} @@ -938,8 +930,6 @@ public: // Cleanup after ourselves... #undef BOOST_FUNCTION_VTABLE -#undef BOOST_FUNCTION_GET_INVOKER -#undef BOOST_FUNCTION_DEFAULT_ALLOCATOR #undef BOOST_FUNCTION_COMMA #undef BOOST_FUNCTION_FUNCTION #undef BOOST_FUNCTION_FUNCTION_INVOKER @@ -948,12 +938,10 @@ public: #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_FUNCTION_REF_INVOKER #undef BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER -#undef BOOST_FUNCTION_MEMBER_INVOKER -#undef BOOST_FUNCTION_VOID_MEMBER_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER -#undef BOOST_FUNCTION_GET_MEMBER_INVOKER +#undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER #undef BOOST_FUNCTION_TEMPLATE_PARMS #undef BOOST_FUNCTION_TEMPLATE_ARGS #undef BOOST_FUNCTION_PARMS diff --git a/test/allocator_test.cpp b/test/allocator_test.cpp index 6411aec..7b35f16 100644 --- a/test/allocator_test.cpp +++ b/test/allocator_test.cpp @@ -27,6 +27,14 @@ struct counting_allocator : public std::allocator typedef counting_allocator other; }; + counting_allocator() + { + } + + template + counting_allocator( counting_allocator ) + { + } T* allocate(std::size_t n) { @@ -41,20 +49,27 @@ struct counting_allocator : public std::allocator } }; -struct plus_int +struct enable_small_object_optimization +{ +}; + +struct disable_small_object_optimization +{ + int unused_state_data[32]; +}; + +template +struct plus_int: base { int operator()(int x, int y) const { return x + y; } - - int unused_state_data[32]; }; static int do_minus(int x, int y) { return x-y; } -struct DoNothing +template +struct DoNothing: base { void operator()() const {} - - int unused_state_data[32]; }; static void do_nothing() {} @@ -62,33 +77,57 @@ static void do_nothing() {} int test_main(int, char*[]) { - function2 > f; - f = plus_int(); + function2 f; + f.assign( plus_int(), counting_allocator() ); f.clear(); BOOST_CHECK(alloc_count == 1); BOOST_CHECK(dealloc_count == 1); - alloc_count = 0; dealloc_count = 0; - f = &do_minus; + f.assign( plus_int(), counting_allocator() ); f.clear(); BOOST_CHECK(alloc_count == 0); BOOST_CHECK(dealloc_count == 0); + f.assign( plus_int(), std::allocator() ); + f.clear(); + f.assign( plus_int(), std::allocator() ); + f.clear(); - function0 > fv; alloc_count = 0; dealloc_count = 0; - fv = DoNothing(); + f.assign( &do_minus, counting_allocator() ); + f.clear(); + BOOST_CHECK(alloc_count == 0); + BOOST_CHECK(dealloc_count == 0); + f.assign( &do_minus, std::allocator() ); + f.clear(); + + function0 fv; + alloc_count = 0; + dealloc_count = 0; + fv.assign( DoNothing(), counting_allocator() ); fv.clear(); BOOST_CHECK(alloc_count == 1); BOOST_CHECK(dealloc_count == 1); - alloc_count = 0; dealloc_count = 0; - fv = &do_nothing; + fv.assign( DoNothing(), counting_allocator() ); fv.clear(); BOOST_CHECK(alloc_count == 0); BOOST_CHECK(dealloc_count == 0); + fv.assign( DoNothing(), std::allocator() ); + fv.clear(); + fv.assign( DoNothing(), std::allocator() ); + fv.clear(); + + alloc_count = 0; + dealloc_count = 0; + fv.assign( &do_nothing, counting_allocator() ); + fv.clear(); + BOOST_CHECK(alloc_count == 0); + BOOST_CHECK(dealloc_count == 0); + fv.assign( &do_nothing, std::allocator() ); + fv.clear(); return 0; }