From 8026bc49d7f5be2cd3ca65a5304b8aad897f55db Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Fri, 28 Mar 2008 14:52:50 +0000 Subject: [PATCH] Merged revisions 43810-43907 via svnmerge from https://svn.boost.org/svn/boost/trunk ................ r43810 | eric_niebler | 2008-03-23 14:51:40 -0700 (Sun, 23 Mar 2008) | 1 line mark up new foreach tests ................ r43823 | fmhess | 2008-03-24 08:07:00 -0700 (Mon, 24 Mar 2008) | 3 lines Fixed compile error with new enable_shared_from_this code, reported by Tim Blechmann ................ r43825 | ramey | 2008-03-24 08:46:09 -0700 (Mon, 24 Mar 2008) | 1 line removed EXIT_SUCCESS ................ r43826 | ramey | 2008-03-24 08:46:43 -0700 (Mon, 24 Mar 2008) | 1 line fixed minor typo ................ r43829 | pdimov | 2008-03-24 09:00:28 -0700 (Mon, 24 Mar 2008) | 1 line New enable_shared_from_this tests, fix. ................ r43838 | danieljames | 2008-03-24 10:03:15 -0700 (Mon, 24 Mar 2008) | 12 lines Merge new changes to unordered & hash. - Unordered tests can run lightweight test or Boost.Test (at least theoretically). - Workaround Open BSD's incorrect numeric_limits. - Move the hash extensions in their own file. - Various small improvements to the unordered docs. - Fix some unordered examples. Merged revisions 43117-43837 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r43845 | dave | 2008-03-24 11:27:22 -0700 (Mon, 24 Mar 2008) | 1 line Work around vc9 bugs ................ r43847 | anthonyw | 2008-03-24 14:44:36 -0700 (Mon, 24 Mar 2008) | 1 line removed forward declaration for undefined type exclusive_lock ................ r43852 | hkaiser | 2008-03-25 06:40:53 -0700 (Tue, 25 Mar 2008) | 1 line Wave: Removed an assertion causing compilation problems on certain platforms. ................ r43856 | pdimov | 2008-03-25 08:46:40 -0700 (Tue, 25 Mar 2008) | 1 line _internal_accept_owner now checks if _owned isn't already true. ................ r43861 | dave | 2008-03-25 13:47:38 -0700 (Tue, 25 Mar 2008) | 2 lines Work around intel-10.0-win compiler bug ................ r43864 | dave | 2008-03-25 15:28:59 -0700 (Tue, 25 Mar 2008) | 2 lines Account for intel 10.x compiler bug ................ r43865 | dave | 2008-03-25 16:06:50 -0700 (Tue, 25 Mar 2008) | 2 lines Work around intel-win-10.0 preprocessor bug ................ r43866 | danieljames | 2008-03-26 02:10:29 -0700 (Wed, 26 Mar 2008) | 3 lines Boost.Thread's documentation no longer has a build section - so just link to the library's documentation like we do for other libraries. ................ r43867 | bemandawes | 2008-03-26 08:59:52 -0700 (Wed, 26 Mar 2008) | 1 line Initial commit ................ r43873 | pdimov | 2008-03-26 11:34:29 -0700 (Wed, 26 Mar 2008) | 1 line Added "Throws: nothing" to get_deleter. ................ r43875 | bemandawes | 2008-03-26 14:26:55 -0700 (Wed, 26 Mar 2008) | 1 line Initial commit ................ r43876 | danieljames | 2008-03-26 22:49:45 -0700 (Wed, 26 Mar 2008) | 2 lines Update the thread links in the generated getting started documentation. ................ r43879 | chris_kohlhoff | 2008-03-27 07:18:07 -0700 (Thu, 27 Mar 2008) | 3 lines Fix double-free error that occurs when an exception is thrown from a handler that has been dispatched (i.e. not posted) through a strand. ................ r43880 | ramey | 2008-03-27 08:53:37 -0700 (Thu, 27 Mar 2008) | 1 line removed suppression of builds for certain platforms with shared libraries ................ r43882 | ramey | 2008-03-27 10:11:23 -0700 (Thu, 27 Mar 2008) | 1 line tweaks to sneak past PGI compiler error message ................ r43883 | ramey | 2008-03-27 10:12:22 -0700 (Thu, 27 Mar 2008) | 1 line added test to check warnings on type trait ................ r43884 | dgregor | 2008-03-27 12:44:37 -0700 (Thu, 27 Mar 2008) | 1 line Change Boost.Function allocator behavior, from Emil Dotchevski ................ r43887 | pdimov | 2008-03-27 15:13:55 -0700 (Thu, 27 Mar 2008) | 1 line Silence unused parameter warning. ................ r43888 | pdimov | 2008-03-27 15:20:11 -0700 (Thu, 27 Mar 2008) | 1 line detail::yield(k) added. ................ r43895 | danieljames | 2008-03-27 16:38:01 -0700 (Thu, 27 Mar 2008) | 25 lines Merged revisions 43838-43894 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ........ r43840 | danieljames | 2008-03-24 17:25:07 +0000 (Mon, 24 Mar 2008) | 1 line Fix a g++ warning. ........ r43844 | danieljames | 2008-03-24 17:56:28 +0000 (Mon, 24 Mar 2008) | 1 line It's a new-ish year. ........ r43885 | danieljames | 2008-03-27 20:36:10 +0000 (Thu, 27 Mar 2008) | 1 line The release script doesn't need to copy images and css - because that's now done in the jamfiles. Also tweak the shell script a tad bit. ........ r43890 | danieljames | 2008-03-27 23:01:40 +0000 (Thu, 27 Mar 2008) | 1 line Starting to add a docbook bibliography. ........ r43894 | danieljames | 2008-03-27 23:24:18 +0000 (Thu, 27 Mar 2008) | 1 line Redeclare 'data' in iterator_base to help compilers which have trouble with accessing the nested typedef. ........ ................ r43900 | noel_belcourt | 2008-03-27 19:10:04 -0700 (Thu, 27 Mar 2008) | 4 lines Fix address-model support for 32/64 bit code generation. Replaced -mcmodel with -m32 / -m64. ................ r43901 | bemandawes | 2008-03-27 19:11:13 -0700 (Thu, 27 Mar 2008) | 1 line Remove per email from Dave ................ r43906 | eric_niebler | 2008-03-27 23:10:55 -0700 (Thu, 27 Mar 2008) | 1 line proto support for BOOST_PROTO_MAX_FUNCTION_CALL_ARITY ................ [SVN r43910] --- doc/history.xml | 16 + doc/reference.xml | 118 ++-- include/boost/function/function_base.hpp | 212 ++++--- include/boost/function/function_template.hpp | 552 +++++++++---------- test/allocator_test.cpp | 67 ++- 5 files changed, 537 insertions(+), 428 deletions(-) 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/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/function_base.hpp b/include/boost/function/function_base.hpp index aa7376a..7d667ae 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; }