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..05fddf8 100644 --- a/doc/history.xml +++ b/doc/history.xml @@ -1,4 +1,11 @@ +
@@ -6,6 +13,42 @@ + Version 1.37.0: + + Improved the performance of Boost.Function's + swap() operation for large function objects. Original patch + contributed by Niels Dekker. + + Added a new header <boost/function/function_typeof.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects. + + Added a new header <boost/function/function_fwd.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects. + + The target() + function now respects the cv-qualifiers of function objects + stored by reference + (using boost::reference_wrapper), such + that a reference to a const function object cannot + be accessed as a reference to a non-const function + object. + + + + Version 1.36.0: + + Boost.Function now implements allocator support + in the same way that is is provided in C++0x, based on C++ + committee + proposal N2308. This + change removes the Allocator + template parameter of boost::function in + favor of a constructor that takes an argument. While this is a + backward-incompatible change, it is likely to affect only a few + users. This change to Function was contributed by Emil + Dotchevski, which also authored the corresponding C++ committee + proposal. + + + Version 1.34.0: Boost.Function now implements a small buffer optimization, which can drastically improve the performance when copying or construction Boost.Function objects storing small function objects. For instance, bind(&X:foo, &x, _1, _2) requires no heap allocation when placed into a Boost.Function object. Note that some exception-safety guarantees have changed: assignment provides the basic exception guarantee and swap() may throw. diff --git a/doc/misc.xml b/doc/misc.xml index 29807de..ef0906c 100644 --- a/doc/misc.xml +++ b/doc/misc.xml @@ -1,4 +1,11 @@ +
@@ -17,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. @@ -30,12 +37,12 @@
Function object wrapper size - Function object wrappers will be the size of two function pointers plus one function pointer or data pointer (whichever is larger). On common 32-bit platforms, this amounts to 12 bytes per wrapper. Additionally, the function object target will be allocated on the heap. + Function object wrappers will be the size of a struct containing a member function pointer and two data pointers. The actual size can vary significantly depending on the underlying platform; on 32-bit Mac OS X with GCC, this amounts to 16 bytes, while it is 32 bytes Windows with Visual C++. Additionally, the function object target may be allocated on the heap, if it cannot be placed into the small-object buffer in the boost::function object.
Copying efficiency - Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using ref) if the cost of this cloning becomes prohibitive. + Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using ref) if the cost of this cloning becomes prohibitive. Small function objects can be stored within the boost::function object itself, improving copying efficiency.
diff --git a/doc/reference.xml b/doc/reference.xml index 8d69d7a..3b1faec 100644 --- a/doc/reference.xml +++ b/doc/reference.xml @@ -1,4 +1,11 @@ + @@ -134,9 +141,6 @@ - - std::allocator<void> - function_base @@ -153,7 +157,6 @@ R - Allocator T1If N == 1 @@ -209,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. @@ -317,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) @@ -334,11 +349,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -347,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> @@ -373,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 @@ -435,11 +444,10 @@ - bool - const functionN<T1, T2, ..., TN, Allocator>& + const functionN<T1, T2, ..., TN>& Functor @@ -448,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> @@ -474,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 @@ -536,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. @@ -562,7 +562,6 @@ R - Allocator T1If N == 1 @@ -626,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. @@ -738,11 +750,10 @@ void - function<Signature, Allocator>& - function<Signature, Allocator>& + function<Signature>& + function<Signature>& f1.swap(f2) @@ -752,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 @@ -833,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/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 @@ +
# include -# include // unary_function, binary_function +# include // unary_function, binary_function # include # include # include @@ -22,4 +22,5 @@ # include # include # include +# include #endif // BOOST_FUNCTION_PROLOGUE_HPP diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp index 6458765..c23778b 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 @@ -17,8 +18,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -29,10 +33,12 @@ # include "boost/mpl/bool.hpp" #endif #include +#include #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. @@ -61,22 +67,7 @@ # define BOOST_FUNCTION_TARGET_FIX(x) #endif // not MSVC -#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) -// Work around a compiler bug. -// boost::python::objects::function has to be seen by the compiler before the -// boost::function class template. -namespace boost { namespace python { namespace objects { - class function; -}}} -#endif - -#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ - || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ - || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) -# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX -#endif - -#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0) # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \ (::boost::is_integral::value)>::value), \ @@ -90,31 +81,6 @@ namespace boost { namespace python { namespace objects { Type>::type #endif -#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 > -class function; -#else -template > -class function; -#endif - -template -inline void swap(function& f1, - function& f2) -{ - f1.swap(f2); -} - -} // end namespace boost -#endif // have partial specialization - namespace boost { namespace detail { namespace function { @@ -129,11 +95,18 @@ namespace boost { union function_buffer { // For pointers to function objects - void* obj_ptr; + mutable void* obj_ptr; // For pointers to std::type_info objects - // (get_functor_type_tag, check_functor_type_tag). - const void* const_obj_ptr; + struct type_t { + // (get_functor_type_tag, check_functor_type_tag). + const BOOST_FUNCTION_STD_NS::type_info* type; + + // Whether the type is const-qualified. + bool const_qualified; + // Whether the type is volatile-qualified. + bool volatile_qualified; + } type; // For function pointers of all kinds mutable void (*func_ptr)(); @@ -144,6 +117,14 @@ namespace boost { void* obj_ptr; } bound_memfunc_ptr; + // For references to function objects. We explicitly keep + // track of the cv-qualifiers on the object referenced. + struct obj_ref_t { + mutable void* obj_ptr; + bool is_const_qualified; + bool is_volatile_qualified; + } obj_ref; + // To relax aliasing constraints mutable char data; }; @@ -175,6 +156,7 @@ namespace boost { // The operation type to perform on the given functor/function pointer enum functor_manager_operation_type { clone_functor_tag, + move_functor_tag, destroy_functor_tag, check_functor_type_tag, get_functor_type_tag @@ -211,34 +193,45 @@ 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: - out_buffer.obj_ptr = in_buffer.obj_ptr; + out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + return; + + case move_functor_tag: + out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr; + in_buffer.obj_ref.obj_ptr = 0; return; case destroy_functor_tag: - out_buffer.obj_ptr = 0; + out_buffer.obj_ref.obj_ptr = 0; return; case check_functor_type_tag: { - // DPG TBD: Since we're only storing a pointer, it's - // possible that the user could ask for a base class or - // derived class. Is that okay? - const BOOST_FUNCTION_STD_NS::type_info& check_type = - *static_cast(out_buffer.const_obj_ptr); - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))) - out_buffer.obj_ptr = in_buffer.obj_ptr; + const BOOST_FUNCTION_STD_NS::type_info& check_type + = *out_buffer.type.type; + + // Check whether we have the same type. We can add + // cv-qualifiers, but we can't take them away. + if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)) + && (!in_buffer.obj_ref.is_const_qualified + || out_buffer.type.const_qualified) + && (!in_buffer.obj_ref.is_volatile_qualified + || out_buffer.type.volatile_qualified)) + out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr; else out_buffer.obj_ptr = 0; } return; case get_functor_type_tag: - out_buffer.const_obj_ptr = &typeid(F); + out_buffer.type.type = &typeid(F); + out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified; + out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified; return; } } @@ -258,33 +251,94 @@ 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 + template + struct functor_manager_common + { + typedef Functor functor_type; + + // Function pointers + static inline void + 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; + 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 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; + } + } + + // Function objects that fit in the small-object buffer. + static inline void + manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, + functor_manager_operation_type op) + { + if (op == clone_functor_tag || op == move_functor_tag) { + const functor_type* in_functor = + reinterpret_cast(&in_buffer.data); + new ((void*)&out_buffer.data) functor_type(*in_functor); + + if (op == move_functor_tag) { + reinterpret_cast(&in_buffer.data)->~Functor(); + } + } else if (op == destroy_functor_tag) { + // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. + reinterpret_cast(&out_buffer.data)->~Functor(); + } else 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; + } + } + }; + + template struct functor_manager { 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) { - if (op == clone_functor_tag) - out_buffer.func_ptr = in_buffer.func_ptr; - else if (op == destroy_functor_tag) - out_buffer.func_ptr = 0; - else /* op == check_functor_type_tag */ { - const 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 - out_buffer.obj_ptr = 0; - } + functor_manager_common::manage_ptr(in_buffer,out_buffer,op); } // Function objects that fit in the small-object buffer. @@ -292,21 +346,7 @@ namespace boost { manager(const function_buffer& in_buffer, function_buffer& out_buffer, functor_manager_operation_type op, mpl::true_) { - if (op == clone_functor_tag) { - const functor_type* in_functor = - reinterpret_cast(&in_buffer.data); - new ((void*)&out_buffer.data) functor_type(*in_functor); - } else if (op == destroy_functor_tag) { - // 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); - if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor))) - out_buffer.obj_ptr = &in_buffer.data; - else - out_buffer.obj_ptr = 0; - } + functor_manager_common::manage_small(in_buffer,out_buffer,op); } // Function objects that require heap allocation @@ -314,59 +354,34 @@ namespace boost { 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 == move_functor_tag) { + out_buffer.obj_ptr = in_buffer.obj_ptr; + in_buffer.obj_ptr = 0; } else if (op == destroy_functor_tag) { /* Cast from the void pointer to the functor pointer type */ functor_type* f = static_cast(out_buffer.obj_ptr); - -# 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 = - *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; } } @@ -381,13 +396,107 @@ 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.type.type = &typeid(functor_type); + out_buffer.type.const_qualified = false; + out_buffer.type.volatile_qualified = false; + 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 == 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 = + 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 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; + } + } + + // 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: @@ -400,7 +509,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: @@ -478,6 +589,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); @@ -507,7 +619,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 @@ -516,7 +628,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); @@ -532,7 +646,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 @@ -579,7 +695,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; }; @@ -754,8 +870,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_fwd.hpp b/include/boost/function/function_fwd.hpp new file mode 100644 index 0000000..d2f713a --- /dev/null +++ b/include/boost/function/function_fwd.hpp @@ -0,0 +1,70 @@ +// Boost.Function library +// Copyright (C) Douglas Gregor 2008 +// +// Use, modification and distribution is subject to the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org +#ifndef BOOST_FUNCTION_FWD_HPP +#define BOOST_FUNCTION_FWD_HPP +#include + +#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG) +// Work around a compiler bug. +// boost::python::objects::function has to be seen by the compiler before the +// boost::function class template. +namespace boost { namespace python { namespace objects { + class function; +}}} +#endif + +#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ + || !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) +# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX +#endif + +namespace boost { + class bad_function_call; + +#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX) + // Preferred syntax + template class function; + + template + inline void swap(function& f1, function& f2) + { + f1.swap(f2); + } +#endif // have partial specialization + + // Portable syntax + template class function0; + template class function1; + template class function2; + template class function3; + template + class function4; + template + class function5; + template + class function6; + template + class function7; + template + class function8; + template + class function9; + template + class function10; +} + +#endif diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp index 536bac4..7730903 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 @@ -11,6 +12,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) @@ -26,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 @@ -54,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 @@ -189,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 @@ -290,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; @@ -426,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) { @@ -456,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; @@ -475,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, @@ -519,27 +475,64 @@ namespace boost { return false; } } - - // Reference to a function object - template + template bool - assign_to(const reference_wrapper& f, - function_buffer& functor, function_obj_ref_tag) const + assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_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(); + 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) + { + 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; + } + } + 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 @@ -547,8 +540,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 @@ -573,7 +565,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 {}; @@ -598,7 +590,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() { } @@ -618,6 +609,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() { } @@ -643,7 +647,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 @@ -667,18 +671,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*) @@ -702,16 +713,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; } @@ -720,16 +727,17 @@ namespace boost { if (&other == this) return; - BOOST_FUNCTION_FUNCTION tmp = *this; - *this = other; - other = tmp; + BOOST_FUNCTION_FUNCTION tmp; + tmp.move_assign(*this); + this->move_assign(other); + other.move_assign(tmp); } // Clear out a target, if there is one void clear() { if (vtable) { - reinterpret_cast(vtable)->clear(this->functor); + static_cast(vtable)->clear(this->functor); vtable = 0; } } @@ -764,84 +772,91 @@ 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; + } + + // Moves the value from the specified argument to *this. If the argument + // has its function object allocated on the heap, move_assign will pass + // its buffer to *this, and set the argument's buffer pointer to NULL. + void move_assign(BOOST_FUNCTION_FUNCTION& f) + { + if (&f == this) + return; + +#if !defined(BOOST_NO_EXCEPTIONS) + try { +#endif + if (!f.empty()) { + this->vtable = f.vtable; + f.vtable->manager(f.functor, this->functor, + boost::detail::function::move_functor_tag); + f.vtable = 0; +#if !defined(BOOST_NO_EXCEPTIONS) + } else { + clear(); + } + } catch (...) { + vtable = 0; + throw; + } +#endif + } }; - template + 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) @@ -852,20 +867,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() {} @@ -881,6 +892,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() {} @@ -933,8 +956,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 @@ -943,12 +964,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 @@ -958,3 +977,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 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/index.html b/index.html index 5119596..b7d40d2 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,11 @@ + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8ab92b1..ef4e0d1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -58,6 +58,9 @@ import testing ; [ run libs/function/test/contains2_test.cpp : : : : ] + [ run libs/function/test/nothrow_swap.cpp : : : : ] + + [ compile libs/function/test/function_typeof_test.cpp ] ; } diff --git a/test/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; } diff --git a/test/contains_test.cpp b/test/contains_test.cpp index 31963c0..fa11559 100644 --- a/test/contains_test.cpp +++ b/test/contains_test.cpp @@ -88,6 +88,15 @@ static void target_test() BOOST_CHECK(!f.target()); BOOST_CHECK(f.target()); BOOST_CHECK(f.target() == &this_seventeen); + + const Seventeen const_seventeen = this_seventeen; + f = boost::ref(const_seventeen); + BOOST_CHECK(!f.target()); + BOOST_CHECK(f.target()); + BOOST_CHECK(f.target() == &const_seventeen); + BOOST_CHECK(f.target()); + BOOST_CHECK(!f.target()); + BOOST_CHECK(!f.target()); } static void equal_test() diff --git a/test/function_n_test.cpp b/test/function_n_test.cpp index 14439a8..cdd7145 100644 --- a/test/function_n_test.cpp +++ b/test/function_n_test.cpp @@ -636,6 +636,54 @@ test_ref() } } +static unsigned construction_count = 0; +static unsigned destruction_count = 0; + +struct MySmallFunctor { + MySmallFunctor() { ++construction_count; } + MySmallFunctor(const MySmallFunctor &) { ++construction_count; } + ~MySmallFunctor() { ++destruction_count; } + int operator()() { return 0; } + }; + +struct MyLargeFunctor { + MyLargeFunctor() { ++construction_count; } + MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; } + ~MyLargeFunctor() { ++destruction_count; } + int operator()() { return 0; } + + float data[128]; + }; + +void test_construct_destroy_count() +{ + { + boost::function0 f; + boost::function0 g; + f = MySmallFunctor(); + g = MySmallFunctor(); + f.swap(g); + } + + // MySmallFunctor objects should be constructed as many times as + // they are destroyed. + BOOST_CHECK(construction_count == destruction_count); + + construction_count = 0; + destruction_count = 0; + { + boost::function0 f; + boost::function0 g; + f = MyLargeFunctor(); + g = MyLargeFunctor(); + f.swap(g); + } + + // MyLargeFunctor objects should be constructed as many times as + // they are destroyed. + BOOST_CHECK(construction_count == destruction_count); +} + int test_main(int, char* []) { test_zero_args(); @@ -644,5 +692,6 @@ int test_main(int, char* []) test_emptiness(); test_member_functions(); test_ref(); + test_construct_destroy_count(); return 0; } diff --git a/test/function_typeof_test.cpp b/test/function_typeof_test.cpp new file mode 100644 index 0000000..2d77cab --- /dev/null +++ b/test/function_typeof_test.cpp @@ -0,0 +1,18 @@ +// Boost.Function library + +// Copyright Douglas Gregor 2008. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org +#include +#include +#include +#include +#include + +void f(boost::function0 f, boost::function0 g) +{ + BOOST_STATIC_ASSERT((boost::is_same, BOOST_TYPEOF(f = g)>::value)); +} diff --git a/test/nothrow_swap.cpp b/test/nothrow_swap.cpp new file mode 100644 index 0000000..0a5b740 --- /dev/null +++ b/test/nothrow_swap.cpp @@ -0,0 +1,60 @@ +// Boost.Function library + +// Copyright Douglas Gregor 2008. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// For more information, see http://www.boost.org + +#include +#include + +struct tried_to_copy { }; + +struct MaybeThrowOnCopy { + MaybeThrowOnCopy(int value = 0) : value(value) { } + + MaybeThrowOnCopy(const MaybeThrowOnCopy& other) : value(other.value) { + if (throwOnCopy) + throw tried_to_copy(); + } + + MaybeThrowOnCopy& operator=(const MaybeThrowOnCopy& other) { + if (throwOnCopy) + throw tried_to_copy(); + value = other.value; + return *this; + } + + int operator()() { return value; } + + int value; + + // Make sure that this function object doesn't trigger the + // small-object optimization in Function. + float padding[100]; + + static bool throwOnCopy; +}; + +bool MaybeThrowOnCopy::throwOnCopy = false; + +int test_main(int, char* []) +{ + boost::function0 f; + boost::function0 g; + + MaybeThrowOnCopy::throwOnCopy = false; + f = MaybeThrowOnCopy(1); + g = MaybeThrowOnCopy(2); + BOOST_CHECK(f() == 1); + BOOST_CHECK(g() == 2); + + MaybeThrowOnCopy::throwOnCopy = true; + f.swap(g); + BOOST_CHECK(f() == 2); + BOOST_CHECK(g() == 1); + + return 0; +}