Chris@16: // Boost.Function library Chris@16: Chris@16: // Copyright Douglas Gregor 2001-2006 Chris@16: // Copyright Emil Dotchevski 2007 Chris@16: // Use, modification and distribution is subject to the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // For more information, see http://www.boost.org Chris@16: Chris@16: #ifndef BOOST_FUNCTION_BASE_HEADER Chris@16: #define BOOST_FUNCTION_BASE_HEADER Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #ifndef BOOST_NO_SFINAE Chris@16: # include "boost/utility/enable_if.hpp" Chris@16: #else Chris@16: # include "boost/mpl/bool.hpp" Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: # pragma warning( push ) Chris@16: # pragma warning( disable : 4793 ) // complaint about native code generation Chris@16: # pragma warning( disable : 4127 ) // "conditional expression is constant" Chris@16: #endif Chris@16: Chris@16: // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info. Chris@16: #ifdef BOOST_NO_STD_TYPEINFO Chris@16: // Embedded VC++ does not have type_info in namespace std Chris@16: # define BOOST_FUNCTION_STD_NS Chris@16: #else Chris@16: # define BOOST_FUNCTION_STD_NS std Chris@16: #endif Chris@16: Chris@16: // Borrowed from Boost.Python library: determines the cases where we Chris@16: // need to use std::type_info::name to compare instead of operator==. Chris@16: #if defined( BOOST_NO_TYPEID ) Chris@16: # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) Chris@101: #elif defined(__GNUC__) \ Chris@16: || defined(_AIX) \ Chris@16: || ( defined(__sgi) && defined(__host_mips)) Chris@16: # include Chris@16: # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \ Chris@16: (std::strcmp((X).name(),(Y).name()) == 0) Chris@16: # else Chris@16: # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) Chris@16: #endif Chris@16: Chris@101: #if defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG) Chris@16: # define BOOST_FUNCTION_TARGET_FIX(x) x Chris@16: #else Chris@16: # define BOOST_FUNCTION_TARGET_FIX(x) Chris@101: #endif // __ICL etc Chris@16: Chris@16: #if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0) Chris@16: # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ Chris@16: typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \ Chris@16: (::boost::is_integral::value)>::value), \ Chris@16: Type>::type Chris@16: #else Chris@16: // BCC doesn't recognize this depends on a template argument and complains Chris@16: // about the use of 'typename' Chris@16: # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ Chris@16: ::boost::enable_if_c<(::boost::type_traits::ice_not< \ Chris@16: (::boost::is_integral::value)>::value), \ Chris@16: Type>::type Chris@16: #endif Chris@16: Chris@16: namespace boost { Chris@16: namespace detail { Chris@16: namespace function { Chris@16: class X; Chris@16: Chris@16: /** Chris@16: * A buffer used to store small function objects in Chris@16: * boost::function. It is a union containing function pointers, Chris@16: * object pointers, and a structure that resembles a bound Chris@16: * member function pointer. Chris@16: */ Chris@16: union function_buffer Chris@16: { Chris@16: // For pointers to function objects Chris@16: mutable void* obj_ptr; Chris@16: Chris@16: // For pointers to std::type_info objects Chris@16: struct type_t { Chris@16: // (get_functor_type_tag, check_functor_type_tag). Chris@16: const detail::sp_typeinfo* type; Chris@16: Chris@16: // Whether the type is const-qualified. Chris@16: bool const_qualified; Chris@16: // Whether the type is volatile-qualified. Chris@16: bool volatile_qualified; Chris@16: } type; Chris@16: Chris@16: // For function pointers of all kinds Chris@16: mutable void (*func_ptr)(); Chris@16: Chris@16: // For bound member pointers Chris@16: struct bound_memfunc_ptr_t { Chris@16: void (X::*memfunc_ptr)(int); Chris@16: void* obj_ptr; Chris@16: } bound_memfunc_ptr; Chris@16: Chris@16: // For references to function objects. We explicitly keep Chris@16: // track of the cv-qualifiers on the object referenced. Chris@16: struct obj_ref_t { Chris@16: mutable void* obj_ptr; Chris@16: bool is_const_qualified; Chris@16: bool is_volatile_qualified; Chris@16: } obj_ref; Chris@16: Chris@16: // To relax aliasing constraints Chris@16: mutable char data; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * The unusable class is a placeholder for unused function arguments Chris@16: * It is also completely unusable except that it constructable from Chris@16: * anything. This helps compilers without partial specialization to Chris@16: * handle Boost.Function objects returning void. Chris@16: */ Chris@16: struct unusable Chris@16: { Chris@16: unusable() {} Chris@16: template unusable(const T&) {} Chris@16: }; Chris@16: Chris@16: /* Determine the return type. This supports compilers that do not support Chris@16: * void returns or partial specialization by silently changing the return Chris@16: * type to "unusable". Chris@16: */ Chris@16: template struct function_return_type { typedef T type; }; Chris@16: Chris@16: template<> Chris@16: struct function_return_type Chris@16: { Chris@16: typedef unusable type; Chris@16: }; Chris@16: Chris@16: // The operation type to perform on the given functor/function pointer Chris@16: enum functor_manager_operation_type { Chris@16: clone_functor_tag, Chris@16: move_functor_tag, Chris@16: destroy_functor_tag, Chris@16: check_functor_type_tag, Chris@16: get_functor_type_tag Chris@16: }; Chris@16: Chris@16: // Tags used to decide between different types of functions Chris@16: struct function_ptr_tag {}; Chris@16: struct function_obj_tag {}; Chris@16: struct member_ptr_tag {}; Chris@16: struct function_obj_ref_tag {}; Chris@16: Chris@16: template Chris@16: class get_function_tag Chris@16: { Chris@16: typedef typename mpl::if_c<(is_pointer::value), Chris@16: function_ptr_tag, Chris@16: function_obj_tag>::type ptr_or_obj_tag; Chris@16: Chris@16: typedef typename mpl::if_c<(is_member_pointer::value), Chris@16: member_ptr_tag, Chris@16: ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag; Chris@16: Chris@16: typedef typename mpl::if_c<(is_reference_wrapper::value), Chris@16: function_obj_ref_tag, Chris@16: ptr_or_obj_or_mem_tag>::type or_ref_tag; Chris@16: Chris@16: public: Chris@16: typedef or_ref_tag type; Chris@16: }; Chris@16: Chris@16: // The trivial manager does nothing but return the same pointer (if we Chris@16: // are cloning) or return the null pointer (if we are deleting). Chris@16: template Chris@16: struct reference_manager Chris@16: { Chris@16: static inline void Chris@16: manage(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op) Chris@16: { Chris@16: switch (op) { Chris@16: case clone_functor_tag: Chris@16: out_buffer.obj_ref = in_buffer.obj_ref; Chris@16: return; Chris@16: Chris@16: case move_functor_tag: Chris@16: out_buffer.obj_ref = in_buffer.obj_ref; Chris@16: in_buffer.obj_ref.obj_ptr = 0; Chris@16: return; Chris@16: Chris@16: case destroy_functor_tag: Chris@16: out_buffer.obj_ref.obj_ptr = 0; Chris@16: return; Chris@16: Chris@16: case check_functor_type_tag: Chris@16: { Chris@16: const detail::sp_typeinfo& check_type Chris@16: = *out_buffer.type.type; Chris@16: Chris@16: // Check whether we have the same type. We can add Chris@16: // cv-qualifiers, but we can't take them away. Chris@16: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(F)) Chris@16: && (!in_buffer.obj_ref.is_const_qualified Chris@16: || out_buffer.type.const_qualified) Chris@16: && (!in_buffer.obj_ref.is_volatile_qualified Chris@16: || out_buffer.type.volatile_qualified)) Chris@16: out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr; Chris@16: else Chris@16: out_buffer.obj_ptr = 0; Chris@16: } Chris@16: return; Chris@16: Chris@16: case get_functor_type_tag: Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(F); Chris@16: out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified; Chris@16: out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified; Chris@16: return; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Determine if boost::function can use the small-object Chris@16: * optimization with the function object type F. Chris@16: */ Chris@16: template Chris@16: struct function_allows_small_object_optimization Chris@16: { Chris@16: BOOST_STATIC_CONSTANT Chris@16: (bool, Chris@16: value = ((sizeof(F) <= sizeof(function_buffer) && Chris@16: (alignment_of::value Chris@16: % alignment_of::value == 0)))); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct functor_wrapper: public F, public A Chris@16: { Chris@16: functor_wrapper( F f, A a ): Chris@16: F(f), Chris@16: A(a) Chris@16: { Chris@16: } Chris@16: Chris@16: functor_wrapper(const functor_wrapper& f) : Chris@16: F(static_cast(f)), Chris@16: A(static_cast(f)) Chris@16: { Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * The functor_manager class contains a static function "manage" which Chris@16: * can clone or destroy the given function/function object pointer. Chris@16: */ Chris@16: template Chris@16: struct functor_manager_common Chris@16: { Chris@16: typedef Functor functor_type; Chris@16: Chris@16: // Function pointers Chris@16: static inline void Chris@16: manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op) Chris@16: { Chris@16: if (op == clone_functor_tag) Chris@16: out_buffer.func_ptr = in_buffer.func_ptr; Chris@16: else if (op == move_functor_tag) { Chris@16: out_buffer.func_ptr = in_buffer.func_ptr; Chris@16: in_buffer.func_ptr = 0; Chris@16: } else if (op == destroy_functor_tag) Chris@16: out_buffer.func_ptr = 0; Chris@16: else if (op == check_functor_type_tag) { Chris@101: const boost::detail::sp_typeinfo& check_type Chris@16: = *out_buffer.type.type; Chris@16: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor))) Chris@16: out_buffer.obj_ptr = &in_buffer.func_ptr; Chris@16: else Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else /* op == get_functor_type_tag */ { Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: } Chris@16: } Chris@16: Chris@16: // Function objects that fit in the small-object buffer. Chris@16: static inline void Chris@16: manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op) Chris@16: { Chris@16: if (op == clone_functor_tag || op == move_functor_tag) { Chris@16: const functor_type* in_functor = Chris@16: reinterpret_cast(&in_buffer.data); Chris@16: new (reinterpret_cast(&out_buffer.data)) functor_type(*in_functor); Chris@16: Chris@16: if (op == move_functor_tag) { Chris@16: functor_type* f = reinterpret_cast(&in_buffer.data); Chris@16: (void)f; // suppress warning about the value of f not being used (MSVC) Chris@16: f->~Functor(); Chris@16: } Chris@16: } else if (op == destroy_functor_tag) { Chris@16: // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. Chris@16: functor_type* f = reinterpret_cast(&out_buffer.data); Chris@16: (void)f; // suppress warning about the value of f not being used (MSVC) Chris@16: f->~Functor(); Chris@16: } else if (op == check_functor_type_tag) { Chris@16: const detail::sp_typeinfo& check_type Chris@16: = *out_buffer.type.type; Chris@16: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor))) Chris@16: out_buffer.obj_ptr = &in_buffer.data; Chris@16: else Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else /* op == get_functor_type_tag */ { Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct functor_manager Chris@16: { Chris@16: private: Chris@16: typedef Functor functor_type; Chris@16: Chris@16: // Function pointers Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, function_ptr_tag) Chris@16: { Chris@16: functor_manager_common::manage_ptr(in_buffer,out_buffer,op); Chris@16: } Chris@16: Chris@16: // Function objects that fit in the small-object buffer. Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, mpl::true_) Chris@16: { Chris@16: functor_manager_common::manage_small(in_buffer,out_buffer,op); Chris@16: } Chris@16: Chris@16: // Function objects that require heap allocation Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, mpl::false_) Chris@16: { Chris@16: if (op == clone_functor_tag) { Chris@16: // Clone the functor Chris@16: // GCC 2.95.3 gets the CV qualifiers wrong here, so we Chris@16: // can't do the static_cast that we should do. Chris@16: // jewillco: Changing this to static_cast because GCC 2.95.3 is Chris@16: // obsolete. Chris@16: const functor_type* f = Chris@16: static_cast(in_buffer.obj_ptr); Chris@16: functor_type* new_f = new functor_type(*f); Chris@16: out_buffer.obj_ptr = new_f; Chris@16: } else if (op == move_functor_tag) { Chris@16: out_buffer.obj_ptr = in_buffer.obj_ptr; Chris@16: in_buffer.obj_ptr = 0; Chris@16: } else if (op == destroy_functor_tag) { Chris@16: /* Cast from the void pointer to the functor pointer type */ Chris@16: functor_type* f = Chris@16: static_cast(out_buffer.obj_ptr); Chris@16: delete f; Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else if (op == check_functor_type_tag) { Chris@16: const detail::sp_typeinfo& check_type Chris@16: = *out_buffer.type.type; Chris@16: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor))) Chris@16: out_buffer.obj_ptr = in_buffer.obj_ptr; Chris@16: else Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else /* op == get_functor_type_tag */ { Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: } Chris@16: } Chris@16: Chris@16: // For function objects, we determine whether the function Chris@16: // object can use the small-object optimization buffer or Chris@16: // whether we need to allocate it on the heap. Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, function_obj_tag) Chris@16: { Chris@16: manager(in_buffer, out_buffer, op, Chris@16: mpl::bool_<(function_allows_small_object_optimization::value)>()); Chris@16: } Chris@16: Chris@16: // For member pointers, we use the small-object optimization buffer. Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, member_ptr_tag) Chris@16: { Chris@16: manager(in_buffer, out_buffer, op, mpl::true_()); Chris@16: } Chris@16: Chris@16: public: Chris@16: /* Dispatch to an appropriate manager based on whether we have a Chris@16: function pointer or a function object pointer. */ Chris@16: static inline void Chris@16: manage(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op) Chris@16: { Chris@16: typedef typename get_function_tag::type tag_type; Chris@16: switch (op) { Chris@16: case get_functor_type_tag: Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(functor_type); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: return; Chris@16: Chris@16: default: Chris@16: manager(in_buffer, out_buffer, op, tag_type()); Chris@16: return; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct functor_manager_a Chris@16: { Chris@16: private: Chris@16: typedef Functor functor_type; Chris@16: Chris@16: // Function pointers Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, function_ptr_tag) Chris@16: { Chris@16: functor_manager_common::manage_ptr(in_buffer,out_buffer,op); Chris@16: } Chris@16: Chris@16: // Function objects that fit in the small-object buffer. Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, mpl::true_) Chris@16: { Chris@16: functor_manager_common::manage_small(in_buffer,out_buffer,op); Chris@16: } Chris@16: Chris@16: // Function objects that require heap allocation Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, mpl::false_) Chris@16: { Chris@16: typedef functor_wrapper functor_wrapper_type; Chris@16: typedef typename Allocator::template rebind::other Chris@16: wrapper_allocator_type; Chris@16: typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type; Chris@16: Chris@16: if (op == clone_functor_tag) { Chris@16: // Clone the functor Chris@16: // GCC 2.95.3 gets the CV qualifiers wrong here, so we Chris@16: // can't do the static_cast that we should do. Chris@16: const functor_wrapper_type* f = Chris@16: static_cast(in_buffer.obj_ptr); Chris@16: wrapper_allocator_type wrapper_allocator(static_cast(*f)); Chris@16: wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); Chris@16: wrapper_allocator.construct(copy, *f); Chris@16: Chris@16: // Get back to the original pointer type Chris@16: functor_wrapper_type* new_f = static_cast(copy); Chris@16: out_buffer.obj_ptr = new_f; Chris@16: } else if (op == move_functor_tag) { Chris@16: out_buffer.obj_ptr = in_buffer.obj_ptr; Chris@16: in_buffer.obj_ptr = 0; Chris@16: } else if (op == destroy_functor_tag) { Chris@16: /* Cast from the void pointer to the functor_wrapper_type */ Chris@16: functor_wrapper_type* victim = Chris@16: static_cast(in_buffer.obj_ptr); Chris@16: wrapper_allocator_type wrapper_allocator(static_cast(*victim)); Chris@16: wrapper_allocator.destroy(victim); Chris@16: wrapper_allocator.deallocate(victim,1); Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else if (op == check_functor_type_tag) { Chris@16: const detail::sp_typeinfo& check_type Chris@16: = *out_buffer.type.type; Chris@16: if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor))) Chris@16: out_buffer.obj_ptr = in_buffer.obj_ptr; Chris@16: else Chris@16: out_buffer.obj_ptr = 0; Chris@16: } else /* op == get_functor_type_tag */ { Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: } Chris@16: } Chris@16: Chris@16: // For function objects, we determine whether the function Chris@16: // object can use the small-object optimization buffer or Chris@16: // whether we need to allocate it on the heap. Chris@16: static inline void Chris@16: manager(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op, function_obj_tag) Chris@16: { Chris@16: manager(in_buffer, out_buffer, op, Chris@16: mpl::bool_<(function_allows_small_object_optimization::value)>()); Chris@16: } Chris@16: Chris@16: public: Chris@16: /* Dispatch to an appropriate manager based on whether we have a Chris@16: function pointer or a function object pointer. */ Chris@16: static inline void Chris@16: manage(const function_buffer& in_buffer, function_buffer& out_buffer, Chris@16: functor_manager_operation_type op) Chris@16: { Chris@16: typedef typename get_function_tag::type tag_type; Chris@16: switch (op) { Chris@16: case get_functor_type_tag: Chris@16: out_buffer.type.type = &BOOST_SP_TYPEID(functor_type); Chris@16: out_buffer.type.const_qualified = false; Chris@16: out_buffer.type.volatile_qualified = false; Chris@16: return; Chris@16: Chris@16: default: Chris@16: manager(in_buffer, out_buffer, op, tag_type()); Chris@16: return; Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: // A type that is only used for comparisons against zero Chris@16: struct useless_clear_type {}; Chris@16: Chris@16: #ifdef BOOST_NO_SFINAE Chris@16: // These routines perform comparisons between a Boost.Function Chris@16: // object and an arbitrary function object (when the last Chris@16: // parameter is mpl::bool_) or against zero (when the Chris@16: // last parameter is mpl::bool_). They are only necessary Chris@16: // for compilers that don't support SFINAE. Chris@16: template Chris@16: bool Chris@16: compare_equal(const Function& f, const Functor&, int, mpl::bool_) Chris@16: { return f.empty(); } Chris@16: Chris@16: template Chris@16: bool Chris@16: compare_not_equal(const Function& f, const Functor&, int, Chris@16: mpl::bool_) Chris@16: { return !f.empty(); } Chris@16: Chris@16: template Chris@16: bool Chris@16: compare_equal(const Function& f, const Functor& g, long, Chris@16: mpl::bool_) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return function_equal(*fp, g); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: compare_equal(const Function& f, const reference_wrapper& g, Chris@16: int, mpl::bool_) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return fp == g.get_pointer(); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: compare_not_equal(const Function& f, const Functor& g, long, Chris@16: mpl::bool_) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return !function_equal(*fp, g); Chris@16: else return true; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: compare_not_equal(const Function& f, Chris@16: const reference_wrapper& g, int, Chris@16: mpl::bool_) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return fp != g.get_pointer(); Chris@16: else return true; Chris@16: } Chris@16: #endif // BOOST_NO_SFINAE Chris@16: Chris@16: /** Chris@16: * Stores the "manager" portion of the vtable for a Chris@16: * boost::function object. Chris@16: */ Chris@16: struct vtable_base Chris@16: { Chris@16: void (*manager)(const function_buffer& in_buffer, Chris@16: function_buffer& out_buffer, Chris@16: functor_manager_operation_type op); Chris@16: }; Chris@16: } // end namespace function Chris@16: } // end namespace detail Chris@16: Chris@16: /** Chris@16: * The function_base class contains the basic elements needed for the Chris@16: * function1, function2, function3, etc. classes. It is common to all Chris@16: * functions (and as such can be used to tell if we have one of the Chris@16: * functionN objects). Chris@16: */ Chris@16: class function_base Chris@16: { Chris@16: public: Chris@16: function_base() : vtable(0) { } Chris@16: Chris@16: /** Determine if the function is empty (i.e., has no target). */ Chris@16: bool empty() const { return !vtable; } Chris@16: Chris@16: /** Retrieve the type of the stored function object, or BOOST_SP_TYPEID(void) Chris@16: if this is empty. */ Chris@16: const detail::sp_typeinfo& target_type() const Chris@16: { Chris@16: if (!vtable) return BOOST_SP_TYPEID(void); Chris@16: Chris@16: detail::function::function_buffer type; Chris@16: get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); Chris@16: return *type.type.type; Chris@16: } Chris@16: Chris@16: template Chris@16: Functor* target() Chris@16: { Chris@16: if (!vtable) return 0; Chris@16: Chris@16: detail::function::function_buffer type_result; Chris@16: type_result.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: type_result.type.const_qualified = is_const::value; Chris@16: type_result.type.volatile_qualified = is_volatile::value; Chris@16: get_vtable()->manager(functor, type_result, Chris@16: detail::function::check_functor_type_tag); Chris@16: return static_cast(type_result.obj_ptr); Chris@16: } Chris@16: Chris@16: template Chris@16: const Functor* target() const Chris@16: { Chris@16: if (!vtable) return 0; Chris@16: Chris@16: detail::function::function_buffer type_result; Chris@16: type_result.type.type = &BOOST_SP_TYPEID(Functor); Chris@16: type_result.type.const_qualified = true; Chris@16: type_result.type.volatile_qualified = is_volatile::value; Chris@16: get_vtable()->manager(functor, type_result, Chris@16: detail::function::check_functor_type_tag); Chris@16: // GCC 2.95.3 gets the CV qualifiers wrong here, so we Chris@16: // can't do the static_cast that we should do. Chris@16: return static_cast(type_result.obj_ptr); Chris@16: } Chris@16: Chris@16: template Chris@16: bool contains(const F& f) const Chris@16: { Chris@16: if (const F* fp = this->template target()) Chris@16: { Chris@16: return function_equal(*fp, f); Chris@16: } else { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3 Chris@16: // GCC 3.3 and newer cannot copy with the global operator==, due to Chris@16: // problems with instantiation of function return types before it Chris@16: // has been verified that the argument types match up. Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator==(Functor g) const Chris@16: { Chris@16: if (const Functor* fp = target()) Chris@16: return function_equal(*fp, g); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator!=(Functor g) const Chris@16: { Chris@16: if (const Functor* fp = target()) Chris@16: return !function_equal(*fp, g); Chris@16: else return true; Chris@16: } Chris@16: #endif Chris@16: Chris@16: public: // should be protected, but GCC 2.95.3 will fail to allow access Chris@16: detail::function::vtable_base* get_vtable() const { Chris@16: return reinterpret_cast( Chris@16: reinterpret_cast(vtable) & ~static_cast(0x01)); Chris@16: } Chris@16: Chris@16: bool has_trivial_copy_and_destroy() const { Chris@16: return reinterpret_cast(vtable) & 0x01; Chris@16: } Chris@16: Chris@16: detail::function::vtable_base* vtable; Chris@16: mutable detail::function::function_buffer functor; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * The bad_function_call exception class is thrown when a boost::function Chris@16: * object is invoked Chris@16: */ Chris@16: class bad_function_call : public std::runtime_error Chris@16: { Chris@16: public: Chris@16: bad_function_call() : std::runtime_error("call to empty boost::function") {} Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_SFINAE Chris@16: inline bool operator==(const function_base& f, Chris@16: detail::function::useless_clear_type*) Chris@16: { Chris@16: return f.empty(); Chris@16: } Chris@16: Chris@16: inline bool operator!=(const function_base& f, Chris@16: detail::function::useless_clear_type*) Chris@16: { Chris@16: return !f.empty(); Chris@16: } Chris@16: Chris@16: inline bool operator==(detail::function::useless_clear_type*, Chris@16: const function_base& f) Chris@16: { Chris@16: return f.empty(); Chris@16: } Chris@16: Chris@16: inline bool operator!=(detail::function::useless_clear_type*, Chris@16: const function_base& f) Chris@16: { Chris@16: return !f.empty(); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_NO_SFINAE Chris@16: // Comparisons between boost::function objects and arbitrary function objects Chris@16: template Chris@16: inline bool operator==(const function_base& f, Functor g) Chris@16: { Chris@16: typedef mpl::bool_<(is_integral::value)> integral; Chris@16: return detail::function::compare_equal(f, g, 0, integral()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator==(Functor g, const function_base& f) Chris@16: { Chris@16: typedef mpl::bool_<(is_integral::value)> integral; Chris@16: return detail::function::compare_equal(f, g, 0, integral()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(const function_base& f, Functor g) Chris@16: { Chris@16: typedef mpl::bool_<(is_integral::value)> integral; Chris@16: return detail::function::compare_not_equal(f, g, 0, integral()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool operator!=(Functor g, const function_base& f) Chris@16: { Chris@16: typedef mpl::bool_<(is_integral::value)> integral; Chris@16: return detail::function::compare_not_equal(f, g, 0, integral()); Chris@16: } Chris@16: #else Chris@16: Chris@16: # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3) Chris@16: // Comparisons between boost::function objects and arbitrary function Chris@16: // objects. GCC 3.3 and before has an obnoxious bug that prevents this Chris@16: // from working. Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator==(const function_base& f, Functor g) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return function_equal(*fp, g); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator==(Functor g, const function_base& f) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return function_equal(g, *fp); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator!=(const function_base& f, Functor g) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return !function_equal(*fp, g); Chris@16: else return true; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator!=(Functor g, const function_base& f) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return !function_equal(g, *fp); Chris@16: else return true; Chris@16: } Chris@16: # endif Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator==(const function_base& f, reference_wrapper g) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return fp == g.get_pointer(); Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator==(reference_wrapper g, const function_base& f) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return g.get_pointer() == fp; Chris@16: else return false; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator!=(const function_base& f, reference_wrapper g) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return fp != g.get_pointer(); Chris@16: else return true; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) Chris@16: operator!=(reference_wrapper g, const function_base& f) Chris@16: { Chris@16: if (const Functor* fp = f.template target()) Chris@16: return g.get_pointer() != fp; Chris@16: else return true; Chris@16: } Chris@16: Chris@16: #endif // Compiler supporting SFINAE Chris@16: Chris@16: namespace detail { Chris@16: namespace function { Chris@16: inline bool has_empty_target(const function_base* f) Chris@16: { Chris@16: return f->empty(); Chris@16: } Chris@16: Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310) Chris@16: inline bool has_empty_target(const void*) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: #else Chris@16: inline bool has_empty_target(...) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: #endif Chris@16: } // end namespace function Chris@16: } // end namespace detail Chris@16: } // end namespace boost Chris@16: Chris@16: #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL Chris@16: #undef BOOST_FUNCTION_COMPARE_TYPE_ID Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: # pragma warning( pop ) Chris@16: #endif Chris@16: Chris@16: #endif // BOOST_FUNCTION_BASE_HEADER