From 872f12efeeae9f4d721ea412f34d4d14a2ea2f08 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 8 Jul 2006 18:07:33 +0000 Subject: [PATCH 01/65] TR1 conformance: derive from unary_function/binary_function [SVN r34481] --- include/boost/function/detail/prologue.hpp | 1 + include/boost/function/function_template.hpp | 11 +++++++++++ 2 files changed, 12 insertions(+) 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_template.hpp b/include/boost/function/function_template.hpp index 3aacea1..321bd13 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -446,6 +446,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 From d84481361fb63691f258e1c7545638c221544159 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 10 Jul 2006 13:17:41 +0000 Subject: [PATCH 02/65] TR1 cyclic dependency fixes. [SVN r34499] --- include/boost/function.hpp | 2 ++ include/boost/function/detail/prologue.hpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/function.hpp b/include/boost/function.hpp index 1a5cca2..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 diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index ab2b323..1ef5f6e 100644 --- a/include/boost/function/detail/prologue.hpp +++ b/include/boost/function/detail/prologue.hpp @@ -11,7 +11,6 @@ #define BOOST_FUNCTION_PROLOGUE_HPP # include # include -# include // unary_function, binary_function # include # include # include From a2a810d2c1eae9006f6ed2f7f45c5084656ed496 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 12 Jul 2006 22:12:01 +0000 Subject: [PATCH 03/65] Put back #include in case functionN.hpp is used directly [SVN r34519] --- include/boost/function/detail/prologue.hpp | 1 + 1 file changed, 1 insertion(+) 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 From 64c8d10fa8b9d40b6d12a393756e3ef0867f0e7f Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Oct 2006 14:29:56 +0000 Subject: [PATCH 04/65] 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 6a3f0df553fdeef9616c36cacf0c05f8b4588b22 Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Tue, 7 Nov 2006 19:11:57 +0000 Subject: [PATCH 05/65] Add copyright, license [SVN r35905] --- index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 221f49e..5119596 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,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 5c514ebe35469febab8e510baaab9d0c98a42687 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 18 Apr 2007 12:13:53 +0000 Subject: [PATCH 06/65] Try to work around EC++4 bug [SVN r37471] --- include/boost/function/function_base.hpp | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 7165434..e0935bf 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -30,6 +30,14 @@ #endif #include +// 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) \ @@ -215,8 +223,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 +273,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 +295,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 +356,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 @@ -480,13 +488,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 From 2a85edbd3102cb89ddbc5e082e51013d20b61e12 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 8 Aug 2007 19:02:26 +0000 Subject: [PATCH 07/65] Remove V1 Jamfiles [SVN r38516] --- 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 80a3f470995b6e3ccf50b199c3a51061b56c30ce Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 21 Aug 2007 15:35:19 +0000 Subject: [PATCH 08/65] Committed patch to eliminate warnings with GCC's -Wundef. Fixes #1197 [SVN r38827] --- include/boost/function/function_base.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index e0935bf..238247b 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -67,7 +67,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 From e4f165a4e8b81152999c757a6ab0f7ab8c9063c3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 29 Aug 2007 18:59:16 +0000 Subject: [PATCH 09/65] Disable MSVC warning about native code generation. Fixes #1163 [SVN r39060] --- include/boost/function/function_base.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 238247b..f8d8e55 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -30,6 +30,11 @@ #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 @@ -741,4 +746,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 From a7b9940f15a7aeef82f3a7f0912216e9d2839ea8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 29 Aug 2007 19:06:11 +0000 Subject: [PATCH 10/65] Handle GCC's -fno-exceptions properly. Fixes #1198 [SVN r39061] --- include/boost/function/function_template.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 321bd13..5d7b2cf 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -562,12 +562,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; } @@ -593,12 +597,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; } From de27ae969741bef9a8b05ef25dca0549b56cab3e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 13 Sep 2007 17:38:58 +0000 Subject: [PATCH 11/65] function/function_base.hpp, function/function_template.hpp: - Switch from dynamic initialization of the vtable pointer to static initialization (Fixes #1260) - Handle member pointers properly, only using mem_fn within the invoker to deal with all of the messy bits of calling member pointers [SVN r39240] --- include/boost/function/function_base.hpp | 15 +- include/boost/function/function_template.hpp | 292 +++++++++++++------ 2 files changed, 220 insertions(+), 87 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index f8d8e55..525703f 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -211,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: @@ -381,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. */ @@ -571,7 +580,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; }; diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 5d7b2cf..a5874f3 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 @@ -181,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 @@ -244,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; @@ -262,50 +426,24 @@ 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(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); } private: - template - void init(F f) - { - typedef typename get_function_tag::type tag; - init(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 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) { @@ -321,22 +459,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; @@ -345,24 +474,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(FunctionObj f, function_buffer& functor, + mpl::true_) const { new ((void*)&functor.data) FunctionObj(f); } @@ -370,7 +486,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(FunctionObj f, function_buffer& functor, + mpl::false_) const { #ifndef BOOST_NO_STD_ALLOCATOR typedef typename Allocator::template rebind::other @@ -390,7 +507,8 @@ namespace boost { template bool - assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) + assign_to(FunctionObj f, function_buffer& functor, + function_obj_tag) const { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor(f, functor, @@ -402,25 +520,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 @@ -435,6 +538,9 @@ namespace boost { } public: + void (*manager)(const function_buffer& in_buffer, + function_buffer& out_buffer, + functor_manager_operation_type op); invoker_type invoker; }; } // end namespace function @@ -538,7 +644,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 @@ -624,7 +730,7 @@ namespace boost { void clear() { if (vtable) { - static_cast(vtable)->clear(this->functor); + reinterpret_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -661,8 +767,23 @@ 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; + + static const vtable_type stored_vtable = + { &manager_type::manage, &invoker_type::invoke }; + + if (stored_vtable.assign_to(f, functor)) + vtable = reinterpret_cast(&stored_vtable); else vtable = 0; } }; @@ -697,7 +818,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 @@ -814,6 +935,7 @@ 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 @@ -823,10 +945,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 3312c7ffcd2499d023d1b5d2dab47ee91cf7730a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 13 Sep 2007 19:06:53 +0000 Subject: [PATCH 12/65] function_template.hpp: - Pass-by-reference internally, when we can. Fixes #1067 [SVN r39244] --- include/boost/function/function_template.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index a5874f3..d4a6ccd 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -426,7 +426,7 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_ARGS); template - bool assign_to(F f, function_buffer& functor) const + bool assign_to(const F& f, function_buffer& functor) const { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); @@ -477,7 +477,7 @@ namespace boost { // Assign to a function object using the small object optimization template void - assign_functor(FunctionObj f, function_buffer& functor, + assign_functor(const FunctionObj& f, function_buffer& functor, mpl::true_) const { new ((void*)&functor.data) FunctionObj(f); @@ -486,7 +486,7 @@ namespace boost { // Assign to a function object allocated on the heap. template void - assign_functor(FunctionObj f, function_buffer& functor, + assign_functor(const FunctionObj& f, function_buffer& functor, mpl::false_) const { #ifndef BOOST_NO_STD_ALLOCATOR @@ -507,7 +507,7 @@ namespace boost { template bool - assign_to(FunctionObj f, function_buffer& functor, + assign_to(const FunctionObj& f, function_buffer& functor, function_obj_tag) const { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { @@ -765,7 +765,7 @@ namespace boost { } template - void assign_to(Functor f) + void assign_to(const Functor& f) { using detail::function::vtable_base; From 53b95c386de3023c9b47dc4091a68ead21e6b5fb Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 14 Sep 2007 21:05:46 +0000 Subject: [PATCH 13/65] Finalizes the fix to Bug #1260, making vtable_base an actual POD type (oops) and playing more nicely with reinterpret_cast (thanks to Brad King for the fixes). [SVN r39285] --- include/boost/function/function_base.hpp | 1 - include/boost/function/function_template.hpp | 13 +++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 525703f..6458765 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -478,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); diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index d4a6ccd..ec52c92 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -434,8 +434,8 @@ namespace boost { void clear(function_buffer& functor) const { - if (manager) - manager(functor, functor, destroy_functor_tag); + if (base.manager) + base.manager(functor, functor, destroy_functor_tag); } private: @@ -538,9 +538,7 @@ namespace boost { } public: - void (*manager)(const function_buffer& in_buffer, - function_buffer& out_buffer, - functor_manager_operation_type op); + vtable_base base; invoker_type invoker; }; } // end namespace function @@ -780,10 +778,9 @@ namespace boost { typedef typename handler_type::manager_type manager_type; static const vtable_type stored_vtable = - { &manager_type::manage, &invoker_type::invoke }; + { { &manager_type::manage }, &invoker_type::invoke }; - if (stored_vtable.assign_to(f, functor)) - vtable = reinterpret_cast(&stored_vtable); + if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; else vtable = 0; } }; From 2378ba59e731d86ea068cf986b057e6b1f49948a Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 2 Oct 2007 17:41:35 +0000 Subject: [PATCH 14/65] Fix for Borland compilers. [SVN r39657] --- include/boost/function/function_template.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index ec52c92..536bac4 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -437,8 +437,9 @@ namespace boost { if (base.manager) base.manager(functor, functor, destroy_functor_tag); } - +#ifndef BOOST_NO_PRIVATE_IN_AGGREGATE private: +#endif // Function pointers template bool From 81e558491b2a6e69b2a7649441f7813f03a8b529 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 5 Nov 2007 21:22:29 +0000 Subject: [PATCH 15/65] Merge lots of copyrights [SVN r40811] --- 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 cead36cd5b2cbef67455fadd7113a6e6300407a1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 6 Dec 2007 18:39:06 +0000 Subject: [PATCH 16/65] Disable more Visual C++ warnings in Function headers. Fixes #1416 [SVN r41798] --- 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 adb7b0a21460f5d83efa6a8f1060aa26414da1ba Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 27 Mar 2008 19:44:37 +0000 Subject: [PATCH 17/65] Change Boost.Function allocator behavior, from Emil Dotchevski [SVN r43884] --- doc/history.xml | 16 + doc/reference.xml | 118 ++-- include/boost/function/function_base.hpp | 212 ++++--- include/boost/function/function_template.hpp | 552 +++++++++---------- test/allocator_test.cpp | 67 ++- 5 files changed, 537 insertions(+), 428 deletions(-) diff --git a/doc/history.xml b/doc/history.xml index 2af6dd6..eb5a442 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -13,6 +13,22 @@ + Version 1.36.0: + + Boost.Function now implements allocator support + in the same way that is is provided in C++0x, based on C++ + committee + proposal N2308. This + change removes the Allocator + template parameter of boost::function in + favor of a constructor that takes an argument. While this is a + backward-incompatible change, it is likely to affect only a few + users. This change to Function was contributed by Emil + Dotchevski, which also authored the corresponding C++ committee + proposal. + + + Version 1.34.0: Boost.Function now implements a small buffer optimization, which can drastically improve the performance when copying or construction Boost.Function objects storing small function objects. For instance, bind(&X:foo, &x, _1, _2) requires no heap allocation when placed into a Boost.Function object. Note that some exception-safety guarantees have changed: assignment provides the basic exception guarantee and swap() may throw. diff --git a/doc/reference.xml b/doc/reference.xml index 54b06e0..3b1faec 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -141,9 +141,6 @@ - - std::allocator<void> - function_base @@ -160,7 +157,6 @@ R - Allocator T1If N == 1 @@ -216,6 +212,19 @@ *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + + F + Allocator + F is a function object Callable from this, Allocator is an allocator. The copy constructor and destructor of Allocator shall not throw. + *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + If memory allocation is required, the given allocator (or a copy of it) will be used to allocate that memory. + + If !this->empty(), destroys the target of this. @@ -324,11 +333,10 @@ - void - functionN<T1, T2, ..., TN, Allocator>& - functionN<T1, T2, ..., TN, Allocator>& + functionN<T1, T2, ..., TN>& + functionN<T1, T2, ..., TN>& f1.swap(f2) @@ -341,11 +349,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -354,12 +361,11 @@ - bool Functor - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& reference_wrapper<Functor> @@ -380,12 +385,11 @@ - bool reference_wrapper<Functor> - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& void - const functionN<T1, T2, ..., TN, Allocator1>& - const functionN<U1, U2, ..., UN, Allocator2>& + const functionN<T1, T2, ..., TN>& + const functionN<U1, U2, ..., UN>& True when f stores an object of @@ -442,11 +444,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -455,12 +456,11 @@ - bool Functor - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& reference_wrapper<Functor> @@ -481,12 +480,11 @@ - bool reference_wrapper<Functor> - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& void - const functionN<T1, T2, ..., TN, Allocator1>& - const functionN<U1, U2, ..., UN, Allocator2>& + const functionN<T1, T2, ..., TN>& + const functionN<U1, U2, ..., UN>& True when f does not store an @@ -543,11 +539,8 @@ Function type R (T1, T2, ..., TN) - - std::allocator<void> - - functionN<R, T1, T2, ..., TN, Allocator> + functionN<R, T1, T2, ..., TN> A generalized function pointer that can be used for callbacks or wrapping function objects. @@ -569,7 +562,6 @@ R - Allocator T1If N == 1 @@ -633,6 +625,19 @@ *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + + F + Allocator + F is a function object Callable from this, Allocator is an allocator. The copy constructor and destructor of Allocator shall not throw. + *this targets a copy of f if f is nonempty, or this->empty() if f is empty. + + If memory allocation is required, the given allocator (or a copy of it) will be used to allocate that memory. + + If !this->empty(), destroys the target of this. @@ -745,11 +750,10 @@ void - function<Signature, Allocator>& - function<Signature, Allocator>& + function<Signature>& + function<Signature>& f1.swap(f2) @@ -759,53 +763,47 @@ bool - const function<Signature, Allocator>& + const function<Signature>& Functor bool Functor - const function<Signature, Allocator>& + const function<Signature>& bool - const function<Signature, Allocator>& + const function<Signature>& reference_wrapper<Functor> bool reference_wrapper<Functor> - const function<Signature, Allocator>& + const function<Signature>& void - const function<Signature1, Allocator1>& - const function<Signature2, Allocator2>& + const function<Signature1>& + const function<Signature2>& True when f stores an object of @@ -840,53 +838,47 @@ bool - const function<Signature, Allocator>& + const function<Signature>& Functor bool Functor - const function<Signature, Allocator>& + const function<Signature>& bool - const function<Signature, Allocator>& + const function<Signature>& reference_wrapper<Functor> bool reference_wrapper<Functor> - const function<Signature, Allocator>& + const function<Signature>& void - const function<Signature1, Allocator1>& - const function<Signature2, Allocator2>& + const function<Signature1>& + const function<Signature2>& True when f does not store an diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index aa7376a..7d667ae 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -1,8 +1,9 @@ // Boost.Function library -// Copyright Douglas Gregor 2001-2006. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Copyright Douglas Gregor 2001-2006 +// Copyright Emil Dotchevski 2007 +// Use, modification and distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // For more information, see http://www.boost.org @@ -73,7 +74,7 @@ namespace boost { namespace python { namespace objects { #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) + || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX #endif @@ -94,21 +95,12 @@ namespace boost { namespace python { namespace objects { #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) namespace boost { -#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) -// The library shipping with MIPSpro 7.3.1.3m has a broken allocator -class function_base; - -template > +template class function; -#else -template > -class function; -#endif -template -inline void swap(function& f1, - function& f2) +template +inline void swap(function& f1, + function& f2) { f1.swap(f2); } @@ -212,8 +204,8 @@ namespace boost { struct reference_manager { static inline void - manage(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op) + get(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { switch (op) { case clone_functor_tag: @@ -259,20 +251,29 @@ namespace boost { % alignment_of::value == 0)))); }; + template + struct functor_wrapper: public F, public A + { + functor_wrapper( F f, A a ): + F(f), + A(a) + { + } + }; + /** * The functor_manager class contains a static function "manage" which * can clone or destroy the given function/function object pointer. */ - template - struct functor_manager + template + struct functor_manager_common { - private: typedef Functor functor_type; - // For function pointers, the manager is trivial + // Function pointers static inline void - manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, function_ptr_tag) + manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { if (op == clone_functor_tag) out_buffer.func_ptr = in_buffer.func_ptr; @@ -290,8 +291,8 @@ namespace boost { // Function objects that fit in the small-object buffer. static inline void - manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, mpl::true_) + manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) { if (op == clone_functor_tag) { const functor_type* in_functor = @@ -309,57 +310,48 @@ namespace boost { out_buffer.obj_ptr = 0; } } + }; + + template + struct functor_manager + { + private: + typedef Functor functor_type; + + // Function pointers + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, function_ptr_tag) + { + functor_manager_common::manage_ptr(in_buffer,out_buffer,op); + } + + // Function objects that fit in the small-object buffer. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, mpl::true_) + { + functor_manager_common::manage_small(in_buffer,out_buffer,op); + } // Function objects that require heap allocation static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, functor_manager_operation_type op, mpl::false_) { -#ifndef BOOST_NO_STD_ALLOCATOR - typedef typename Allocator::template rebind::other - allocator_type; - typedef typename allocator_type::pointer pointer_type; -#else - typedef functor_type* pointer_type; -#endif // BOOST_NO_STD_ALLOCATOR - -# ifndef BOOST_NO_STD_ALLOCATOR - allocator_type allocator; -# endif // BOOST_NO_STD_ALLOCATOR - if (op == clone_functor_tag) { + // Clone the functor // GCC 2.95.3 gets the CV qualifiers wrong here, so we // can't do the static_cast that we should do. const functor_type* f = (const functor_type*)(in_buffer.obj_ptr); - - // Clone the functor -# ifndef BOOST_NO_STD_ALLOCATOR - pointer_type copy = allocator.allocate(1); - allocator.construct(copy, *f); - - // Get back to the original pointer type - functor_type* new_f = static_cast(copy); -# else functor_type* new_f = new functor_type(*f); -# endif // BOOST_NO_STD_ALLOCATOR out_buffer.obj_ptr = new_f; } else if (op == destroy_functor_tag) { /* Cast from the void pointer to the functor pointer type */ functor_type* f = static_cast(out_buffer.obj_ptr); - -# ifndef BOOST_NO_STD_ALLOCATOR - /* Cast from the functor pointer type to the allocator's pointer - type */ - pointer_type victim = static_cast(f); - - // Destroy and deallocate the functor - allocator.destroy(victim); - allocator.deallocate(victim, 1); -# else delete f; -# endif // BOOST_NO_STD_ALLOCATOR out_buffer.obj_ptr = 0; } else /* op == check_functor_type_tag */ { const BOOST_FUNCTION_STD_NS::type_info& check_type = @@ -382,13 +374,98 @@ namespace boost { mpl::bool_<(function_allows_small_object_optimization::value)>()); } - // For member pointers, we treat them as function objects with - // the small-object optimization always enabled. + public: + /* Dispatch to an appropriate manager based on whether we have a + function pointer or a function object pointer. */ + static inline void + manage(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) + { + typedef typename get_function_tag::type tag_type; + switch (op) { + case get_functor_type_tag: + out_buffer.const_obj_ptr = &typeid(functor_type); + return; + + default: + manager(in_buffer, out_buffer, op, tag_type()); + return; + } + } + }; + + template + struct functor_manager_a + { + private: + typedef Functor functor_type; + + // Function pointers static inline void manager(const function_buffer& in_buffer, function_buffer& out_buffer, - functor_manager_operation_type op, member_ptr_tag) + functor_manager_operation_type op, function_ptr_tag) { - manager(in_buffer, out_buffer, op, mpl::true_()); + functor_manager_common::manage_ptr(in_buffer,out_buffer,op); + } + + // Function objects that fit in the small-object buffer. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, mpl::true_) + { + functor_manager_common::manage_small(in_buffer,out_buffer,op); + } + + // Function objects that require heap allocation + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, mpl::false_) + { + typedef functor_wrapper functor_wrapper_type; + typedef typename Allocator::template rebind::other + wrapper_allocator_type; + typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type; + + if (op == clone_functor_tag) { + // Clone the functor + // GCC 2.95.3 gets the CV qualifiers wrong here, so we + // can't do the static_cast that we should do. + const functor_wrapper_type* f = + (const functor_wrapper_type*)(in_buffer.obj_ptr); + wrapper_allocator_type wrapper_allocator(static_cast(*f)); + wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); + wrapper_allocator.construct(copy, *f); + + // Get back to the original pointer type + functor_wrapper_type* new_f = static_cast(copy); + out_buffer.obj_ptr = new_f; + } else if (op == destroy_functor_tag) { + /* Cast from the void pointer to the functor_wrapper_type */ + functor_wrapper_type* victim = + static_cast(in_buffer.obj_ptr); + wrapper_allocator_type wrapper_allocator(static_cast(*victim)); + wrapper_allocator.destroy(victim); + wrapper_allocator.deallocate(victim,1); + out_buffer.obj_ptr = 0; + } else /* op == check_functor_type_tag */ { + const BOOST_FUNCTION_STD_NS::type_info& check_type = + *static_cast(out_buffer.const_obj_ptr); + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + out_buffer.obj_ptr = in_buffer.obj_ptr; + else + out_buffer.obj_ptr = 0; + } + } + + // For function objects, we determine whether the function + // object can use the small-object optimization buffer or + // whether we need to allocate it on the heap. + static inline void + manager(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op, function_obj_tag) + { + manager(in_buffer, out_buffer, op, + mpl::bool_<(function_allows_small_object_optimization::value)>()); } public: @@ -479,6 +556,7 @@ namespace boost { */ struct vtable_base { + vtable_base() : manager(0) { } void (*manager)(const function_buffer& in_buffer, function_buffer& out_buffer, functor_manager_operation_type op); @@ -580,7 +658,7 @@ public: #endif public: // should be protected, but GCC 2.95.3 will fail to allow access - const detail::function::vtable_base* vtable; + detail::function::vtable_base* vtable; mutable detail::function::function_buffer functor; }; @@ -755,8 +833,4 @@ namespace detail { #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL #undef BOOST_FUNCTION_COMPARE_TYPE_ID -#if defined(BOOST_MSVC) -# pragma warning( pop ) -#endif - #endif // BOOST_FUNCTION_BASE_HEADER diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index ab5c643..a575ebf 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -1,8 +1,9 @@ // Boost.Function library -// Copyright Douglas Gregor 2001-2006. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// Copyright Douglas Gregor 2001-2006 +// Copyright Emil Dotchevski 2007 +// Use, modification and distribution is subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // For more information, see http://www.boost.org @@ -31,13 +32,6 @@ #define BOOST_FUNCTION_ARG_TYPES BOOST_PP_REPEAT(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_ARG_TYPE,BOOST_PP_EMPTY) -// Type of the default allocator -#ifndef BOOST_NO_STD_ALLOCATOR -# define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator -#else -# define BOOST_FUNCTION_DEFAULT_ALLOCATOR int -#endif // BOOST_NO_STD_ALLOCATOR - // Comma if nonzero number of arguments #if BOOST_FUNCTION_NUM_ARGS == 0 # define BOOST_FUNCTION_COMMA @@ -59,20 +53,12 @@ BOOST_JOIN(function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER \ BOOST_JOIN(void_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_MEMBER_INVOKER \ - BOOST_JOIN(member_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_VOID_MEMBER_INVOKER \ - BOOST_JOIN(void_member_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_INVOKER \ BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER \ BOOST_JOIN(get_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_GET_MEMBER_INVOKER \ - BOOST_JOIN(get_member_invoker,BOOST_FUNCTION_NUM_ARGS) -#define BOOST_FUNCTION_GET_INVOKER \ - BOOST_JOIN(get_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VTABLE BOOST_JOIN(basic_vtable,BOOST_FUNCTION_NUM_ARGS) #ifndef BOOST_NO_VOID_RETURNS @@ -194,44 +180,6 @@ namespace boost { } }; -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Handle invocation of member pointers. */ - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_MEMBER_INVOKER - { - static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA - BOOST_FUNCTION_PARMS) - - { - MemberPtr* f = - reinterpret_cast(&function_obj_ptr.data); - return boost::mem_fn(*f)(BOOST_FUNCTION_ARGS); - } - }; - - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_VOID_MEMBER_INVOKER - { - static BOOST_FUNCTION_VOID_RETURN_TYPE - invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA - BOOST_FUNCTION_PARMS) - - { - MemberPtr* f = - reinterpret_cast(&function_obj_ptr.data); - BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS)); - } - }; -#endif - template< typename FunctionPtr, typename R BOOST_FUNCTION_COMMA @@ -295,130 +243,11 @@ namespace boost { >::type type; }; -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Retrieve the appropriate invoker for a member pointer. */ - template< - typename MemberPtr, - typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS - > - struct BOOST_FUNCTION_GET_MEMBER_INVOKER - { - typedef typename mpl::if_c<(is_void::value), - BOOST_FUNCTION_VOID_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >, - BOOST_FUNCTION_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - > - >::type type; - }; -#endif - - /* Given the tag returned by get_function_tag, retrieve the - actual invoker that will be used for the given function - object. - - Each specialization contains an "apply" nested class template - that accepts the function object, return type, function - argument types, and allocator. The resulting "apply" class - contains two typedefs, "invoker_type" and "manager_type", - which correspond to the invoker and manager types. */ - template - struct BOOST_FUNCTION_GET_INVOKER { }; - - /* Retrieve the invoker for a function pointer. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< - FunctionPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; - -#if BOOST_FUNCTION_NUM_ARGS > 0 - /* Retrieve the invoker for a member pointer. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_MEMBER_INVOKER< - MemberPtr, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; -#endif - - /* Retrieve the invoker for a function object. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< - FunctionObj, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef functor_manager manager_type; - }; - }; - - /* Retrieve the invoker for a reference to a function object. */ - template<> - struct BOOST_FUNCTION_GET_INVOKER - { - template - struct apply - { - typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER< - typename RefWrapper::type, - R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS - >::type - invoker_type; - - typedef reference_manager manager_type; - }; - }; - /** * vtable for a specific boost::function instance. */ - template - struct BOOST_FUNCTION_VTABLE + template + struct BOOST_FUNCTION_VTABLE : vtable_base { #ifndef BOOST_NO_VOID_RETURNS typedef R result_type; @@ -431,25 +260,80 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_ARGS); template - bool assign_to(const F& f, function_buffer& functor) const + BOOST_FUNCTION_VTABLE(F f) : vtable_base(), invoker(0) + { + init(f); + } + template + BOOST_FUNCTION_VTABLE(F f, Allocator) : vtable_base(), invoker(0) + { + init_a(f); + } + + template + bool assign_to(F f, function_buffer& functor) { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); } - - void clear(function_buffer& functor) const + template + bool assign_to_a(F f, function_buffer& functor, Allocator a) { - if (base.manager) - base.manager(functor, functor, destroy_functor_tag); + typedef typename get_function_tag::type tag; + return assign_to_a(f, functor, a, tag()); } -#ifndef BOOST_NO_PRIVATE_IN_AGGREGATE + + void clear(function_buffer& functor) + { + if (manager) + manager(functor, functor, destroy_functor_tag); + } + private: -#endif + template + void init(F f) + { + typedef typename get_function_tag::type tag; + init(f, tag()); + } + template + void init_a(F f) + { + typedef typename get_function_tag::type tag; + init_a(f, tag()); + } + // Function pointers + template + void init(FunctionPtr /*f*/, function_ptr_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< + FunctionPtr, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager::manage; + } + template + void init_a(FunctionPtr f, function_ptr_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_INVOKER< + FunctionPtr, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager_a::manage; + } + template bool - assign_to(FunctionPtr f, function_buffer& functor, - function_ptr_tag) const + assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) { this->clear(functor); if (f) { @@ -461,17 +345,53 @@ namespace boost { return false; } } + template + bool + assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) + { + return assign_to(f,functor,function_ptr_tag()); + } // Member pointers #if BOOST_FUNCTION_NUM_ARGS > 0 template - bool - assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) const + void init(MemberPtr f, member_ptr_tag) { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. + this->init(mem_fn(f)); + } + template + void init_a(MemberPtr f, member_ptr_tag) + { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. + this->init_a(mem_fn(f)); + } + + template + bool assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) + { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. if (f) { - // Always use the small-object optimization for member - // pointers. - assign_functor(f, functor, mpl::true_()); + this->assign_to(mem_fn(f), functor); + return true; + } else { + return false; + } + } + template + bool assign_to_a(MemberPtr f, function_buffer& functor, Allocator a, member_ptr_tag) + { + // DPG TBD: Add explicit support for member function + // objects, so we invoke through mem_fn() but we retain the + // right target_type() values. + if (f) { + this->assign_to_a(mem_fn(f), functor, a); return true; } else { return false; @@ -480,41 +400,72 @@ namespace boost { #endif // BOOST_FUNCTION_NUM_ARGS > 0 // Function objects + template + void init(FunctionObj /*f*/, function_obj_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager::manage; + } + template + void init_a(FunctionObj /*f*/, function_obj_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &functor_manager_a::manage; + } + // Assign to a function object using the small object optimization template void - assign_functor(const FunctionObj& f, function_buffer& functor, - mpl::true_) const + assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) { new ((void*)&functor.data) FunctionObj(f); } + template + void + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) + { + assign_functor(f,functor,mpl::true_()); + } // Assign to a function object allocated on the heap. template void - assign_functor(const FunctionObj& f, function_buffer& functor, - mpl::false_) const + assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) { -#ifndef BOOST_NO_STD_ALLOCATOR - typedef typename Allocator::template rebind::other - allocator_type; - typedef typename allocator_type::pointer pointer_type; - - allocator_type allocator; - pointer_type copy = allocator.allocate(1); - allocator.construct(copy, f); - - // Get back to the original pointer type - functor.obj_ptr = static_cast(copy); -# else functor.obj_ptr = new FunctionObj(f); -# endif // BOOST_NO_STD_ALLOCATOR + } + template + void + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) + { + typedef functor_wrapper functor_wrapper_type; + typedef typename Allocator::template rebind::other + wrapper_allocator_type; + typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type; + wrapper_allocator_type wrapper_allocator(a); + wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); + wrapper_allocator.construct(copy, functor_wrapper_type(f,a)); + functor_wrapper_type* new_f = static_cast(copy); + functor.obj_ptr = new_f; } template bool - assign_to(const FunctionObj& f, function_buffer& functor, - function_obj_tag) const + assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor(f, functor, @@ -524,12 +475,45 @@ namespace boost { return false; } } + template + bool + assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) + { + if (!boost::detail::function::has_empty_target(boost::addressof(f))) { + assign_functor_a(f, functor, a, + mpl::bool_<(function_allows_small_object_optimization::value)>()); + return true; + } else { + return false; + } + } // Reference to a function object + template + void + init(const reference_wrapper& /*f*/, function_obj_ref_tag) + { + typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER< + FunctionObj, + R BOOST_FUNCTION_COMMA + BOOST_FUNCTION_TEMPLATE_ARGS + >::type + actual_invoker_type; + + invoker = &actual_invoker_type::invoke; + manager = &reference_manager::get; + } + template + void + init_a(const reference_wrapper& f, function_obj_ref_tag) + { + init(f,function_obj_ref_tag()); + } + template bool assign_to(const reference_wrapper& f, - function_buffer& functor, function_obj_ref_tag) const + function_buffer& functor, function_obj_ref_tag) { if (!boost::detail::function::has_empty_target(f.get_pointer())) { // DPG TBD: We might need to detect constness of @@ -542,9 +526,15 @@ namespace boost { return false; } } + template + bool + assign_to_a(const reference_wrapper& f, + function_buffer& functor, Allocator, function_obj_ref_tag) + { + return assign_to(f,functor,function_obj_ref_tag()); + } public: - vtable_base base; invoker_type invoker; }; } // end namespace function @@ -552,8 +542,7 @@ namespace boost { template< typename R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_PARMS, - typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR + BOOST_FUNCTION_TEMPLATE_PARMS > class BOOST_FUNCTION_FUNCTION : public function_base @@ -578,7 +567,7 @@ namespace boost { private: typedef boost::detail::function::BOOST_FUNCTION_VTABLE< - R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, Allocator> + R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS> vtable_type; struct clear_type {}; @@ -603,7 +592,6 @@ namespace boost { BOOST_STATIC_CONSTANT(int, arity = BOOST_FUNCTION_NUM_ARGS); BOOST_FUNCTION_ARG_TYPES - typedef Allocator allocator_type; typedef BOOST_FUNCTION_FUNCTION self_type; BOOST_FUNCTION_FUNCTION() : function_base() { } @@ -623,6 +611,19 @@ namespace boost { { this->assign_to(f); } + template + BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a +#ifndef BOOST_NO_SFINAE + ,typename enable_if_c< + (boost::type_traits::ice_not< + (is_integral::value)>::value), + int>::type = 0 +#endif // BOOST_NO_SFINAE + ) : + function_base() + { + this->assign_to_a(f,a); + } #ifndef BOOST_NO_SFINAE BOOST_FUNCTION_FUNCTION(clear_type*) : function_base() { } @@ -648,7 +649,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return static_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #else @@ -672,18 +673,25 @@ namespace boost { operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { this->clear(); -#ifndef BOOST_NO_EXCEPTIONS try { this->assign_to(f); } catch (...) { vtable = 0; throw; } -#else - this->assign_to(f); -#endif return *this; } + template + void assign(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a) + { + this->clear(); + try { + this->assign_to_a(f,a); + } catch (...) { + vtable = 0; + throw; + } + } #ifndef BOOST_NO_SFINAE BOOST_FUNCTION_FUNCTION& operator=(clear_type*) @@ -707,16 +715,12 @@ namespace boost { return *this; this->clear(); -#ifndef BOOST_NO_EXCEPTIONS try { this->assign_to_own(f); } catch (...) { vtable = 0; throw; } -#else - this->assign_to_own(f); -#endif return *this; } @@ -734,7 +738,7 @@ namespace boost { void clear() { if (vtable) { - reinterpret_cast(vtable)->clear(this->functor); + static_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -769,84 +773,64 @@ namespace boost { } template - void assign_to(const Functor& f) + void assign_to(Functor f) { - using detail::function::vtable_base; - - typedef typename detail::function::get_function_tag::type tag; - typedef detail::function::BOOST_FUNCTION_GET_INVOKER get_invoker; - typedef typename get_invoker:: - template apply - handler_type; - - typedef typename handler_type::invoker_type invoker_type; - typedef typename handler_type::manager_type manager_type; - - static const vtable_type stored_vtable = - { { &manager_type::manage }, &invoker_type::invoke }; - - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; + static vtable_type stored_vtable(f); + if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable; + else vtable = 0; + } + template + void assign_to_a(Functor f,Allocator a) + { + static vtable_type stored_vtable(f,a); + if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable; else vtable = 0; } }; - template + template inline void swap(BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator + BOOST_FUNCTION_TEMPLATE_ARGS >& f1, BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS, - Allocator + BOOST_FUNCTION_TEMPLATE_ARGS >& f2) { f1.swap(f2); } #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - template + template typename BOOST_FUNCTION_FUNCTION< - R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, - Allocator>::result_type - BOOST_FUNCTION_FUNCTION + R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type + BOOST_FUNCTION_FUNCTION ::operator()(BOOST_FUNCTION_PARMS) const { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return static_cast(vtable)->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif // Poison comparisons between boost::function objects of the same type. -template +template void operator==(const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&, + BOOST_FUNCTION_TEMPLATE_ARGS>&, const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&); -template + BOOST_FUNCTION_TEMPLATE_ARGS>&); +template void operator!=(const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&, + BOOST_FUNCTION_TEMPLATE_ARGS>&, const BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA - BOOST_FUNCTION_TEMPLATE_ARGS , - Allocator>&); + BOOST_FUNCTION_TEMPLATE_ARGS>& ); #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) @@ -857,20 +841,16 @@ template -class function - : public BOOST_FUNCTION_FUNCTION + BOOST_FUNCTION_TEMPLATE_PARMS> +class function + : public BOOST_FUNCTION_FUNCTION { - typedef BOOST_FUNCTION_FUNCTION base_type; + typedef BOOST_FUNCTION_FUNCTION base_type; typedef function self_type; struct clear_type {}; public: - typedef typename base_type::allocator_type allocator_type; function() : base_type() {} @@ -886,6 +866,18 @@ public: base_type(f) { } + template + function(Functor f, Allocator a +#ifndef BOOST_NO_SFINAE + ,typename enable_if_c< + (boost::type_traits::ice_not< + (is_integral::value)>::value), + int>::type = 0 +#endif + ) : + base_type(f,a) + { + } #ifndef BOOST_NO_SFINAE function(clear_type*) : base_type() {} @@ -938,8 +930,6 @@ public: // Cleanup after ourselves... #undef BOOST_FUNCTION_VTABLE -#undef BOOST_FUNCTION_GET_INVOKER -#undef BOOST_FUNCTION_DEFAULT_ALLOCATOR #undef BOOST_FUNCTION_COMMA #undef BOOST_FUNCTION_FUNCTION #undef BOOST_FUNCTION_FUNCTION_INVOKER @@ -948,12 +938,10 @@ public: #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_FUNCTION_REF_INVOKER #undef BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER -#undef BOOST_FUNCTION_MEMBER_INVOKER -#undef BOOST_FUNCTION_VOID_MEMBER_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER -#undef BOOST_FUNCTION_GET_MEMBER_INVOKER +#undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER #undef BOOST_FUNCTION_TEMPLATE_PARMS #undef BOOST_FUNCTION_TEMPLATE_ARGS #undef BOOST_FUNCTION_PARMS diff --git a/test/allocator_test.cpp b/test/allocator_test.cpp index 6411aec..7b35f16 100644 --- a/test/allocator_test.cpp +++ b/test/allocator_test.cpp @@ -27,6 +27,14 @@ struct counting_allocator : public std::allocator typedef counting_allocator other; }; + counting_allocator() + { + } + + template + counting_allocator( counting_allocator ) + { + } T* allocate(std::size_t n) { @@ -41,20 +49,27 @@ struct counting_allocator : public std::allocator } }; -struct plus_int +struct enable_small_object_optimization +{ +}; + +struct disable_small_object_optimization +{ + int unused_state_data[32]; +}; + +template +struct plus_int: base { int operator()(int x, int y) const { return x + y; } - - int unused_state_data[32]; }; static int do_minus(int x, int y) { return x-y; } -struct DoNothing +template +struct DoNothing: base { void operator()() const {} - - int unused_state_data[32]; }; static void do_nothing() {} @@ -62,33 +77,57 @@ static void do_nothing() {} int test_main(int, char*[]) { - function2 > f; - f = plus_int(); + function2 f; + f.assign( plus_int(), counting_allocator() ); f.clear(); BOOST_CHECK(alloc_count == 1); BOOST_CHECK(dealloc_count == 1); - alloc_count = 0; dealloc_count = 0; - f = &do_minus; + f.assign( plus_int(), counting_allocator() ); f.clear(); BOOST_CHECK(alloc_count == 0); BOOST_CHECK(dealloc_count == 0); + f.assign( plus_int(), std::allocator() ); + f.clear(); + f.assign( plus_int(), std::allocator() ); + f.clear(); - function0 > fv; alloc_count = 0; dealloc_count = 0; - fv = DoNothing(); + f.assign( &do_minus, counting_allocator() ); + f.clear(); + BOOST_CHECK(alloc_count == 0); + BOOST_CHECK(dealloc_count == 0); + f.assign( &do_minus, std::allocator() ); + f.clear(); + + function0 fv; + alloc_count = 0; + dealloc_count = 0; + fv.assign( DoNothing(), counting_allocator() ); fv.clear(); BOOST_CHECK(alloc_count == 1); BOOST_CHECK(dealloc_count == 1); - alloc_count = 0; dealloc_count = 0; - fv = &do_nothing; + fv.assign( DoNothing(), counting_allocator() ); fv.clear(); BOOST_CHECK(alloc_count == 0); BOOST_CHECK(dealloc_count == 0); + fv.assign( DoNothing(), std::allocator() ); + fv.clear(); + fv.assign( DoNothing(), std::allocator() ); + fv.clear(); + + alloc_count = 0; + dealloc_count = 0; + fv.assign( &do_nothing, counting_allocator() ); + fv.clear(); + BOOST_CHECK(alloc_count == 0); + BOOST_CHECK(dealloc_count == 0); + fv.assign( &do_nothing, std::allocator() ); + fv.clear(); return 0; } From 0936dbdd03ced9b3cb55fa938b1e7f93858bfaf1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 4 Apr 2008 12:26:53 +0000 Subject: [PATCH 18/65] Add missing include for is_void [SVN r44030] --- include/boost/function/detail/prologue.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index ab2b323..7b41637 100644 --- a/include/boost/function/detail/prologue.hpp +++ b/include/boost/function/detail/prologue.hpp @@ -22,4 +22,5 @@ # include # include # include +# include #endif // BOOST_FUNCTION_PROLOGUE_HPP From fe2d04e95431fefc736b3cb8d1d3dc4c87b61c41 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Thu, 17 Apr 2008 15:49:39 +0000 Subject: [PATCH 19/65] Change include so that it still works when Boost.TR1 is in the include path. [SVN r44506] --- include/boost/function/detail/prologue.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/detail/prologue.hpp b/include/boost/function/detail/prologue.hpp index 7b41637..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 From 04040ae5662bf89d8dfa56a5e587fc6dc7f975bc Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 28 Apr 2008 14:11:46 +0000 Subject: [PATCH 20/65] Improve documentation on the size/efficiency of boost::function objects [SVN r44852] --- doc/misc.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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.
From bacb5d67527b5e696ea1f89928373042b54fd110 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 17 Jun 2008 13:59:04 +0000 Subject: [PATCH 21/65] Attempt to work around problem with allocator casts in Boost.Function [SVN r46446] --- include/boost/function/function_base.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 7d667ae..8d46711 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -432,7 +432,7 @@ namespace boost { // 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_type wrapper_allocator(static_cast(*f)); wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); wrapper_allocator.construct(copy, *f); @@ -443,7 +443,7 @@ namespace boost { /* 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_type wrapper_allocator(static_cast(*victim)); wrapper_allocator.destroy(victim); wrapper_allocator.deallocate(victim,1); out_buffer.obj_ptr = 0; From e3dfa7268aa7ee96bac8aa53a64f3bd7507d9625 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 5 Sep 2008 14:55:34 +0000 Subject: [PATCH 22/65] Add forward-declaration header for Boost.Function. Fixes #1668 [SVN r48613] --- include/boost/function/function_base.hpp | 32 +---------- include/boost/function/function_fwd.hpp | 67 ++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 include/boost/function/function_fwd.hpp diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 8d46711..ea92b25 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -30,6 +30,7 @@ # include "boost/mpl/bool.hpp" #endif #include +#include #if defined(BOOST_MSVC) # pragma warning( push ) @@ -63,21 +64,6 @@ # 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) # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \ @@ -92,22 +78,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 { diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp new file mode 100644 index 0000000..7a1ad52 --- /dev/null +++ b/include/boost/function/function_fwd.hpp @@ -0,0 +1,67 @@ +// 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 { +#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 From d5a86a2d527230359d5d00b95bad3fd93af944c1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 5 Sep 2008 15:43:22 +0000 Subject: [PATCH 23/65] Improve the performance of Boost.Function's swap. Thanks to Niels Dekker for the original patch. Fixes #1910 [SVN r48615] --- doc/history.xml | 8 +++ include/boost/function/function_base.hpp | 25 ++++++++-- include/boost/function/function_fwd.hpp | 2 + include/boost/function/function_template.hpp | 33 +++++++++++-- test/Jamfile.v2 | 1 + test/nothrow_swap.cpp | 51 ++++++++++++++++++++ 6 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 test/nothrow_swap.cpp diff --git a/doc/history.xml b/doc/history.xml index eb5a442..c79b11a 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -13,6 +13,14 @@ + Version 1.37.0: + + Improved the performance of Boost.Function's + swap() operation for large function objects. Original patch + contributed by Niels Dekker. + + + 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 ea92b25..b74f43a 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -92,7 +92,7 @@ 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). @@ -138,6 +138,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 @@ -182,6 +183,11 @@ namespace boost { out_buffer.obj_ptr = in_buffer.obj_ptr; return; + case move_functor_tag: + out_buffer.obj_ptr = in_buffer.obj_ptr; + in_buffer.obj_ptr = 0; + return; + case destroy_functor_tag: out_buffer.obj_ptr = 0; return; @@ -247,7 +253,10 @@ 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 = @@ -264,10 +273,14 @@ 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(); @@ -317,6 +330,9 @@ 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 = @@ -409,6 +425,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 = diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp index 7a1ad52..1f9b0c8 100644 --- a/include/boost/function/function_fwd.hpp +++ b/include/boost/function/function_fwd.hpp @@ -26,6 +26,8 @@ namespace boost { namespace python { namespace objects { #endif namespace boost { + class bad_function_call; + #if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) // Preferred syntax template class function; diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index a575ebf..e34ff5e 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -729,9 +729,10 @@ 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 @@ -786,6 +787,32 @@ namespace boost { if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable; 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); +#if !defined(BOOST_NO_EXCEPTIONS) + } else { + clear(); + } + } catch (...) { + vtable = 0; + throw; + } +#endif + } }; template diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8ab92b1..f309b41 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -58,6 +58,7 @@ import testing ; [ run libs/function/test/contains2_test.cpp : : : : ] + [ run libs/function/test/nothrow_swap.cpp : : : : ] ; } diff --git a/test/nothrow_swap.cpp b/test/nothrow_swap.cpp new file mode 100644 index 0000000..4f222bc --- /dev/null +++ b/test/nothrow_swap.cpp @@ -0,0 +1,51 @@ +#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; +} From ea18f5777b458c88e92a3b31bc1356a08cb77faf Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 5 Sep 2008 16:13:49 +0000 Subject: [PATCH 24/65] Add Boost.Typeof support to Boost.Function. Fixes #1621 [SVN r48616] --- doc/history.xml | 4 ++ include/boost/function/function_fwd.hpp | 1 + include/boost/function/function_typeof.hpp | 45 ++++++++++++++++++++++ test/Jamfile.v2 | 2 + test/function_typeof_test.cpp | 18 +++++++++ test/nothrow_swap.cpp | 9 +++++ 6 files changed, 79 insertions(+) create mode 100644 include/boost/function/function_typeof.hpp create mode 100644 test/function_typeof_test.cpp diff --git a/doc/history.xml b/doc/history.xml index c79b11a..a7f89df 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -18,6 +18,10 @@ 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. diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp index 1f9b0c8..d2f713a 100644 --- a/include/boost/function/function_fwd.hpp +++ b/include/boost/function/function_fwd.hpp @@ -66,4 +66,5 @@ namespace boost { typename T10> class function10; } + #endif 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 f309b41..ef4e0d1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -59,6 +59,8 @@ 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/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 index 4f222bc..0a5b740 100644 --- a/test/nothrow_swap.cpp +++ b/test/nothrow_swap.cpp @@ -1,3 +1,12 @@ +// 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 From f379ef85329b5702fcef46ac64b11e1cbc93c1d9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 5 Sep 2008 17:52:12 +0000 Subject: [PATCH 25/65] Make Boost.Function's target() operation respect the cv-qualifiers of referenced function objects. Fixes #736 [SVN r48618] --- doc/history.xml | 8 ++ include/boost/function/function_base.hpp | 109 +++++++++++++------ include/boost/function/function_template.hpp | 8 +- test/contains_test.cpp | 9 ++ 4 files changed, 98 insertions(+), 36 deletions(-) diff --git a/doc/history.xml b/doc/history.xml index a7f89df..05fddf8 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -22,6 +22,14 @@ 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. diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index b74f43a..064fdde 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -95,8 +97,15 @@ namespace boost { 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 std::type_info* type; + + // Whether the type is const-qualified. + bool const_qualified : 1; + // Whether the type is volatile-qualified. + bool volatile_qualified : 1; + } type; // For function pointers of all kinds mutable void (*func_ptr)(); @@ -107,6 +116,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 : 1; + bool is_volatile : 1; + } obj_ref; + // To relax aliasing constraints mutable char data; }; @@ -180,34 +197,40 @@ namespace boost { { 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_ptr = in_buffer.obj_ptr; - in_buffer.obj_ptr = 0; + 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 + || out_buffer.type.const_qualified) + && (!in_buffer.obj_ref.is_volatile + || 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; + out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile; return; } } @@ -258,13 +281,17 @@ namespace boost { 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; } } @@ -284,13 +311,17 @@ namespace boost { } 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; } } }; @@ -339,13 +370,17 @@ namespace boost { 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; } } @@ -370,7 +405,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: @@ -436,13 +473,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; } } @@ -467,7 +508,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: @@ -575,7 +618,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 @@ -584,7 +627,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); @@ -600,7 +645,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_template.hpp b/include/boost/function/function_template.hpp index e34ff5e..a3ee7c1 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -516,11 +516,9 @@ namespace boost { 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 = is_const::value; + functor.obj_ref.is_volatile = is_volatile::value; return true; } else { return false; 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() From 2fe4cc253f39452de7664389c1698c51ad24f26e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 6 Sep 2008 03:16:25 +0000 Subject: [PATCH 26/65] Fix double-destruction problem with small function objects and swap(), and try to work around a GCC 4.2 issue. See #1910 for comments about the former problem from Niels Dekker. [SVN r48627] --- include/boost/function/function_base.hpp | 18 ++++---- include/boost/function/function_template.hpp | 5 ++- test/function_n_test.cpp | 47 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 064fdde..8c8ad3b 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -99,12 +99,12 @@ namespace boost { // For pointers to std::type_info objects struct type_t { // (get_functor_type_tag, check_functor_type_tag). - const std::type_info* type; + const BOOST_FUNCTION_STD_NS::type_info* type; // Whether the type is const-qualified. - bool const_qualified : 1; + bool const_qualified; // Whether the type is volatile-qualified. - bool volatile_qualified : 1; + bool volatile_qualified; } type; // For function pointers of all kinds @@ -120,8 +120,8 @@ namespace boost { // track of the cv-qualifiers on the object referenced. struct obj_ref_t { mutable void* obj_ptr; - bool is_const : 1; - bool is_volatile : 1; + bool is_const_qualified; + bool is_volatile_qualified; } obj_ref; // To relax aliasing constraints @@ -217,9 +217,9 @@ namespace boost { // 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 + && (!in_buffer.obj_ref.is_const_qualified || out_buffer.type.const_qualified) - && (!in_buffer.obj_ref.is_volatile + && (!in_buffer.obj_ref.is_volatile_qualified || out_buffer.type.volatile_qualified)) out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr; else @@ -229,8 +229,8 @@ namespace boost { case get_functor_type_tag: out_buffer.type.type = &typeid(F); - out_buffer.type.const_qualified = in_buffer.obj_ref.is_const; - out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile; + 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; } } diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index a3ee7c1..7730903 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -517,8 +517,8 @@ namespace boost { { if (!boost::detail::function::has_empty_target(f.get_pointer())) { functor.obj_ref.obj_ptr = (void *)f.get_pointer(); - functor.obj_ref.is_const = is_const::value; - functor.obj_ref.is_volatile = is_volatile::value; + functor.obj_ref.is_const_qualified = is_const::value; + functor.obj_ref.is_volatile_qualified = is_volatile::value; return true; } else { return false; @@ -801,6 +801,7 @@ namespace boost { 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(); diff --git a/test/function_n_test.cpp b/test/function_n_test.cpp index 14439a8..5d8d0d5 100644 --- a/test/function_n_test.cpp +++ b/test/function_n_test.cpp @@ -636,6 +636,52 @@ 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; } + }; + +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 +690,6 @@ int test_main(int, char* []) test_emptiness(); test_member_functions(); test_ref(); + test_construct_destroy_count(); return 0; } From da259e8dcedee00bf5277d88016baedcce9bd7fd Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 6 Sep 2008 16:30:58 +0000 Subject: [PATCH 27/65] Make MyLargeFunctor large. [SVN r48633] --- test/function_n_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/function_n_test.cpp b/test/function_n_test.cpp index 5d8d0d5..cdd7145 100644 --- a/test/function_n_test.cpp +++ b/test/function_n_test.cpp @@ -651,6 +651,8 @@ struct MyLargeFunctor { MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; } ~MyLargeFunctor() { ++destruction_count; } int operator()() { return 0; } + + float data[128]; }; void test_construct_destroy_count() From 75890fea53b499a80b2bace3708583964a8da456 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 23 Sep 2008 00:26:21 +0000 Subject: [PATCH 28/65] CodeGear C++ fix, from Nicola Musatti. Fixes #2325 [SVN r48922] --- include/boost/function/function_base.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 8c8ad3b..c23778b 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ # define BOOST_FUNCTION_TARGET_FIX(x) #endif // not MSVC -#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), \ From 8ca7384121964a7df9f8aa070a2d267e2d1403e8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 14 Oct 2008 15:31:57 +0000 Subject: [PATCH 29/65] Fix Boost.Function thread safety issue again [SVN r49326] --- include/boost/function/function_base.hpp | 13 +- include/boost/function/function_template.hpp | 403 +++++++++++++------ 2 files changed, 287 insertions(+), 129 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index c23778b..6612fb8 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -193,8 +193,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: @@ -396,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. */ @@ -589,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); diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 7730903..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,27 +619,6 @@ 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, @@ -533,6 +642,7 @@ namespace boost { } public: + vtable_base base; invoker_type invoker; }; } // end namespace function @@ -737,7 +847,7 @@ namespace boost { void clear() { if (vtable) { - static_cast(vtable)->clear(this->functor); + reinterpret_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -774,15 +884,53 @@ 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; } @@ -837,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 @@ -964,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 From f559986ae8e89f8f0e56da53706cbd14bf19890e Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Sat, 1 Nov 2008 13:15:41 +0000 Subject: [PATCH 30/65] Continuing merge of CMake build system files into trunk with the encouragement of Doug Gregor [SVN r49510] --- CMakeLists.txt | 22 ++++++++++++++++++++++ doc/CMakeLists.txt | 2 ++ test/CMakeLists.txt | 20 ++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 doc/CMakeLists.txt create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..09cdec5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +#---------------------------------------------------------------------------- +# This file was automatically generated from the original CMakeLists.txt file +# Add a variable to hold the headers for the library +set (lib_headers + function.hpp + function +) + +# Add a library target to the build system +boost_library_project( + function + # SRCDIRS + TESTDIRS test + HEADERS ${lib_headers} + DOCDIRS doc + # DESCRIPTION + MODULARIZED + # AUTHORS + # MAINTAINERS +) + + diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000..f8483bf --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,2 @@ +boost_add_documentation(function.xml + faq.xml history.xml misc.xml reference.xml tests.xml tutorial.xml) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..51c4280 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,20 @@ +boost_test_run(lib_function_test function_test.cpp) +boost_test_run(function_n_test) +boost_test_run(allocator_test) +boost_test_run(stateless_test) +boost_test_run(lambda_test) +boost_test_compile_fail(function_test_fail1) +boost_test_compile_fail(function_test_fail2) +boost_test_compile(function_30) +boost_test_run(function_arith_cxx98) +boost_test_run(function_arith_portable) +boost_test_run(sum_avg_cxx98) +boost_test_run(sum_avg_portable) +boost_test_run(mem_fun_cxx98) +boost_test_run(mem_fun_portable) +boost_test_run(std_bind_cxx98) +boost_test_run(std_bind_portable) +boost_test_run(function_ref_cxx98) +boost_test_run(function_ref_portable) +boost_test_run(contains_test) +boost_test_run(contains2_test) From 07800455a89babc061e3dc72b75a6cb03048a7d5 Mon Sep 17 00:00:00 2001 From: "K. Noel Belcourt" Date: Mon, 3 Nov 2008 18:37:49 +0000 Subject: [PATCH 31/65] Both Sun and Pgi on Linux correctly put typeinfo into the std namespace, but function_base keys off the BOOST_NO_EXCEPTION_STD_NAMESPACE macro instead of the BOOST_NO_STD_TYPEINFO macro. The attached patch changes function_base to use the typeinfo macro. Because eVC 4.2 doesn't put typeinfo into the std namespace, I need to define BOOST_NO_STD_TYPEINFO only for this eVC version. [SVN r49571] --- include/boost/function/function_base.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 6612fb8..35afa16 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -42,7 +42,7 @@ #endif // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info. -#ifdef BOOST_NO_EXCEPTION_STD_NAMESPACE +#ifdef BOOST_NO_STD_TYPEINFO // Embedded VC++ does not have type_info in namespace std # define BOOST_FUNCTION_STD_NS #else From e8504c1777dcad593c2e01ceaaab6fc8a462ebe5 Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Fri, 7 Nov 2008 17:02:56 +0000 Subject: [PATCH 32/65] Updating CMake files to latest trunk. Added dependency information for regression tests and a few new macros for internal use. [SVN r49627] --- test/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 51c4280..2230181 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,6 @@ +boost_additional_test_dependencies(function BOOST_DEPENDS test lambda) + + boost_test_run(lib_function_test function_test.cpp) boost_test_run(function_n_test) boost_test_run(allocator_test) From 529dc74954fd437289b92040a3b087f90a4aa0dd Mon Sep 17 00:00:00 2001 From: "Michael A. Jackson" Date: Fri, 7 Nov 2008 17:05:27 +0000 Subject: [PATCH 33/65] Updating dependency information for modularized libraries. [SVN r49628] --- module.cmake | 1 + 1 file changed, 1 insertion(+) create mode 100644 module.cmake diff --git a/module.cmake b/module.cmake new file mode 100644 index 0000000..052e0cf --- /dev/null +++ b/module.cmake @@ -0,0 +1 @@ +boost_module(function DEPENDS detail preprocessor utility) From 821e6d34ddfe7fdce3f9a50b5f398ce70201b4ea Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 2 Dec 2008 10:10:46 +0000 Subject: [PATCH 34/65] Fix -Wundef warning and suspect usage of BOOST_STRICT_CONFIG. [SVN r50064] --- include/boost/function/function_fwd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_fwd.hpp b/include/boost/function/function_fwd.hpp index d2f713a..fb318c9 100644 --- a/include/boost/function/function_fwd.hpp +++ b/include/boost/function/function_fwd.hpp @@ -21,7 +21,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 From 678fb133f08fd6a3c2e7095d69750fcede05cec1 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 17 Feb 2009 10:05:58 +0000 Subject: [PATCH 35/65] Add PDF generation options to fix external links to point to the web site. Added a few more Boostbook based libs that were missed first time around. Fixed PDF naming issues. [SVN r51284] --- doc/Jamfile.v2 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 8d76ce5..b1dd5ab 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -6,5 +6,10 @@ project boost/doc ; import boostbook : boostbook ; -boostbook function-doc : function.xml ; +boostbook function-doc + : + function.xml + : + pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html + ; From 6f8ec5c8c5565b56dca38d9e7d2393ea0d963db2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Mar 2009 05:23:53 +0000 Subject: [PATCH 36/65] Implement an optimization that David Abrahams and myself came up with, where Boost.Function uses a bit in the vtable pointer to indicate when the target function object has a trivial copy constructor, trivial destructor, and fits within the small object buffer. In this case, we just copy the bits of the function object rather than performing an indirect call to the manager. This results in a 60% speedup on a micro-benchmark that copies and calls such function objects repeatedly. [SVN r51743] --- include/boost/function/function_base.hpp | 18 +++++-- include/boost/function/function_template.hpp | 53 +++++++++++++++----- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 35afa16..2cc6bf6 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -625,7 +628,7 @@ public: if (!vtable) return typeid(void); detail::function::function_buffer type; - vtable->manager(functor, type, detail::function::get_functor_type_tag); + get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); return *type.type.type; } @@ -638,7 +641,7 @@ public: type_result.type.type = &typeid(Functor); type_result.type.const_qualified = is_const::value; type_result.type.volatile_qualified = is_volatile::value; - vtable->manager(functor, type_result, + get_vtable()->manager(functor, type_result, detail::function::check_functor_type_tag); return static_cast(type_result.obj_ptr); } @@ -656,7 +659,7 @@ public: type_result.type.type = &typeid(Functor); type_result.type.const_qualified = true; type_result.type.volatile_qualified = is_volatile::value; - vtable->manager(functor, type_result, + get_vtable()->manager(functor, type_result, detail::function::check_functor_type_tag); // GCC 2.95.3 gets the CV qualifiers wrong here, so we // can't do the static_cast that we should do. @@ -702,6 +705,15 @@ public: #endif public: // should be protected, but GCC 2.95.3 will fail to allow access + detail::function::vtable_base* get_vtable() const { + return reinterpret_cast( + reinterpret_cast(vtable) & ~(std::size_t)0x01); + } + + bool has_trivial_copy_and_destroy() const { + return reinterpret_cast(vtable) & 0x01; + } + detail::function::vtable_base* vtable; mutable detail::function::function_buffer functor; }; diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 584abe9..23687b4 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -678,6 +678,11 @@ namespace boost { R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS> vtable_type; + vtable_type* get_vtable() const { + return reinterpret_cast( + reinterpret_cast(vtable) & ~(std::size_t)0x01); + } + struct clear_type {}; public: @@ -757,7 +762,7 @@ namespace boost { if (this->empty()) boost::throw_exception(bad_function_call()); - return static_cast(vtable)->invoker + return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #else @@ -847,7 +852,8 @@ namespace boost { void clear() { if (vtable) { - reinterpret_cast(vtable)->clear(this->functor); + if (!this->has_trivial_copy_and_destroy()) + get_vtable()->clear(this->functor); vtable = 0; } } @@ -876,8 +882,11 @@ namespace boost { { if (!f.empty()) { this->vtable = f.vtable; - f.vtable->manager(f.functor, this->functor, - boost::detail::function::clone_functor_tag); + if (this->has_trivial_copy_and_destroy()) + this->functor = f.functor; + else + get_vtable()->base.manager(f.functor, this->functor, + boost::detail::function::clone_functor_tag); } } @@ -903,8 +912,15 @@ namespace boost { static vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; - if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base; - else vtable = 0; + if (stored_vtable.assign_to(f, functor)) { + std::size_t value = reinterpret_cast(&stored_vtable.base); + if (boost::has_trivial_copy_constructor::value && + boost::has_trivial_destructor::value && + detail::function::function_allows_small_object_optimization::value) + value |= (std::size_t)0x01; + vtable = reinterpret_cast(value); + } else + vtable = 0; } template @@ -930,8 +946,15 @@ namespace boost { static vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; - if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base; - else vtable = 0; + if (stored_vtable.assign_to_a(f, functor, a)) { + std::size_t value = reinterpret_cast(&stored_vtable.base); + if (boost::has_trivial_copy_constructor::value && + boost::has_trivial_destructor::value && + detail::function::function_allows_small_object_optimization::value) + value |= (std::size_t)0x01; + vtable = reinterpret_cast(value); + } else + vtable = 0; } // Moves the value from the specified argument to *this. If the argument @@ -947,9 +970,12 @@ namespace boost { #endif if (!f.empty()) { this->vtable = f.vtable; - f.vtable->manager(f.functor, this->functor, - boost::detail::function::move_functor_tag); - f.vtable = 0; + if (this->has_trivial_copy_and_destroy()) + this->functor = f.functor; + else + get_vtable()->base.manager(f.functor, this->functor, + boost::detail::function::move_functor_tag); + f.vtable = 0; #if !defined(BOOST_NO_EXCEPTIONS) } else { clear(); @@ -979,13 +1005,14 @@ namespace boost { template typename BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type - BOOST_FUNCTION_FUNCTION + inline + BOOST_FUNCTION_FUNCTION ::operator()(BOOST_FUNCTION_PARMS) const { if (this->empty()) boost::throw_exception(bad_function_call()); - return reinterpret_cast(vtable)->invoker + return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } #endif From a74e72cce9b6423b72124709f0f41246cd9f8e8b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 Mar 2009 05:49:02 +0000 Subject: [PATCH 37/65] Make Boost.Function compile under BOOST_NO_EXCEPTIONS. Fixes #2499 Fixes #2494 Fixes #2469 Fixes #2466 [SVN r51745] --- include/boost/function/function_template.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 23687b4..5f5ea0b 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -976,10 +976,10 @@ namespace boost { get_vtable()->base.manager(f.functor, this->functor, boost::detail::function::move_functor_tag); f.vtable = 0; -#if !defined(BOOST_NO_EXCEPTIONS) } else { clear(); } +#if !defined(BOOST_NO_EXCEPTIONS) } catch (...) { vtable = 0; throw; From e10f4eaef98c3d49bfd8fbedc7b2ed2966d82f72 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 6 Jun 2009 15:31:47 +0000 Subject: [PATCH 38/65] Add missing #pragma warning(pop). Fixes #2767. [SVN r53694] --- include/boost/function/function_base.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 2cc6bf6..fe8e17d 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -889,4 +889,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 From 68128bfffa65118692f66572438de60ef5f326c1 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sun, 7 Jun 2009 15:44:50 +0000 Subject: [PATCH 39/65] Make Boost.Function compile with disabled exceptions. Closes #2900. Patch from Gabi Davar. [SVN r53722] --- include/boost/function/function_template.hpp | 33 ++++++++++---------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 5f5ea0b..e02b9bd 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -11,6 +11,7 @@ // Note: this header is a header template and must NOT have multiple-inclusion // protection. #include +#include #if defined(BOOST_MSVC) # pragma warning( push ) @@ -786,24 +787,26 @@ namespace boost { operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { this->clear(); - try { + BOOST_TRY { this->assign_to(f); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END return *this; } template void assign(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a) { this->clear(); - try { + BOOST_TRY{ this->assign_to_a(f,a); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END } #ifndef BOOST_NO_SFINAE @@ -828,12 +831,13 @@ namespace boost { return *this; this->clear(); - try { + BOOST_TRY { this->assign_to_own(f); - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } + BOOST_CATCH_END return *this; } @@ -965,9 +969,7 @@ namespace boost { if (&f == this) return; -#if !defined(BOOST_NO_EXCEPTIONS) - try { -#endif + BOOST_TRY { if (!f.empty()) { this->vtable = f.vtable; if (this->has_trivial_copy_and_destroy()) @@ -979,12 +981,11 @@ namespace boost { } else { clear(); } -#if !defined(BOOST_NO_EXCEPTIONS) - } catch (...) { + } BOOST_CATCH (...) { vtable = 0; - throw; + BOOST_RETHROW; } -#endif + BOOST_CATCH_END } }; From ff3244d562ffc9ba2ee66b929702c483377fb08f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 3 Jul 2009 22:20:26 +0000 Subject: [PATCH 40/65] When copying boost::ref, copy even when the referenced function is empty. Fixes #2642 Patch by Steven Watanabe [SVN r54616] --- include/boost/function/function_template.hpp | 12 ++++------ test/function_test.cpp | 25 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index e02b9bd..6a99109 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -625,14 +625,10 @@ namespace boost { assign_to(const reference_wrapper& f, function_buffer& functor, function_obj_ref_tag) { - if (!boost::detail::function::has_empty_target(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; - } + 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; } template bool diff --git a/test/function_test.cpp b/test/function_test.cpp index 9870ac7..faf4bfb 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -629,6 +629,30 @@ test_ref() } } +static void dummy() {} + +static void test_empty_ref() +{ + boost::function f1; + boost::function f2(boost::ref(f1)); + + try { + f2(); + BOOST_ERROR("Exception didn't throw for reference to empty function."); + } + catch(runtime_error e) {} + + f1 = dummy; + + try { + f2(); + } + catch(runtime_error e) { + BOOST_ERROR("Error calling referenced function."); + } +} + + static void test_exception() { boost::function f; @@ -674,6 +698,7 @@ int test_main(int, char* []) test_emptiness(); test_member_functions(); test_ref(); + test_empty_ref(); test_exception(); test_implicit(); test_call(); From e8247198fa3af8470805bb627f79006612c23d4f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 3 Jul 2009 22:20:52 +0000 Subject: [PATCH 41/65] Add 'and later versions' to support info for GCC and Visual C++. Fixes #2847. I didn't explicitly specify the versions since no one's updating this list and it's highly unlikely that a future version will break this. The same could probably be done for the other compilers but I don't know them very well so I'm leaving them alone. [SVN r54617] --- doc/tutorial.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tutorial.xml b/doc/tutorial.xml index d369392..f8f2294 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -35,12 +35,12 @@ form to use for your compiler. - GNU C++ 2.95.x, 3.0.x, 3.1.x + GNU C++ since 2.95.x Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 Compaq's cxx 6.2 - Microsoft Visual C++ 7.1 + Microsoft Visual C++ since 7.1 From ae534d73424b93bc1f78bc88e50984bee404013c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 3 Jul 2009 22:21:40 +0000 Subject: [PATCH 42/65] Fix Boost.Function unit tests for C++0x. Fixes #3012 Based on a patch from Richard Webb. Changed a bit so that it also works for the Visual C++ 10 beta. [SVN r54618] --- doc/tutorial.xml | 4 ++-- test/function_test.cpp | 18 +++++++++--------- test/lambda_test.cpp | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/tutorial.xml b/doc/tutorial.xml index f8f2294..1e2eba8 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -35,12 +35,12 @@ form to use for your compiler. - GNU C++ since 2.95.x + GNU C++ 2.95.x, 3.0.x and later verseions Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 Compaq's cxx 6.2 - Microsoft Visual C++ since 7.1 + Microsoft Visual C++ 7.1 and later versions diff --git a/test/function_test.cpp b/test/function_test.cpp index faf4bfb..65d6e58 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -13,8 +13,8 @@ #include #include -using namespace boost; -using namespace std; +using boost::function; +using std::string; int global_int; @@ -525,7 +525,7 @@ test_zero_args() static void test_one_arg() { - negate neg; + std::negate neg; function f1(neg); BOOST_CHECK(f1(5) == -5); @@ -607,12 +607,12 @@ struct add_with_throw_on_copy { add_with_throw_on_copy(const add_with_throw_on_copy&) { - throw runtime_error("But this CAN'T throw"); + throw std::runtime_error("But this CAN'T throw"); } add_with_throw_on_copy& operator=(const add_with_throw_on_copy&) { - throw runtime_error("But this CAN'T throw"); + throw std::runtime_error("But this CAN'T throw"); } }; @@ -621,10 +621,10 @@ test_ref() { add_with_throw_on_copy atc; try { - boost::function f(ref(atc)); + boost::function f(boost::ref(atc)); BOOST_CHECK(f(1, 3) == 4); } - catch(runtime_error e) { + catch(std::runtime_error e) { BOOST_ERROR("Nonthrowing constructor threw an exception"); } } @@ -640,14 +640,14 @@ static void test_empty_ref() f2(); BOOST_ERROR("Exception didn't throw for reference to empty function."); } - catch(runtime_error e) {} + catch(std::runtime_error e) {} f1 = dummy; try { f2(); } - catch(runtime_error e) { + catch(std::runtime_error e) { BOOST_ERROR("Error calling referenced function."); } } diff --git a/test/lambda_test.cpp b/test/lambda_test.cpp index 97fa7f8..2abca54 100644 --- a/test/lambda_test.cpp +++ b/test/lambda_test.cpp @@ -15,21 +15,21 @@ #include #include -using namespace std; -using namespace boost; -using namespace boost::lambda; - static unsigned func_impl(int arg1, bool arg2, double arg3) { + using namespace std; return abs (static_cast((arg2 ? arg1 : 2 * arg1) * arg3)); } int test_main(int, char*[]) { + using boost::function; + using namespace boost::lambda; + function f1 = bind(func_impl, 15, _1, _2); - function f2 = bind(f1, false, _1); - function f3 = bind(f2, 4.0); + function f2 = boost::lambda::bind(f1, false, _1); + function f3 = boost::lambda::bind(f2, 4.0); f3(); From 8b63c146ea13bd6f21bdd5013b24a830e9ebd528 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Fri, 3 Jul 2009 22:22:03 +0000 Subject: [PATCH 43/65] Work around Visual C++ copy constructor bug. Fixes #2929. Based on the patch by Steven Watanabe. [SVN r54619] --- include/boost/function/function_base.hpp | 6 ++++++ test/allocator_test.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index fe8e17d..c4663c3 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -262,6 +262,12 @@ namespace boost { A(a) { } + + functor_wrapper(const functor_wrapper& f) : + F(static_cast(f)), + A(static_cast(f)) + { + } }; /** diff --git a/test/allocator_test.cpp b/test/allocator_test.cpp index 7b35f16..3643b2b 100644 --- a/test/allocator_test.cpp +++ b/test/allocator_test.cpp @@ -128,6 +128,10 @@ test_main(int, char*[]) BOOST_CHECK(dealloc_count == 0); fv.assign( &do_nothing, std::allocator() ); fv.clear(); + + function0 fv2; + fv.assign(&do_nothing, std::allocator() ); + fv2.assign(fv, std::allocator() ); return 0; } From 2020d39e2c89f8c9aa8571ef9e31f7e907a0b7ee Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 12 Jul 2009 15:53:54 +0000 Subject: [PATCH 44/65] Fix a typo. [SVN r54909] --- doc/tutorial.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial.xml b/doc/tutorial.xml index 1e2eba8..ed3812b 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -35,7 +35,7 @@ form to use for your compiler. - GNU C++ 2.95.x, 3.0.x and later verseions + GNU C++ 2.95.x, 3.0.x and later versions Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 From 81c78765881a73f053428def939eab44a71424ea Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sun, 26 Jul 2009 00:49:56 +0000 Subject: [PATCH 45/65] Copyrights on CMakeLists.txt to keep them from clogging up the inspect reports. This is essentially the same commit as r55095 on the release branch. [SVN r55159] --- CMakeLists.txt | 6 ++++++ doc/CMakeLists.txt | 6 ++++++ test/CMakeLists.txt | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09cdec5..a052a8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# #---------------------------------------------------------------------------- # This file was automatically generated from the original CMakeLists.txt file # Add a variable to hold the headers for the library diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index f8483bf..dd5603f 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,2 +1,8 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# boost_add_documentation(function.xml faq.xml history.xml misc.xml reference.xml tests.xml tutorial.xml) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2230181..2f3c771 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,9 @@ +# +# Copyright Troy D. Straszheim +# +# Distributed under the Boost Software License, Version 1.0. +# See http://www.boost.org/LICENSE_1_0.txt +# boost_additional_test_dependencies(function BOOST_DEPENDS test lambda) From a1f62de42051973096f6aa977ef1bc825c02e361 Mon Sep 17 00:00:00 2001 From: "Troy D. Straszheim" Date: Sat, 17 Oct 2009 02:07:38 +0000 Subject: [PATCH 46/65] rm cmake from trunk. I'm not entirely sure this is necessary to satisfy the inspect script, but I'm not taking any chances, and it is easy to put back [SVN r56942] --- CMakeLists.txt | 28 ---------------------------- doc/CMakeLists.txt | 8 -------- module.cmake | 1 - test/CMakeLists.txt | 29 ----------------------------- 4 files changed, 66 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 doc/CMakeLists.txt delete mode 100644 module.cmake delete mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index a052a8a..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -#---------------------------------------------------------------------------- -# This file was automatically generated from the original CMakeLists.txt file -# Add a variable to hold the headers for the library -set (lib_headers - function.hpp - function -) - -# Add a library target to the build system -boost_library_project( - function - # SRCDIRS - TESTDIRS test - HEADERS ${lib_headers} - DOCDIRS doc - # DESCRIPTION - MODULARIZED - # AUTHORS - # MAINTAINERS -) - - diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt deleted file mode 100644 index dd5603f..0000000 --- a/doc/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -boost_add_documentation(function.xml - faq.xml history.xml misc.xml reference.xml tests.xml tutorial.xml) diff --git a/module.cmake b/module.cmake deleted file mode 100644 index 052e0cf..0000000 --- a/module.cmake +++ /dev/null @@ -1 +0,0 @@ -boost_module(function DEPENDS detail preprocessor utility) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 2f3c771..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright Troy D. Straszheim -# -# Distributed under the Boost Software License, Version 1.0. -# See http://www.boost.org/LICENSE_1_0.txt -# -boost_additional_test_dependencies(function BOOST_DEPENDS test lambda) - - -boost_test_run(lib_function_test function_test.cpp) -boost_test_run(function_n_test) -boost_test_run(allocator_test) -boost_test_run(stateless_test) -boost_test_run(lambda_test) -boost_test_compile_fail(function_test_fail1) -boost_test_compile_fail(function_test_fail2) -boost_test_compile(function_30) -boost_test_run(function_arith_cxx98) -boost_test_run(function_arith_portable) -boost_test_run(sum_avg_cxx98) -boost_test_run(sum_avg_portable) -boost_test_run(mem_fun_cxx98) -boost_test_run(mem_fun_portable) -boost_test_run(std_bind_cxx98) -boost_test_run(std_bind_portable) -boost_test_run(function_ref_cxx98) -boost_test_run(function_ref_portable) -boost_test_run(contains_test) -boost_test_run(contains2_test) From 22c6592a409e6cf602d5563bc0a45484b180a643 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 3 Dec 2009 20:59:32 +0000 Subject: [PATCH 47/65] Fix function_base.hpp to not require typeid. Refs #3666. Requires [58127]. [SVN r58128] --- include/boost/function/function_base.hpp | 52 ++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index c4663c3..eb201a8 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -54,7 +54,9 @@ // 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) \ +#if defined( BOOST_NO_TYPEID ) +# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) +#elif (defined(__GNUC__) && __GNUC__ >= 3) \ || defined(_AIX) \ || ( defined(__sgi) && defined(__host_mips)) # include @@ -103,7 +105,7 @@ namespace boost { // For pointers to std::type_info objects struct type_t { // (get_functor_type_tag, check_functor_type_tag). - const BOOST_FUNCTION_STD_NS::type_info* type; + const detail::sp_typeinfo* type; // Whether the type is const-qualified. bool const_qualified; @@ -215,12 +217,12 @@ namespace boost { case check_functor_type_tag: { - const BOOST_FUNCTION_STD_NS::type_info& check_type + const detail::sp_typeinfo& 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)) + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(F)) && (!in_buffer.obj_ref.is_const_qualified || out_buffer.type.const_qualified) && (!in_buffer.obj_ref.is_volatile_qualified @@ -232,7 +234,7 @@ namespace boost { return; case get_functor_type_tag: - out_buffer.type.type = &typeid(F); + out_buffer.type.type = &BOOST_SP_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; @@ -292,14 +294,14 @@ namespace boost { } else if (op == destroy_functor_tag) out_buffer.func_ptr = 0; else if (op == check_functor_type_tag) { - const BOOST_FUNCTION_STD_NS::type_info& check_type + const detail::sp_typeinfo& check_type = *out_buffer.type.type; - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_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.type = &BOOST_SP_TYPEID(Functor); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; } @@ -322,14 +324,14 @@ namespace boost { // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. reinterpret_cast(&out_buffer.data)->~Functor(); } else if (op == check_functor_type_tag) { - const BOOST_FUNCTION_STD_NS::type_info& check_type + const detail::sp_typeinfo& check_type = *out_buffer.type.type; - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_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.type = &BOOST_SP_TYPEID(Functor); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; } @@ -381,14 +383,14 @@ namespace boost { delete f; out_buffer.obj_ptr = 0; } else if (op == check_functor_type_tag) { - const BOOST_FUNCTION_STD_NS::type_info& check_type + const detail::sp_typeinfo& check_type = *out_buffer.type.type; - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_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.type = &BOOST_SP_TYPEID(Functor); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; } @@ -423,7 +425,7 @@ namespace boost { typedef typename get_function_tag::type tag_type; switch (op) { case get_functor_type_tag: - out_buffer.type.type = &typeid(functor_type); + out_buffer.type.type = &BOOST_SP_TYPEID(functor_type); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; return; @@ -492,14 +494,14 @@ namespace boost { wrapper_allocator.deallocate(victim,1); out_buffer.obj_ptr = 0; } else if (op == check_functor_type_tag) { - const BOOST_FUNCTION_STD_NS::type_info& check_type + const detail::sp_typeinfo& check_type = *out_buffer.type.type; - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_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.type = &BOOST_SP_TYPEID(Functor); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; } @@ -526,7 +528,7 @@ namespace boost { typedef typename get_function_tag::type tag_type; switch (op) { case get_functor_type_tag: - out_buffer.type.type = &typeid(functor_type); + out_buffer.type.type = &BOOST_SP_TYPEID(functor_type); out_buffer.type.const_qualified = false; out_buffer.type.volatile_qualified = false; return; @@ -627,11 +629,11 @@ public: /** Determine if the function is empty (i.e., has no target). */ bool empty() const { return !vtable; } - /** Retrieve the type of the stored function object, or typeid(void) + /** Retrieve the type of the stored function object, or BOOST_SP_TYPEID(void) if this is empty. */ - const BOOST_FUNCTION_STD_NS::type_info& target_type() const + const detail::sp_typeinfo& target_type() const { - if (!vtable) return typeid(void); + if (!vtable) return BOOST_SP_TYPEID(void); detail::function::function_buffer type; get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); @@ -644,7 +646,7 @@ public: if (!vtable) return 0; detail::function::function_buffer type_result; - type_result.type.type = &typeid(Functor); + type_result.type.type = &BOOST_SP_TYPEID(Functor); type_result.type.const_qualified = is_const::value; type_result.type.volatile_qualified = is_volatile::value; get_vtable()->manager(functor, type_result, @@ -662,7 +664,7 @@ public: if (!vtable) return 0; detail::function::function_buffer type_result; - type_result.type.type = &typeid(Functor); + type_result.type.type = &BOOST_SP_TYPEID(Functor); type_result.type.const_qualified = true; type_result.type.volatile_qualified = is_volatile::value; get_vtable()->manager(functor, type_result, From de3b8e745124951b1637a3af48daf825ea8c1a26 Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Tue, 20 Apr 2010 17:54:16 +0000 Subject: [PATCH 48/65] Fixed tab and no-newline-at-end-of-file issues from inspection report [SVN r61435] --- include/boost/function/function_base.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index eb201a8..fe9bbbe 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -264,12 +264,12 @@ namespace boost { A(a) { } - - functor_wrapper(const functor_wrapper& f) : + + functor_wrapper(const functor_wrapper& f) : F(static_cast(f)), A(static_cast(f)) - { - } + { + } }; /** From 2e19728cdb204aa2a77e8b93238a0524e6fa4c47 Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Tue, 8 Jun 2010 23:55:25 +0000 Subject: [PATCH 49/65] Removed all but one old-style cast, breaking GCC 2.95.3; fixes #3410 [SVN r62614] --- include/boost/function/function_base.hpp | 12 +++++++----- include/boost/function/function_template.hpp | 12 ++++++------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index fe9bbbe..e092f01 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -315,7 +315,7 @@ namespace boost { 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); + new (reinterpret_cast(&out_buffer.data)) functor_type(*in_functor); if (op == move_functor_tag) { reinterpret_cast(&in_buffer.data)->~Functor(); @@ -369,8 +369,10 @@ namespace boost { // 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. + // jewillco: Changing this to static_cast because GCC 2.95.3 is + // obsolete. const functor_type* f = - (const functor_type*)(in_buffer.obj_ptr); + static_cast(in_buffer.obj_ptr); functor_type* new_f = new functor_type(*f); out_buffer.obj_ptr = new_f; } else if (op == move_functor_tag) { @@ -474,7 +476,7 @@ namespace boost { // 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); + static_cast(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); @@ -671,7 +673,7 @@ public: detail::function::check_functor_type_tag); // GCC 2.95.3 gets the CV qualifiers wrong here, so we // can't do the static_cast that we should do. - return (const Functor*)(type_result.obj_ptr); + return static_cast(type_result.obj_ptr); } template @@ -715,7 +717,7 @@ public: public: // should be protected, but GCC 2.95.3 will fail to allow access detail::function::vtable_base* get_vtable() const { return reinterpret_cast( - reinterpret_cast(vtable) & ~(std::size_t)0x01); + reinterpret_cast(vtable) & ~static_cast(0x01)); } bool has_trivial_copy_and_destroy() const { diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 6a99109..9539e64 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -514,7 +514,7 @@ namespace boost { if (f) { // should be a reinterpret cast, but some compilers insist // on giving cv-qualifiers to free functions - functor.func_ptr = (void (*)())(f); + functor.func_ptr = reinterpret_cast(f); return true; } else { return false; @@ -563,7 +563,7 @@ namespace boost { void assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) { - new ((void*)&functor.data) FunctionObj(f); + new (reinterpret_cast(&functor.data)) FunctionObj(f); } template void @@ -625,7 +625,7 @@ namespace boost { assign_to(const reference_wrapper& f, function_buffer& functor, function_obj_ref_tag) { - functor.obj_ref.obj_ptr = (void *)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; @@ -677,7 +677,7 @@ namespace boost { vtable_type* get_vtable() const { return reinterpret_cast( - reinterpret_cast(vtable) & ~(std::size_t)0x01); + reinterpret_cast(vtable) & ~static_cast(0x01)); } struct clear_type {}; @@ -917,7 +917,7 @@ namespace boost { if (boost::has_trivial_copy_constructor::value && boost::has_trivial_destructor::value && detail::function::function_allows_small_object_optimization::value) - value |= (std::size_t)0x01; + value |= static_cast(0x01); vtable = reinterpret_cast(value); } else vtable = 0; @@ -951,7 +951,7 @@ namespace boost { if (boost::has_trivial_copy_constructor::value && boost::has_trivial_destructor::value && detail::function::function_allows_small_object_optimization::value) - value |= (std::size_t)0x01; + value |= static_cast(0x01); vtable = reinterpret_cast(value); } else vtable = 0; From 820ad024fee763eceea22faa26abf47df4df505b Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Wed, 9 Jun 2010 00:47:51 +0000 Subject: [PATCH 50/65] Applied patch from #3618; fixes #3618 [SVN r62621] --- include/boost/function/function_base.hpp | 8 ++++++-- test/Jamfile.v2 | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index e092f01..581aae3 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -318,11 +318,15 @@ namespace boost { new (reinterpret_cast(&out_buffer.data)) functor_type(*in_functor); if (op == move_functor_tag) { - reinterpret_cast(&in_buffer.data)->~Functor(); + functor_type* f = reinterpret_cast(&in_buffer.data); + (void)f; // suppress warning about the value of f not being used (MSVC) + f->~Functor(); } } else if (op == destroy_functor_tag) { // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. - reinterpret_cast(&out_buffer.data)->~Functor(); + functor_type* f = reinterpret_cast(&out_buffer.data); + (void)f; // suppress warning about the value of f not being used (MSVC) + f->~Functor(); } else if (op == check_functor_type_tag) { const detail::sp_typeinfo& check_type = *out_buffer.type.type; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ef4e0d1..68895fa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -8,6 +8,7 @@ # For more information, see http://www.boost.org/ project + : requirements msvc:on : source-location $(BOOST_ROOT) ; From c4f1ce7cb121de80a1714caa81ce7b5c0e4a9ec3 Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Wed, 9 Jun 2010 00:49:45 +0000 Subject: [PATCH 51/65] Applied patch from #3912; fixes #3912 [SVN r62622] --- 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 bdb2769..b72842b 100644 --- a/include/boost/function.hpp +++ b/include/boost/function.hpp @@ -23,8 +23,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 Visual Age C++ version do not handle the file iteration well +#if BOOST_WORKAROUND(__IBMCPP__, >= 500) && BOOST_WORKAROUND(__IBMCPP__, < 800) # if BOOST_FUNCTION_MAX_ARGS >= 0 # include # endif From 6902f6f9433080d1ec356a051eb0dfb9afe6c0c1 Mon Sep 17 00:00:00 2001 From: Jeremiah Willcock Date: Wed, 9 Jun 2010 00:51:41 +0000 Subject: [PATCH 52/65] Applied patch from #4073; fixes #4073 [SVN r62623] --- include/boost/function/function_template.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 9539e64..783d41d 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -536,7 +536,7 @@ namespace boost { // objects, so we invoke through mem_fn() but we retain the // right target_type() values. if (f) { - this->assign_to(mem_fn(f), functor); + this->assign_to(boost::mem_fn(f), functor); return true; } else { return false; @@ -549,7 +549,7 @@ namespace boost { // 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); + this->assign_to_a(boost::mem_fn(f), functor, a); return true; } else { return false; From c0d4005441d92c08b01a0528b7825713a6378b7c Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 9 Jun 2010 15:40:48 +0000 Subject: [PATCH 53/65] Make sure that the cv flags are copied when we copy a reference to a function object. Fixes #4325 [SVN r62665] --- include/boost/function/function_base.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 581aae3..78b7dd1 100644 --- a/include/boost/function/function_base.hpp +++ b/include/boost/function/function_base.hpp @@ -203,11 +203,11 @@ namespace boost { { switch (op) { case clone_functor_tag: - out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + out_buffer.obj_ref = in_buffer.obj_ref; return; case move_functor_tag: - out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + out_buffer.obj_ref = in_buffer.obj_ref; in_buffer.obj_ref.obj_ptr = 0; return; From 09fc8792fab8766e36630d0489b04d3184393bad Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 20 Jun 2010 18:00:48 +0000 Subject: [PATCH 54/65] Update various libraries' documentation build. Mostly to use the images and css files under doc/src instead of doc/html, usually be deleting the settings in order to use the defaults. Also add 'boost.root' to some builds in order to fix links which rely on it. [SVN r63146] --- doc/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index b1dd5ab..9f518e6 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -10,6 +10,7 @@ boostbook function-doc : function.xml : + boost.root=../../../.. pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html ; From 9ea95b071b57e01f1dce30d7f5c7607f593460e7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 26 Jun 2010 12:10:47 +0000 Subject: [PATCH 55/65] Detab some jamfiles. [SVN r63343] --- doc/Jamfile.v2 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 9f518e6..1aee1e7 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -7,10 +7,10 @@ project boost/doc ; import boostbook : boostbook ; boostbook function-doc - : - function.xml - : - boost.root=../../../.. + : + function.xml + : + boost.root=../../../.. pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html - ; + ; From 8cde82a568634dd47bf685d4529e19cb8eaee974 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sun, 2 Jan 2011 05:13:03 +0000 Subject: [PATCH 56/65] Remove extra definition of operator(), since it's inline anyway. Fixes #4765. [SVN r67560] --- include/boost/function/function_template.hpp | 22 -------------------- 1 file changed, 22 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 783d41d..00a4a2c 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -751,9 +751,6 @@ namespace boost { ~BOOST_FUNCTION_FUNCTION() { clear(); } -#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) - // MSVC 6.0 and prior require all definitions to be inline, but - // these definitions can become very costly. result_type operator()(BOOST_FUNCTION_PARMS) const { if (this->empty()) @@ -762,9 +759,6 @@ namespace boost { return get_vtable()->invoker (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); } -#else - result_type operator()(BOOST_FUNCTION_PARMS) const; -#endif // The distinction between when to use BOOST_FUNCTION_FUNCTION and // when to use self_type is obnoxious. MSVC cannot handle self_type as @@ -998,22 +992,6 @@ namespace boost { f1.swap(f2); } -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) - template - typename BOOST_FUNCTION_FUNCTION< - R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type - inline - BOOST_FUNCTION_FUNCTION - ::operator()(BOOST_FUNCTION_PARMS) const - { - if (this->empty()) - boost::throw_exception(bad_function_call()); - - return get_vtable()->invoker - (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); - } -#endif - // Poison comparisons between boost::function objects of the same type. template void operator==(const BOOST_FUNCTION_FUNCTION< From 7ee94c69755b029702c2591f496d952e148e3da9 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 21 Mar 2011 09:01:18 +0000 Subject: [PATCH 57/65] Function: Extra member tests, to catch #4073. [SVN r70301] --- test/mem_fun_cxx98.cpp | 16 +++++++++++----- test/mem_fun_portable.cpp | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/test/mem_fun_cxx98.cpp b/test/mem_fun_cxx98.cpp index afded46..fba21dd 100644 --- a/test/mem_fun_cxx98.cpp +++ b/test/mem_fun_cxx98.cpp @@ -10,22 +10,28 @@ #include +#include #include #include struct X { int foo(int); + std::ostream& foo2(std::ostream&) const; }; int X::foo(int x) { return -x; } +std::ostream& X::foo2(std::ostream& x) const { return x; } int main() { boost::function f; + boost::function f2; -f = &X::foo; - -X x; -f(&x, 5); + f = &X::foo; + f2 = &X::foo2; - return 0; + X x; + BOOST_TEST(f(&x, 5) == -5); + BOOST_TEST(f2(&x, boost::ref(std::cout)) == std::cout); + + return ::boost::report_errors(); } diff --git a/test/mem_fun_portable.cpp b/test/mem_fun_portable.cpp index 689eb22..b0dcd14 100644 --- a/test/mem_fun_portable.cpp +++ b/test/mem_fun_portable.cpp @@ -10,22 +10,28 @@ #include +#include #include #include struct X { int foo(int); + std::ostream& foo2(std::ostream&) const; }; int X::foo(int x) { return -x; } +std::ostream& X::foo2(std::ostream& x) const { return x; } int main() { boost::function2 f; + boost::function2 f2; -f = &X::foo; - -X x; -f(&x, 5); + f = &X::foo; + f2 = &X::foo2; - return 0; + X x; + BOOST_TEST(f(&x, 5) == -5); + BOOST_TEST(f2(&x, boost::ref(std::cout)) == std::cout); + + return ::boost::report_errors(); } From cbb9e7c4daa83339496403c89f84cd33bbd50098 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Tue, 31 May 2011 21:12:35 +0000 Subject: [PATCH 58/65] Applied patch from #4717 [SVN r72316] --- include/boost/function/function_template.hpp | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 00a4a2c..3514e28 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -486,19 +486,19 @@ namespace boost { BOOST_FUNCTION_TEMPLATE_ARGS); template - bool assign_to(F f, function_buffer& functor) + bool assign_to(F f, function_buffer& functor) const { typedef typename get_function_tag::type tag; return assign_to(f, functor, tag()); } template - bool assign_to_a(F f, function_buffer& functor, Allocator a) + bool assign_to_a(F f, function_buffer& functor, Allocator a) const { typedef typename get_function_tag::type tag; return assign_to_a(f, functor, a, tag()); } - void clear(function_buffer& functor) + void clear(function_buffer& functor) const { if (base.manager) base.manager(functor, functor, destroy_functor_tag); @@ -508,7 +508,7 @@ namespace boost { // Function pointers 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) { @@ -522,7 +522,7 @@ namespace boost { } template bool - assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) + assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) const { return assign_to(f,functor,function_ptr_tag()); } @@ -530,7 +530,7 @@ namespace boost { // Member pointers #if BOOST_FUNCTION_NUM_ARGS > 0 template - bool assign_to(MemberPtr f, function_buffer& functor, 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 @@ -543,7 +543,7 @@ namespace boost { } } template - bool assign_to_a(MemberPtr f, function_buffer& functor, Allocator a, member_ptr_tag) + bool assign_to_a(MemberPtr f, function_buffer& functor, Allocator a, member_ptr_tag) const { // DPG TBD: Add explicit support for member function // objects, so we invoke through mem_fn() but we retain the @@ -561,13 +561,13 @@ namespace boost { // Assign to a function object using the small object optimization template void - assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) + assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) const { new (reinterpret_cast(&functor.data)) FunctionObj(f); } template void - assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) const { assign_functor(f,functor,mpl::true_()); } @@ -575,13 +575,13 @@ namespace boost { // Assign to a function object allocated on the heap. template void - assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) + assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) const { functor.obj_ptr = new FunctionObj(f); } template void - assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) + assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) const { typedef functor_wrapper functor_wrapper_type; typedef typename Allocator::template rebind::other @@ -596,7 +596,7 @@ namespace boost { template bool - assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) + assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) const { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor(f, functor, @@ -608,7 +608,7 @@ namespace boost { } template bool - assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) + assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) const { if (!boost::detail::function::has_empty_target(boost::addressof(f))) { assign_functor_a(f, functor, a, @@ -623,7 +623,7 @@ namespace boost { template bool assign_to(const reference_wrapper& f, - function_buffer& functor, function_obj_ref_tag) + function_buffer& functor, function_obj_ref_tag) const { functor.obj_ref.obj_ptr = (void *)(f.get_pointer()); functor.obj_ref.is_const_qualified = is_const::value; @@ -633,7 +633,7 @@ namespace boost { template bool assign_to_a(const reference_wrapper& f, - function_buffer& functor, Allocator, function_obj_ref_tag) + function_buffer& functor, Allocator, function_obj_ref_tag) const { return assign_to(f,functor,function_obj_ref_tag()); } @@ -903,7 +903,7 @@ namespace boost { // 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 = + static const vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; if (stored_vtable.assign_to(f, functor)) { @@ -937,7 +937,7 @@ namespace boost { // 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 = + static const vtable_type stored_vtable = { { &manager_type::manage }, &invoker_type::invoke }; if (stored_vtable.assign_to_a(f, functor, a)) { From 775213a9e6b453ac6437c2c1c29000e7913c31f9 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Tue, 11 Oct 2011 15:23:29 +0000 Subject: [PATCH 59/65] Remove extraneous semicolon [SVN r74916] --- include/boost/function/function_template.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 3514e28..bf139a0 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -858,7 +858,7 @@ namespace boost { #else private: struct dummy { - void nonnull() {}; + void nonnull() {} }; typedef void (dummy::*safe_bool)(); From bfde71273baaaad50c4bdc7cb9347a64e796db2b Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sat, 18 Aug 2012 14:26:41 +0000 Subject: [PATCH 60/65] Fix typo; Refs #7244 [SVN r80077] --- doc/reference.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/reference.xml b/doc/reference.xml index 3b1faec..c742403 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -58,7 +58,7 @@ A function object f of type F is stateless if it is a function pointer or if - boost::is_stateless<T> + boost::is_stateless<F> is true. The construction of or copy to a Boost.Function object from a stateless function object will not cause exceptions to be thrown and will not allocate any storage. From 419f424959dd6d7f4ea443a2d755cc6d89c86dfb Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 17 Sep 2012 04:08:18 +0000 Subject: [PATCH 61/65] Add move assignment and move constructors to Boost.Function (refs #7330) [SVN r80552] --- include/boost/function/function_template.hpp | 51 ++++++++++- test/function_test.cpp | 91 ++++++++++++++++++++ 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index bf139a0..f9699d0 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -748,7 +748,14 @@ namespace boost { { this->assign_to_own(f); } - + +#ifndef BOOST_NO_RVALUE_REFERENCES + BOOST_FUNCTION_FUNCTION(BOOST_FUNCTION_FUNCTION&& f) : function_base() + { + this->move_assign(f); + } +#endif + ~BOOST_FUNCTION_FUNCTION() { clear(); } result_type operator()(BOOST_FUNCTION_PARMS) const @@ -830,6 +837,26 @@ namespace boost { BOOST_CATCH_END return *this; } + +#ifndef BOOST_NO_RVALUE_REFERENCES + // Move assignment from another BOOST_FUNCTION_FUNCTION + BOOST_FUNCTION_FUNCTION& operator=(BOOST_FUNCTION_FUNCTION&& f) + { + + if (&f == this) + return *this; + + this->clear(); + BOOST_TRY { + this->move_assign(f); + } BOOST_CATCH (...) { + vtable = 0; + BOOST_RETHROW; + } + BOOST_CATCH_END + return *this; + } +#endif void swap(BOOST_FUNCTION_FUNCTION& other) { @@ -1063,12 +1090,26 @@ public: function(const base_type& f) : base_type(static_cast(f)){} +#ifndef BOOST_NO_RVALUE_REFERENCES + // Move constructors + function(self_type&& f): base_type(static_cast(f)){} + function(base_type&& f): base_type(static_cast(f)){} +#endif + self_type& operator=(const self_type& f) { self_type(f).swap(*this); return *this; } +#ifndef BOOST_NO_RVALUE_REFERENCES + self_type& operator=(self_type&& f) + { + self_type(static_cast(f)).swap(*this); + return *this; + } +#endif + template #ifndef BOOST_NO_SFINAE typename enable_if_c< @@ -1097,6 +1138,14 @@ public: self_type(f).swap(*this); return *this; } + +#ifndef BOOST_NO_RVALUE_REFERENCES + self_type& operator=(base_type&& f) + { + self_type(static_cast(f)).swap(*this); + return *this; + } +#endif }; #undef BOOST_FUNCTION_PARTIAL_SPEC diff --git a/test/function_test.cpp b/test/function_test.cpp index 65d6e58..7f5cb04 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -690,6 +690,95 @@ static void test_call() test_call_cref(std::plus()); } +struct big_aggregating_structure { + int disable_small_objects_optimizations[32]; + + big_aggregating_structure() + { + ++ global_int; + } + + big_aggregating_structure(const big_aggregating_structure&) + { + ++ global_int; + } + + ~big_aggregating_structure() + { + -- global_int; + } + + void operator()() + { + ++ global_int; + } + + void operator()(int) + { + ++ global_int; + } +}; + +template +static void test_move_semantics() +{ + typedef FunctionT f1_type; + + big_aggregating_structure obj; + + f1_type f1 = obj; + global_int = 0; + f1(); + + BOOST_CHECK(!f1.empty()); + BOOST_CHECK(global_int == 1); + +#ifndef BOOST_NO_RVALUE_REFERENCES + // Testing rvalue constructors + f1_type f2(static_cast(f1)); + BOOST_CHECK(f1.empty()); + BOOST_CHECK(!f2.empty()); + BOOST_CHECK(global_int == 1); + f2(); + BOOST_CHECK(global_int == 2); + + f1_type f3(static_cast(f2)); + BOOST_CHECK(f1.empty()); + BOOST_CHECK(f2.empty()); + BOOST_CHECK(!f3.empty()); + BOOST_CHECK(global_int == 2); + f3(); + BOOST_CHECK(global_int == 3); + + // Testing move assignment + f1_type f4; + BOOST_CHECK(f4.empty()); + f4 = static_cast(f3); + BOOST_CHECK(f1.empty()); + BOOST_CHECK(f2.empty()); + BOOST_CHECK(f3.empty()); + BOOST_CHECK(!f4.empty()); + BOOST_CHECK(global_int == 3); + f4(); + BOOST_CHECK(global_int == 4); + + // Testing self move assignment + f4 = static_cast(f4); + BOOST_CHECK(!f4.empty()); + BOOST_CHECK(global_int == 4); + + // Testing, that no memory leaked when assigning to nonempty function + f4 = obj; + BOOST_CHECK(!f4.empty()); + BOOST_CHECK(global_int == 4); + f1_type f5 = obj; + BOOST_CHECK(global_int == 5); + f4 = static_cast(f5); + BOOST_CHECK(global_int == 4); + +#endif +} + int test_main(int, char* []) { test_zero_args(); @@ -702,6 +791,8 @@ int test_main(int, char* []) test_exception(); test_implicit(); test_call(); + test_move_semantics >(); + test_move_semantics >(); return 0; } From 9e30736439be228adfc850030a039e58d0b82bef Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 21 Nov 2012 01:49:52 +0000 Subject: [PATCH 62/65] Updated to use new macro names [SVN r81450] --- include/boost/function/function_template.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index f9699d0..42b7d0f 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -749,7 +749,7 @@ namespace boost { this->assign_to_own(f); } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES BOOST_FUNCTION_FUNCTION(BOOST_FUNCTION_FUNCTION&& f) : function_base() { this->move_assign(f); @@ -838,7 +838,7 @@ namespace boost { return *this; } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Move assignment from another BOOST_FUNCTION_FUNCTION BOOST_FUNCTION_FUNCTION& operator=(BOOST_FUNCTION_FUNCTION&& f) { @@ -1090,7 +1090,7 @@ public: function(const base_type& f) : base_type(static_cast(f)){} -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Move constructors function(self_type&& f): base_type(static_cast(f)){} function(base_type&& f): base_type(static_cast(f)){} @@ -1102,7 +1102,7 @@ public: return *this; } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES self_type& operator=(self_type&& f) { self_type(static_cast(f)).swap(*this); @@ -1139,7 +1139,7 @@ public: return *this; } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES self_type& operator=(base_type&& f) { self_type(static_cast(f)).swap(*this); From 74a61f025295a34ff603381ca657681cc4279a9f Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Mon, 26 Nov 2012 18:47:49 +0000 Subject: [PATCH 63/65] Removed usage of deprecated macros in Boost.Function [SVN r81570] --- test/function_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/function_test.cpp b/test/function_test.cpp index 7f5cb04..02a60ce 100644 --- a/test/function_test.cpp +++ b/test/function_test.cpp @@ -733,7 +733,7 @@ static void test_move_semantics() BOOST_CHECK(!f1.empty()); BOOST_CHECK(global_int == 1); -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Testing rvalue constructors f1_type f2(static_cast(f1)); BOOST_CHECK(f1.empty()); From 95a195639765e3d189341f5da152eb983e19603a Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Sat, 29 Dec 2012 16:36:12 +0000 Subject: [PATCH 64/65] Added missing 'std::'; Refs #7819 [SVN r82273] --- include/boost/function/function_template.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 42b7d0f..73ed72e 100644 --- a/include/boost/function/function_template.hpp +++ b/include/boost/function/function_template.hpp @@ -677,7 +677,7 @@ namespace boost { vtable_type* get_vtable() const { return reinterpret_cast( - reinterpret_cast(vtable) & ~static_cast(0x01)); + reinterpret_cast(vtable) & ~static_cast(0x01)); } struct clear_type {}; From 26d278733f64e1004f6842d0a99a1c1f6fdaecb8 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Sat, 15 Jun 2013 06:59:30 +0000 Subject: [PATCH 65/65] Update documentation of Boost.Function and add info about rvalues (refs #8505) [SVN r84787] --- doc/history.xml | 9 ++++++++ doc/reference.xml | 58 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/doc/history.xml b/doc/history.xml index 05fddf8..75ecd42 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -13,6 +13,15 @@ + Version 1.52.0: + + Move constructors and move assignment + operators added (only for compilers with C++11 rvalue + references support). Original patch + contributed by Antony Polukhin. + + + Version 1.37.0: Improved the performance of Boost.Function's diff --git a/doc/reference.xml b/doc/reference.xml index c742403..843a25f 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -203,6 +203,15 @@ Will not throw unless copying the target of f throws. + + + functionN&& + + C++11 compatible compiler. + Moves the value from f to *this. If the argument has its function object allocated on the heap, its buffer will be assigned to *this leaving argument empty. + Will not throw unless argument has its function object allocated not on the heap and copying the target of f throws. + +