From 0207da800890a267eb4b7a3f382a77f6cb79c178 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 21 Mar 2006 02:26:31 +0000 Subject: [PATCH 01/14] This commit was manufactured by cvs2svn to create branch 'RC_1_34_0'. [SVN r33417] From 0123f84bff81a4fe7399b9e50837b8f842e5c1fa Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 29 Sep 2006 17:23:17 +0000 Subject: [PATCH 02/14] Suppress annoying MSVC warnings [SVN r35423] --- include/boost/function/function_template.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 3aacea1..0568c07 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -70,6 +70,11 @@ # define BOOST_FUNCTION_RETURN(X) X; return BOOST_FUNCTION_VOID_RETURN_TYPE () #endif +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant. +#endif + namespace boost { namespace detail { namespace function { @@ -793,6 +798,10 @@ public: } // end namespace boost +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + // Cleanup after ourselves... #undef BOOST_FUNCTION_VTABLE #undef BOOST_FUNCTION_DEFAULT_ALLOCATOR From d92355cca295ac1a90c4fc2f44dd5b6d9c6f341c Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 29 Sep 2006 17:23:28 +0000 Subject: [PATCH 03/14] Suppress annoying MSVC warnings [SVN r35424] --- include/boost/function/function_template.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 0568c07..b6f786c 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -75,6 +75,11 @@ # pragma warning(disable: 4127) // conditional expression is constant. #endif +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant. +#endif + namespace boost { namespace detail { namespace function { @@ -793,6 +798,10 @@ public: } }; +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + #undef BOOST_FUNCTION_PARTIAL_SPEC #endif // have partial specialization From c7d5016022f2104a96d4690f56f6dafa428b0bdd Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Oct 2006 14:29:56 +0000 Subject: [PATCH 04/14] Eliminate MSVC 8.0 warning [SVN r35588] --- include/boost/function/function_base.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index ae83343..7165434 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -284,10 +284,8 @@ namespace boost { 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); // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. - out_functor->~Functor(); + reinterpret_cast(&out_buffer.data)->~Functor(); } else /* op == check_functor_type_tag */ { const std::type_info& check_type = *static_cast(out_buffer.const_obj_ptr); From 47033bd16232662149a247832305de075927ddae Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 3 Nov 2006 19:41:10 +0000 Subject: [PATCH 05/14] Fix inspection problems [SVN r35827] --- doc/Jamfile.v2 | 5 +++++ doc/faq.xml | 7 +++++++ doc/history.xml | 7 +++++++ doc/misc.xml | 7 +++++++ doc/reference.xml | 7 +++++++ doc/tests.xml | 7 +++++++ doc/tutorial.xml | 7 +++++++ index.html | 7 +++++++ 8 files changed, 54 insertions(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index a0f0612..8d76ce5 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,3 +1,8 @@ +# Copyright (c) 2002 Douglas Gregor + +# Distributed under 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) project boost/doc ; import boostbook : boostbook ; diff --git a/doc/faq.xml b/doc/faq.xml index 652b9cc..939de04 100644 --- a/doc/faq.xml +++ b/doc/faq.xml @@ -1,4 +1,11 @@ +
diff --git a/doc/history.xml b/doc/history.xml index f30db79..2af6dd6 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -1,4 +1,11 @@ +
diff --git a/doc/misc.xml b/doc/misc.xml index 29807de..840605d 100644 --- a/doc/misc.xml +++ b/doc/misc.xml @@ -1,4 +1,11 @@ +
diff --git a/doc/reference.xml b/doc/reference.xml index 8d69d7a..54b06e0 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -1,4 +1,11 @@ + diff --git a/doc/tests.xml b/doc/tests.xml index 0afa2a8..8f14173 100644 --- a/doc/tests.xml +++ b/doc/tests.xml @@ -1,4 +1,11 @@ + diff --git a/doc/tutorial.xml b/doc/tutorial.xml index 4732d62..d369392 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -1,4 +1,11 @@ +
+ From 2ecd62c61267dde709fda0eb0b81ccf0135ed4ca Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 6 Nov 2006 17:10:46 +0000 Subject: [PATCH 06/14] Remove obsolete Boost.Build v1 files. [SVN r35880] --- test/Jamfile | 68 ---------------------------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 test/Jamfile diff --git a/test/Jamfile b/test/Jamfile deleted file mode 100644 index 09d2d97..0000000 --- a/test/Jamfile +++ /dev/null @@ -1,68 +0,0 @@ -# Function library - -# Copyright (C) 2001-2003 Douglas Gregor - -# 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/ - - -# Testing Jamfile autogenerated from XML source -subproject libs/function/test ; - -# bring in rules for testing -SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; -include testing.jam ; - -# Make tests run by default. -DEPENDS all : test ; - -{ - # look in BOOST_ROOT for sources first, just in this Jamfile - local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ; - - test-suite function - : - [ run libs/function/test/function_test.cpp : : : : lib_function_test ] - - [ run libs/function/test/function_n_test.cpp : : : : ] - - [ run libs/function/test/allocator_test.cpp : : : : ] - - [ run libs/function/test/stateless_test.cpp : : : : ] - - [ run libs/function/test/lambda_test.cpp : : : : ] - - [ compile-fail libs/function/test/function_test_fail1.cpp : : : : ] - - [ compile-fail libs/function/test/function_test_fail2.cpp : : : : ] - - [ compile libs/function/test/function_30.cpp : : : : ] - - [ run libs/function/test/function_arith_cxx98.cpp : : : : ] - - [ run libs/function/test/function_arith_portable.cpp : : : : ] - - [ run libs/function/test/sum_avg_cxx98.cpp : : : : ] - - [ run libs/function/test/sum_avg_portable.cpp : : : : ] - - [ run libs/function/test/mem_fun_cxx98.cpp : : : : ] - - [ run libs/function/test/mem_fun_portable.cpp : : : : ] - - [ run libs/function/test/std_bind_cxx98.cpp : : : : ] - - [ run libs/function/test/std_bind_portable.cpp : : : : ] - - [ run libs/function/test/function_ref_cxx98.cpp : : : : ] - - [ run libs/function/test/function_ref_portable.cpp : : : : ] - - [ run libs/function/test/contains_test.cpp : : : : ] - - [ run libs/function/test/contains2_test.cpp : : : : ] - ; -} From 0b2aeda22676b3b87b86d6e4f864e8918b6cfa1c Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Tue, 7 Nov 2006 19:27:00 +0000 Subject: [PATCH 07/14] Merged copyright and license addition [SVN r35907] --- index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 96e751d..b7d40d2 100644 --- a/index.html +++ b/index.html @@ -11,6 +11,10 @@ Automatic redirection failed, please go to -../../doc/html/function.html +../../doc/html/function.html  
+

© Copyright Beman Dawes, 2001

+

Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy +at www.boost.org/LICENSE_1_0.txt)

- + \ No newline at end of file From 7581949360b6546137c3b041da090947937cd2bd Mon Sep 17 00:00:00 2001 From: Thomas Witt Date: Fri, 1 Jun 2007 16:12:08 +0000 Subject: [PATCH 08/14] Patches from Trac #583. [SVN r37846] --- include/boost/function.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/function.hpp b/include/boost/function.hpp index 1a5cca2..c3f3572 100644 --- a/include/boost/function.hpp +++ b/include/boost/function.hpp @@ -21,8 +21,8 @@ // in anything that may be included by function_template.hpp doesn't break #include -// Visual Age C++ doesn't handle the file iteration well -#if BOOST_WORKAROUND(__IBMCPP__, >= 500) +// Older versions of the IBM C++ compiler do not handle file iterations well +#if BOOST_WORKAROUND(__IBMCPP__, >= 500) && BOOST_WORKAROUND(__IBMCPP__, < 800) # if BOOST_FUNCTION_MAX_ARGS >= 0 # include # endif From 1b60e82b2fb142f9b9d7123ca20bb0be833b7c38 Mon Sep 17 00:00:00 2001 From: nobody Date: Tue, 24 Jul 2007 19:28:14 +0000 Subject: [PATCH 09/14] This commit was manufactured by cvs2svn to create tag 'Version_1_34_1'. [SVN r38286] From 6147e7ddcc76164a2295a56c05614800aeed1c49 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Fri, 5 Oct 2007 14:25:06 +0000 Subject: [PATCH 10/14] Starting point for releases [SVN r39706] From c4539395febcea4d528a00874ef89687119452fd Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Sun, 25 Nov 2007 18:07:19 +0000 Subject: [PATCH 11/14] Full merge from trunk at revision 41356 of entire boost-root tree. [SVN r41369] --- include/boost/function.hpp | 6 +- include/boost/function/detail/prologue.hpp | 1 + include/boost/function/function_base.hpp | 55 ++- include/boost/function/function_template.hpp | 335 +++++++++++++------ 4 files changed, 274 insertions(+), 123 deletions(-) diff --git a/include/boost/function.hpp b/include/boost/function.hpp index c3f3572..bdb2769 100644 --- a/include/boost/function.hpp +++ b/include/boost/function.hpp @@ -10,6 +10,8 @@ // William Kempf, Jesse Jones and Karl Nelson were all very helpful in the // design of this library. +#include // unary_function, binary_function + #include #include @@ -21,8 +23,8 @@ // in anything that may be included by function_template.hpp doesn't break #include -// Older versions of the IBM C++ compiler do not handle file iterations well -#if BOOST_WORKAROUND(__IBMCPP__, >= 500) && BOOST_WORKAROUND(__IBMCPP__, < 800) +// Visual Age C++ doesn't handle the file iteration well +#if BOOST_WORKAROUND(__IBMCPP__, >= 500) # if BOOST_FUNCTION_MAX_ARGS >= 0 # include # endif diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index 1ef5f6e..ab2b323 100644 --- a/include/boost/function/detail/prologue.hpp +++ b/include/boost/function/detail/prologue.hpp @@ -11,6 +11,7 @@ #define BOOST_FUNCTION_PROLOGUE_HPP # include # include +# include // unary_function, binary_function # include # include # include diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 7165434..6458765 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -30,6 +30,19 @@ #endif #include +#if defined(BOOST_MSVC) +# pragma warning( push ) +# pragma warning( disable : 4793 ) // complaint about native code generation +#endif + +// Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info. +#ifdef BOOST_NO_EXCEPTION_STD_NAMESPACE +// Embedded VC++ does not have type_info in namespace std +# define BOOST_FUNCTION_STD_NS +#else +# define BOOST_FUNCTION_STD_NS std +#endif + // Borrowed from Boost.Python library: determines the cases where we // need to use std::type_info::name to compare instead of operator==. # if (defined(__GNUC__) && __GNUC__ >= 3) \ @@ -59,7 +72,7 @@ namespace boost { namespace python { namespace objects { #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) + || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX #endif @@ -198,8 +211,8 @@ namespace boost { struct reference_manager { static inline void - get(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + manage(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { switch (op) { case clone_functor_tag: @@ -215,8 +228,8 @@ namespace boost { // 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); + 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(F))) out_buffer.obj_ptr = in_buffer.obj_ptr; else @@ -265,8 +278,8 @@ namespace boost { 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); + 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.func_ptr; else @@ -287,8 +300,8 @@ namespace boost { // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. reinterpret_cast(&out_buffer.data)->~Functor(); } else /* op == check_functor_type_tag */ { - const std::type_info& check_type = - *static_cast(out_buffer.const_obj_ptr); + 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.data; else @@ -348,8 +361,8 @@ namespace boost { # endif // BOOST_NO_STD_ALLOCATOR out_buffer.obj_ptr = 0; } else /* op == check_functor_type_tag */ { - const std::type_info& check_type = - *static_cast(out_buffer.const_obj_ptr); + 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 @@ -368,6 +381,15 @@ 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. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, member_ptr_tag) + { + manager(in_buffer, out_buffer, op, mpl::true_()); + } + public: /* Dispatch to an appropriate manager based on whether we have a function pointer or a function object pointer. */ @@ -456,7 +478,6 @@ 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); @@ -480,13 +501,13 @@ public: /** Retrieve the type of the stored function object, or typeid(void) if this is empty. */ - const std::type_info& target_type() const + const BOOST_FUNCTION_STD_NS::type_info& target_type() const { 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); + return *static_cast(type.const_obj_ptr); } template @@ -558,7 +579,7 @@ public: #endif public: // should be protected, but GCC 2.95.3 will fail to allow access - detail::function::vtable_base* vtable; + const detail::function::vtable_base* vtable; mutable detail::function::function_buffer functor; }; @@ -733,4 +754,8 @@ 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 b6f786c..536bac4 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -54,12 +54,20 @@ 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 @@ -70,16 +78,6 @@ # define BOOST_FUNCTION_RETURN(X) X; return BOOST_FUNCTION_VOID_RETURN_TYPE () #endif -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant. -#endif - -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant. -#endif - namespace boost { namespace detail { namespace function { @@ -191,6 +189,44 @@ 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 @@ -254,12 +290,130 @@ 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 : vtable_base + struct BOOST_FUNCTION_VTABLE { #ifndef BOOST_NO_VOID_RETURNS typedef R result_type; @@ -272,50 +426,25 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_ARGS); template - BOOST_FUNCTION_VTABLE(F f) : vtable_base(), invoker(0) - { - init(f); - } - - template - bool assign_to(F f, function_buffer& functor) + bool assign_to(const F& f, function_buffer& functor) const { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); } - void clear(function_buffer& functor) + void clear(function_buffer& functor) const { - if (manager) - manager(functor, functor, destroy_functor_tag); + if (base.manager) + base.manager(functor, functor, destroy_functor_tag); } - +#ifndef BOOST_NO_PRIVATE_IN_AGGREGATE private: - template - void init(F f) - { - typedef typename get_function_tag::type tag; - init(f, tag()); - } - +#endif // 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 bool - assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) + assign_to(FunctionPtr f, function_buffer& functor, + function_ptr_tag) const { this->clear(functor); if (f) { @@ -331,22 +460,13 @@ namespace boost { // Member pointers #if BOOST_FUNCTION_NUM_ARGS > 0 template - void init(MemberPtr f, member_ptr_tag) + bool + assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) const { - // 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, 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); + // Always use the small-object optimization for member + // pointers. + assign_functor(f, functor, mpl::true_()); return true; } else { return false; @@ -355,24 +475,11 @@ 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; - } - // Assign to a function object using the small object optimization template void - assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) + assign_functor(const FunctionObj& f, function_buffer& functor, + mpl::true_) const { new ((void*)&functor.data) FunctionObj(f); } @@ -380,7 +487,8 @@ namespace boost { // Assign to a function object allocated on the heap. template void - assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) + assign_functor(const FunctionObj& f, function_buffer& functor, + mpl::false_) const { #ifndef BOOST_NO_STD_ALLOCATOR typedef typename Allocator::template rebind::other @@ -400,7 +508,8 @@ namespace boost { template bool - assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) + assign_to(const FunctionObj& f, function_buffer& functor, + function_obj_tag) const { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor(f, functor, @@ -412,25 +521,10 @@ namespace boost { } // 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 bool assign_to(const reference_wrapper& f, - function_buffer& functor, function_obj_ref_tag) + function_buffer& functor, function_obj_ref_tag) const { if (!boost::detail::function::has_empty_target(f.get_pointer())) { // DPG TBD: We might need to detect constness of @@ -445,6 +539,7 @@ namespace boost { } public: + vtable_base base; invoker_type invoker; }; } // end namespace function @@ -456,6 +551,17 @@ namespace boost { typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR > class BOOST_FUNCTION_FUNCTION : public function_base + +#if BOOST_FUNCTION_NUM_ARGS == 1 + + , public std::unary_function + +#elif BOOST_FUNCTION_NUM_ARGS == 2 + + , public std::binary_function + +#endif + { public: #ifndef BOOST_NO_VOID_RETURNS @@ -537,7 +643,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return static_cast(vtable)->invoker + return reinterpret_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #else @@ -561,12 +667,16 @@ 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; } @@ -592,12 +702,16 @@ 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; } @@ -615,7 +729,7 @@ namespace boost { void clear() { if (vtable) { - static_cast(vtable)->clear(this->functor); + reinterpret_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -650,10 +764,24 @@ namespace boost { } template - void assign_to(Functor f) + void assign_to(const Functor& f) { - static vtable_type stored_vtable(f); - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable; + 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; else vtable = 0; } }; @@ -688,7 +816,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return static_cast(vtable)->invoker + return reinterpret_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif @@ -798,21 +926,14 @@ public: } }; -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - #undef BOOST_FUNCTION_PARTIAL_SPEC #endif // have partial specialization } // end namespace boost -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - // 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 @@ -822,10 +943,12 @@ 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_MEM_FUNCTION_INVOKER +#undef BOOST_FUNCTION_GET_MEMBER_INVOKER #undef BOOST_FUNCTION_TEMPLATE_PARMS #undef BOOST_FUNCTION_TEMPLATE_ARGS #undef BOOST_FUNCTION_PARMS From bfdb5b161dd90a60440aa9417be5a99f8631e9e1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 14 Dec 2007 14:48:14 +0000 Subject: [PATCH 12/14] Merged fixes for Function, Signals, and MPI from trunk. See #1499, see #1416, see #1486 [SVN r42031] --- include/boost/function/function_base.hpp | 1 + include/boost/function/function_template.hpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 6458765..aa7376a 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -33,6 +33,7 @@ #if defined(BOOST_MSVC) # pragma warning( push ) # pragma warning( disable : 4793 ) // complaint about native code generation +# pragma warning( disable : 4127 ) // "conditional expression is constant" #endif // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info. diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 536bac4..ab5c643 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -11,6 +11,11 @@ // protection. #include +#if defined(BOOST_MSVC) +# pragma warning( push ) +# pragma warning( disable : 4127 ) // "conditional expression is constant" +#endif + #define BOOST_FUNCTION_TEMPLATE_PARMS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, typename T) #define BOOST_FUNCTION_TEMPLATE_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, T) @@ -958,3 +963,7 @@ public: #undef BOOST_FUNCTION_ARG_TYPES #undef BOOST_FUNCTION_VOID_RETURN_TYPE #undef BOOST_FUNCTION_RETURN + +#if defined(BOOST_MSVC) +# pragma warning( pop ) +#endif From 83309a36c7627e44917ecc3b7bbb57979ae550c8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 14 Jul 2008 18:32:29 +0000 Subject: [PATCH 13/14] Merge Boost.Function from the trunk [SVN r47422] --- doc/history.xml | 16 + doc/misc.xml | 6 +- doc/reference.xml | 118 ++-- include/boost/function/detail/prologue.hpp | 3 +- include/boost/function/function_base.hpp | 212 ++++--- include/boost/function/function_template.hpp | 552 +++++++++---------- test/allocator_test.cpp | 67 ++- 7 files changed, 542 insertions(+), 432 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/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; } From 587658b047716dcdb33ef04fba8cc69324396e81 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 16 Oct 2008 13:21:50 +0000 Subject: [PATCH 14/14] Merge Boost.Function fixes from trunk [SVN r49361] --- doc/history.xml | 20 + include/boost/function/function_base.hpp | 178 +++++--- include/boost/function/function_fwd.hpp | 70 +++ include/boost/function/function_template.hpp | 445 +++++++++++++------ include/boost/function/function_typeof.hpp | 45 ++ test/Jamfile.v2 | 3 + test/contains_test.cpp | 9 + test/function_n_test.cpp | 49 ++ test/function_typeof_test.cpp | 18 + test/nothrow_swap.cpp | 60 +++ 10 files changed, 696 insertions(+), 201 deletions(-) create mode 100644 include/boost/function/function_fwd.hpp create mode 100644 include/boost/function/function_typeof.hpp create mode 100644 test/function_typeof_test.cpp create mode 100644 test/nothrow_swap.cpp diff --git a/doc/history.xml b/doc/history.xml index eb5a442..05fddf8 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -13,6 +13,26 @@ + Version 1.37.0: + + Improved the performance of Boost.Function's + swap() operation for large function objects. Original patch + contributed by Niels Dekker. + + Added a new header <boost/function/function_typeof.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects. + + Added a new header <boost/function/function_fwd.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects. + + The target() + function now respects the cv-qualifiers of function objects + stored by reference + (using boost::reference_wrapper), such + that a reference to a const function object cannot + be accessed as a reference to a non-const function + object. + + + Version 1.36.0: Boost.Function now implements allocator support diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 8d46711..6612fb8 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -18,8 +18,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -30,6 +33,7 @@ # include "boost/mpl/bool.hpp" #endif #include +#include #if defined(BOOST_MSVC) # pragma warning( push ) @@ -63,22 +67,7 @@ # define BOOST_FUNCTION_TARGET_FIX(x) #endif // not MSVC -#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) -// Work around a compiler bug. -// boost::python::objects::function has to be seen by the compiler before the -// boost::function class template. -namespace boost { namespace python { namespace objects { - class function; -}}} -#endif - -#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ - || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) -# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX -#endif - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0) # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \ (::boost::is_integral::value)>::value), \ @@ -92,22 +81,6 @@ namespace boost { namespace python { namespace objects { Type>::type #endif -#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) -namespace boost { - -template -class function; - -template -inline void swap(function& f1, - function& f2) -{ - f1.swap(f2); -} - -} // end namespace boost -#endif // have partial specialization - namespace boost { namespace detail { namespace function { @@ -122,11 +95,18 @@ namespace boost { union function_buffer { // For pointers to function objects - void* obj_ptr; + mutable void* obj_ptr; // For pointers to std::type_info objects - // (get_functor_type_tag, check_functor_type_tag). - const void* const_obj_ptr; + struct type_t { + // (get_functor_type_tag, check_functor_type_tag). + const BOOST_FUNCTION_STD_NS::type_info* type; + + // Whether the type is const-qualified. + bool const_qualified; + // Whether the type is volatile-qualified. + bool volatile_qualified; + } type; // For function pointers of all kinds mutable void (*func_ptr)(); @@ -137,6 +117,14 @@ namespace boost { void* obj_ptr; } bound_memfunc_ptr; + // For references to function objects. We explicitly keep + // track of the cv-qualifiers on the object referenced. + struct obj_ref_t { + mutable void* obj_ptr; + bool is_const_qualified; + bool is_volatile_qualified; + } obj_ref; + // To relax aliasing constraints mutable char data; }; @@ -168,6 +156,7 @@ namespace boost { // The operation type to perform on the given functor/function pointer enum functor_manager_operation_type { clone_functor_tag, + move_functor_tag, destroy_functor_tag, check_functor_type_tag, get_functor_type_tag @@ -204,34 +193,45 @@ namespace boost { struct reference_manager { static inline void - get(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + manage(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { switch (op) { case clone_functor_tag: - out_buffer.obj_ptr = in_buffer.obj_ptr; + out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + return; + + case move_functor_tag: + out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + in_buffer.obj_ref.obj_ptr = 0; return; case destroy_functor_tag: - out_buffer.obj_ptr = 0; + out_buffer.obj_ref.obj_ptr = 0; return; case check_functor_type_tag: { - // 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 BOOST_FUNCTION_STD_NS::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; + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; + + // Check whether we have the same type. We can add + // cv-qualifiers, but we can't take them away. + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)) + && (!in_buffer.obj_ref.is_const_qualified + || out_buffer.type.const_qualified) + && (!in_buffer.obj_ref.is_volatile_qualified + || out_buffer.type.volatile_qualified)) + out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr; else out_buffer.obj_ptr = 0; } return; case get_functor_type_tag: - out_buffer.const_obj_ptr = &typeid(F); + out_buffer.type.type = &typeid(F); + out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified; + out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified; return; } } @@ -277,15 +277,22 @@ namespace boost { { if (op == clone_functor_tag) out_buffer.func_ptr = in_buffer.func_ptr; - else if (op == destroy_functor_tag) + else if (op == move_functor_tag) { + out_buffer.func_ptr = in_buffer.func_ptr; + in_buffer.func_ptr = 0; + } else if (op == destroy_functor_tag) out_buffer.func_ptr = 0; - else /* op == check_functor_type_tag */ { - const BOOST_FUNCTION_STD_NS::type_info& check_type = - *static_cast(out_buffer.const_obj_ptr); + else if (op == check_functor_type_tag) { + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) out_buffer.obj_ptr = &in_buffer.func_ptr; else out_buffer.obj_ptr = 0; + } else /* op == get_functor_type_tag */ { + out_buffer.type.type = &typeid(Functor); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; } } @@ -294,20 +301,28 @@ namespace boost { manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, functor_manager_operation_type op) { - if (op == clone_functor_tag) { + if (op == clone_functor_tag || op == move_functor_tag) { const functor_type* in_functor = reinterpret_cast(&in_buffer.data); new ((void*)&out_buffer.data) functor_type(*in_functor); + + if (op == move_functor_tag) { + reinterpret_cast(&in_buffer.data)->~Functor(); + } } else if (op == destroy_functor_tag) { // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. reinterpret_cast(&out_buffer.data)->~Functor(); - } else /* op == check_functor_type_tag */ { - const BOOST_FUNCTION_STD_NS::type_info& check_type = - *static_cast(out_buffer.const_obj_ptr); + } else if (op == check_functor_type_tag) { + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) out_buffer.obj_ptr = &in_buffer.data; else out_buffer.obj_ptr = 0; + } else /* op == get_functor_type_tag */ { + out_buffer.type.type = &typeid(Functor); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; } } }; @@ -347,19 +362,26 @@ namespace boost { (const functor_type*)(in_buffer.obj_ptr); functor_type* new_f = new functor_type(*f); out_buffer.obj_ptr = new_f; + } else if (op == move_functor_tag) { + out_buffer.obj_ptr = in_buffer.obj_ptr; + in_buffer.obj_ptr = 0; } 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); delete f; 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); + } else if (op == check_functor_type_tag) { + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) out_buffer.obj_ptr = in_buffer.obj_ptr; else out_buffer.obj_ptr = 0; + } else /* op == get_functor_type_tag */ { + out_buffer.type.type = &typeid(Functor); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; } } @@ -374,6 +396,14 @@ namespace boost { mpl::bool_<(function_allows_small_object_optimization::value)>()); } + // For member pointers, we use the small-object optimization buffer. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, member_ptr_tag) + { + manager(in_buffer, out_buffer, op, mpl::true_()); + } + public: /* Dispatch to an appropriate manager based on whether we have a function pointer or a function object pointer. */ @@ -384,7 +414,9 @@ namespace boost { typedef typename get_function_tag::type tag_type; switch (op) { case get_functor_type_tag: - out_buffer.const_obj_ptr = &typeid(functor_type); + out_buffer.type.type = &typeid(functor_type); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; return; default: @@ -439,6 +471,9 @@ namespace boost { // Get back to the original pointer type functor_wrapper_type* new_f = static_cast(copy); out_buffer.obj_ptr = new_f; + } else if (op == move_functor_tag) { + out_buffer.obj_ptr = in_buffer.obj_ptr; + in_buffer.obj_ptr = 0; } else if (op == destroy_functor_tag) { /* Cast from the void pointer to the functor_wrapper_type */ functor_wrapper_type* victim = @@ -447,13 +482,17 @@ namespace boost { 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); + } else if (op == check_functor_type_tag) { + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) out_buffer.obj_ptr = in_buffer.obj_ptr; else out_buffer.obj_ptr = 0; + } else /* op == get_functor_type_tag */ { + out_buffer.type.type = &typeid(Functor); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; } } @@ -478,7 +517,9 @@ namespace boost { typedef typename get_function_tag::type tag_type; switch (op) { case get_functor_type_tag: - out_buffer.const_obj_ptr = &typeid(functor_type); + out_buffer.type.type = &typeid(functor_type); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; return; default: @@ -556,7 +597,6 @@ 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); @@ -586,7 +626,7 @@ public: detail::function::function_buffer type; vtable->manager(functor, type, detail::function::get_functor_type_tag); - return *static_cast(type.const_obj_ptr); + return *type.type.type; } template @@ -595,7 +635,9 @@ public: if (!vtable) return 0; detail::function::function_buffer type_result; - type_result.const_obj_ptr = &typeid(Functor); + type_result.type.type = &typeid(Functor); + type_result.type.const_qualified = is_const::value; + type_result.type.volatile_qualified = is_volatile::value; vtable->manager(functor, type_result, detail::function::check_functor_type_tag); return static_cast(type_result.obj_ptr); @@ -611,7 +653,9 @@ public: if (!vtable) return 0; detail::function::function_buffer type_result; - type_result.const_obj_ptr = &typeid(Functor); + type_result.type.type = &typeid(Functor); + type_result.type.const_qualified = true; + type_result.type.volatile_qualified = is_volatile::value; vtable->manager(functor, type_result, detail::function::check_functor_type_tag); // GCC 2.95.3 gets the CV qualifiers wrong here, so we diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp new file mode 100644 index 0000000..d2f713a --- /dev/null +++ b/include/boost/function/function_fwd.hpp @@ -0,0 +1,70 @@ +// Boost.Function library +// Copyright (C) Douglas Gregor 2008 +// +// 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 +#ifndef BOOST_FUNCTION_FWD_HPP +#define BOOST_FUNCTION_FWD_HPP +#include + +#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) +// Work around a compiler bug. +// boost::python::objects::function has to be seen by the compiler before the +// boost::function class template. +namespace boost { namespace python { namespace objects { + class function; +}}} +#endif + +#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ + || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) +# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX +#endif + +namespace boost { + class bad_function_call; + +#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) + // Preferred syntax + template class function; + + template + inline void swap(function& f1, function& f2) + { + f1.swap(f2); + } +#endif // have partial specialization + + // Portable syntax + template class function0; + template class function1; + template class function2; + template class function3; + template + class function4; + template + class function5; + template + class function6; + template + class function7; + template + class function8; + template + class function9; + template + class function10; +} + +#endif diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index a575ebf..584abe9 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -53,12 +53,20 @@ 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(function_mem_invoker,BOOST_FUNCTION_NUM_ARGS) +#define BOOST_FUNCTION_VOID_MEMBER_INVOKER \ + BOOST_JOIN(function_void_mem_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 @@ -180,6 +188,44 @@ 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 @@ -243,11 +289,190 @@ 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; + }; + + template + struct apply_a + { + 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; + }; + + template + struct apply_a + { + 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; + }; + + template + struct apply_a + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + invoker_type; + + typedef functor_manager_a 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; + }; + + template + struct apply_a + { + 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. + * vtable for a specific boost::function instance. This + * structure must be an aggregate so that we can use static + * initialization in boost::function's assign_to and assign_to_a + * members. It therefore cannot have any constructors, + * destructors, base classes, etc. */ template - struct BOOST_FUNCTION_VTABLE : vtable_base + struct BOOST_FUNCTION_VTABLE { #ifndef BOOST_NO_VOID_RETURNS typedef R result_type; @@ -259,17 +484,6 @@ namespace boost { BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS); - template - 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) { @@ -285,52 +499,12 @@ namespace boost { void clear(function_buffer& functor) { - if (manager) - manager(functor, functor, destroy_functor_tag); + if (base.manager) + base.manager(functor, functor, destroy_functor_tag); } private: - 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) @@ -354,23 +528,6 @@ namespace boost { // Member pointers #if BOOST_FUNCTION_NUM_ARGS > 0 - 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 - 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) { @@ -400,33 +557,6 @@ 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 @@ -489,38 +619,15 @@ namespace boost { } // 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) { if (!boost::detail::function::has_empty_target(f.get_pointer())) { - // 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(); + functor.obj_ref.obj_ptr = (void *)f.get_pointer(); + functor.obj_ref.is_const_qualified = is_const::value; + functor.obj_ref.is_volatile_qualified = is_volatile::value; return true; } else { return false; @@ -535,6 +642,7 @@ namespace boost { } public: + vtable_base base; invoker_type invoker; }; } // end namespace function @@ -729,16 +837,17 @@ namespace boost { if (&other == this) return; - BOOST_FUNCTION_FUNCTION tmp = *this; - *this = other; - other = tmp; + BOOST_FUNCTION_FUNCTION tmp; + tmp.move_assign(*this); + this->move_assign(other); + other.move_assign(tmp); } // Clear out a target, if there is one void clear() { if (vtable) { - static_cast(vtable)->clear(this->functor); + reinterpret_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -775,17 +884,82 @@ namespace boost { template void assign_to(Functor f) { - static vtable_type stored_vtable(f); - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable; + 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; + + // Note: it is extremely important that this initialization use + // static initialization. Otherwise, we will have a race + // condition here in multi-threaded code. See + // http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/. + static vtable_type stored_vtable = + { { &manager_type::manage }, &invoker_type::invoke }; + + if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; else vtable = 0; } + 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; + 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_a + handler_type; + + typedef typename handler_type::invoker_type invoker_type; + typedef typename handler_type::manager_type manager_type; + + // Note: it is extremely important that this initialization use + // static initialization. Otherwise, we will have a race + // condition here in multi-threaded code. See + // http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/. + static vtable_type stored_vtable = + { { &manager_type::manage }, &invoker_type::invoke }; + + if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base; else vtable = 0; } + + // Moves the value from the specified argument to *this. If the argument + // has its function object allocated on the heap, move_assign will pass + // its buffer to *this, and set the argument's buffer pointer to NULL. + void move_assign(BOOST_FUNCTION_FUNCTION& f) + { + if (&f == this) + return; + +#if !defined(BOOST_NO_EXCEPTIONS) + try { +#endif + if (!f.empty()) { + this->vtable = f.vtable; + f.vtable->manager(f.functor, this->functor, + boost::detail::function::move_functor_tag); + f.vtable = 0; +#if !defined(BOOST_NO_EXCEPTIONS) + } else { + clear(); + } + } catch (...) { + vtable = 0; + throw; + } +#endif + } }; template @@ -811,7 +985,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return static_cast(vtable)->invoker + return reinterpret_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif @@ -938,10 +1112,13 @@ 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_MEM_FUNCTION_INVOKER +#undef BOOST_FUNCTION_GET_INVOKER #undef BOOST_FUNCTION_TEMPLATE_PARMS #undef BOOST_FUNCTION_TEMPLATE_ARGS #undef BOOST_FUNCTION_PARMS diff --git a/include/boost/function/function_typeof.hpp b/include/boost/function/function_typeof.hpp new file mode 100644 index 0000000..246dc15 --- /dev/null +++ b/include/boost/function/function_typeof.hpp @@ -0,0 +1,45 @@ +// Boost.Function library - Typeof support +// Copyright (C) Douglas Gregor 2008 +// +// 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 +#ifndef BOOST_FUNCTION_TYPEOF_HPP +#define BOOST_FUNCTION_TYPEOF_HPP +#include +#include + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TYPE(boost::bad_function_call) + +#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function, (typename)) +#endif + +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function0, (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function1, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function2, (typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function3, + (typename)(typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function4, + (typename)(typename)(typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function5, + (typename)(typename)(typename)(typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function6, + (typename)(typename)(typename)(typename)(typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function7, + (typename)(typename)(typename)(typename)(typename)(typename)(typename) + (typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function8, + (typename)(typename)(typename)(typename)(typename)(typename)(typename) + (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function9, + (typename)(typename)(typename)(typename)(typename)(typename)(typename) + (typename)(typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function10, + (typename)(typename)(typename)(typename)(typename)(typename)(typename) + (typename)(typename)(typename)(typename)) +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8ab92b1..ef4e0d1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -58,6 +58,9 @@ import testing ; [ run libs/function/test/contains2_test.cpp : : : : ] + [ run libs/function/test/nothrow_swap.cpp : : : : ] + + [ compile libs/function/test/function_typeof_test.cpp ] ; } diff --git a/test/contains_test.cpp b/test/contains_test.cpp index 31963c0..fa11559 100644 --- a/test/contains_test.cpp +++ b/test/contains_test.cpp @@ -88,6 +88,15 @@ static void target_test() BOOST_CHECK(!f.target()); BOOST_CHECK(f.target()); BOOST_CHECK(f.target() == &this_seventeen); + + const Seventeen const_seventeen = this_seventeen; + f = boost::ref(const_seventeen); + BOOST_CHECK(!f.target()); + BOOST_CHECK(f.target()); + BOOST_CHECK(f.target() == &const_seventeen); + BOOST_CHECK(f.target()); + BOOST_CHECK(!f.target()); + BOOST_CHECK(!f.target()); } static void equal_test() diff --git a/test/function_n_test.cpp b/test/function_n_test.cpp index 14439a8..cdd7145 100644 --- a/test/function_n_test.cpp +++ b/test/function_n_test.cpp @@ -636,6 +636,54 @@ test_ref() } } +static unsigned construction_count = 0; +static unsigned destruction_count = 0; + +struct MySmallFunctor { + MySmallFunctor() { ++construction_count; } + MySmallFunctor(const MySmallFunctor &) { ++construction_count; } + ~MySmallFunctor() { ++destruction_count; } + int operator()() { return 0; } + }; + +struct MyLargeFunctor { + MyLargeFunctor() { ++construction_count; } + MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; } + ~MyLargeFunctor() { ++destruction_count; } + int operator()() { return 0; } + + float data[128]; + }; + +void test_construct_destroy_count() +{ + { + boost::function0 f; + boost::function0 g; + f = MySmallFunctor(); + g = MySmallFunctor(); + f.swap(g); + } + + // MySmallFunctor objects should be constructed as many times as + // they are destroyed. + BOOST_CHECK(construction_count == destruction_count); + + construction_count = 0; + destruction_count = 0; + { + boost::function0 f; + boost::function0 g; + f = MyLargeFunctor(); + g = MyLargeFunctor(); + f.swap(g); + } + + // MyLargeFunctor objects should be constructed as many times as + // they are destroyed. + BOOST_CHECK(construction_count == destruction_count); +} + int test_main(int, char* []) { test_zero_args(); @@ -644,5 +692,6 @@ int test_main(int, char* []) test_emptiness(); test_member_functions(); test_ref(); + test_construct_destroy_count(); return 0; } diff --git a/test/function_typeof_test.cpp b/test/function_typeof_test.cpp new file mode 100644 index 0000000..2d77cab --- /dev/null +++ b/test/function_typeof_test.cpp @@ -0,0 +1,18 @@ +// Boost.Function library + +// Copyright Douglas Gregor 2008. 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 +#include +#include +#include +#include +#include + +void f(boost::function0 f, boost::function0 g) +{ + BOOST_STATIC_ASSERT((boost::is_same, BOOST_TYPEOF(f = g)>::value)); +} diff --git a/test/nothrow_swap.cpp b/test/nothrow_swap.cpp new file mode 100644 index 0000000..0a5b740 --- /dev/null +++ b/test/nothrow_swap.cpp @@ -0,0 +1,60 @@ +// Boost.Function library + +// Copyright Douglas Gregor 2008. 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 + +#include +#include + +struct tried_to_copy { }; + +struct MaybeThrowOnCopy { + MaybeThrowOnCopy(int value = 0) : value(value) { } + + MaybeThrowOnCopy(const MaybeThrowOnCopy& other) : value(other.value) { + if (throwOnCopy) + throw tried_to_copy(); + } + + MaybeThrowOnCopy& operator=(const MaybeThrowOnCopy& other) { + if (throwOnCopy) + throw tried_to_copy(); + value = other.value; + return *this; + } + + int operator()() { return value; } + + int value; + + // Make sure that this function object doesn't trigger the + // small-object optimization in Function. + float padding[100]; + + static bool throwOnCopy; +}; + +bool MaybeThrowOnCopy::throwOnCopy = false; + +int test_main(int, char* []) +{ + boost::function0 f; + boost::function0 g; + + MaybeThrowOnCopy::throwOnCopy = false; + f = MaybeThrowOnCopy(1); + g = MaybeThrowOnCopy(2); + BOOST_CHECK(f() == 1); + BOOST_CHECK(g() == 2); + + MaybeThrowOnCopy::throwOnCopy = true; + f.swap(g); + BOOST_CHECK(f() == 2); + BOOST_CHECK(g() == 1); + + return 0; +}