| // Boost.Function library |
| |
| // 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 |
| |
| #ifndef NDNBOOST_FUNCTION_BASE_HEADER |
| #define NDNBOOST_FUNCTION_BASE_HEADER |
| |
| #include <stdexcept> |
| #include <string> |
| #include <memory> |
| #include <new> |
| #include <ndnboost/config.hpp> |
| #include <ndnboost/detail/sp_typeinfo.hpp> |
| #include <ndnboost/assert.hpp> |
| #include <ndnboost/integer.hpp> |
| #include <ndnboost/type_traits/has_trivial_copy.hpp> |
| #include <ndnboost/type_traits/has_trivial_destructor.hpp> |
| #include <ndnboost/type_traits/is_const.hpp> |
| #include <ndnboost/type_traits/is_integral.hpp> |
| #include <ndnboost/type_traits/is_volatile.hpp> |
| #include <ndnboost/type_traits/composite_traits.hpp> |
| #include <ndnboost/type_traits/ice.hpp> |
| #include <ndnboost/ref.hpp> |
| #include <ndnboost/mpl/if.hpp> |
| #include <ndnboost/detail/workaround.hpp> |
| #include <ndnboost/type_traits/alignment_of.hpp> |
| #ifndef NDNBOOST_NO_SFINAE |
| # include "ndnboost/utility/enable_if.hpp" |
| #else |
| # include "ndnboost/mpl/bool.hpp" |
| #endif |
| #include <ndnboost/function_equal.hpp> |
| #include <ndnboost/function/function_fwd.hpp> |
| |
| #if defined(NDNBOOST_MSVC) |
| # pragma warning( push ) |
| # pragma warning( disable : 4793 ) // complaint about native code generation |
| # pragma warning( disable : 4127 ) // "conditional expression is constant" |
| #endif |
| |
| // Define NDNBOOST_FUNCTION_STD_NS to the namespace that contains type_info. |
| #ifdef NDNBOOST_NO_STD_TYPEINFO |
| // Embedded VC++ does not have type_info in namespace std |
| # define NDNBOOST_FUNCTION_STD_NS |
| #else |
| # define NDNBOOST_FUNCTION_STD_NS std |
| #endif |
| |
| // Borrowed from Boost.Python library: determines the cases where we |
| // need to use std::type_info::name to compare instead of operator==. |
| #if defined( NDNBOOST_NO_TYPEID ) |
| # define NDNBOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) |
| #elif (defined(__GNUC__) && __GNUC__ >= 3) \ |
| || defined(_AIX) \ |
| || ( defined(__sgi) && defined(__host_mips)) |
| # include <cstring> |
| # define NDNBOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \ |
| (std::strcmp((X).name(),(Y).name()) == 0) |
| # else |
| # define NDNBOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) |
| #endif |
| |
| #if defined(NDNBOOST_MSVC) && NDNBOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(NDNBOOST_STRICT_CONFIG) |
| # define NDNBOOST_FUNCTION_TARGET_FIX(x) x |
| #else |
| # define NDNBOOST_FUNCTION_TARGET_FIX(x) |
| #endif // not MSVC |
| |
| #if !NDNBOOST_WORKAROUND(__BORLANDC__, < 0x5A0) |
| # define NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ |
| typename ::ndnboost::enable_if_c<(::ndnboost::type_traits::ice_not< \ |
| (::ndnboost::is_integral<Functor>::value)>::value), \ |
| Type>::type |
| #else |
| // BCC doesn't recognize this depends on a template argument and complains |
| // about the use of 'typename' |
| # define NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ |
| ::ndnboost::enable_if_c<(::ndnboost::type_traits::ice_not< \ |
| (::ndnboost::is_integral<Functor>::value)>::value), \ |
| Type>::type |
| #endif |
| |
| namespace ndnboost { |
| namespace detail { |
| namespace function { |
| class X; |
| |
| /** |
| * A buffer used to store small function objects in |
| * ndnboost::function. It is a union containing function pointers, |
| * object pointers, and a structure that resembles a bound |
| * member function pointer. |
| */ |
| union function_buffer |
| { |
| // For pointers to function objects |
| mutable void* obj_ptr; |
| |
| // For pointers to std::type_info objects |
| struct type_t { |
| // (get_functor_type_tag, check_functor_type_tag). |
| const detail::sp_typeinfo* 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)(); |
| |
| // For bound member pointers |
| struct bound_memfunc_ptr_t { |
| void (X::*memfunc_ptr)(int); |
| 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; |
| }; |
| |
| /** |
| * The unusable class is a placeholder for unused function arguments |
| * It is also completely unusable except that it constructable from |
| * anything. This helps compilers without partial specialization to |
| * handle Boost.Function objects returning void. |
| */ |
| struct unusable |
| { |
| unusable() {} |
| template<typename T> unusable(const T&) {} |
| }; |
| |
| /* Determine the return type. This supports compilers that do not support |
| * void returns or partial specialization by silently changing the return |
| * type to "unusable". |
| */ |
| template<typename T> struct function_return_type { typedef T type; }; |
| |
| template<> |
| struct function_return_type<void> |
| { |
| typedef unusable type; |
| }; |
| |
| // 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 |
| }; |
| |
| // Tags used to decide between different types of functions |
| struct function_ptr_tag {}; |
| struct function_obj_tag {}; |
| struct member_ptr_tag {}; |
| struct function_obj_ref_tag {}; |
| |
| template<typename F> |
| class get_function_tag |
| { |
| typedef typename mpl::if_c<(is_pointer<F>::value), |
| function_ptr_tag, |
| function_obj_tag>::type ptr_or_obj_tag; |
| |
| typedef typename mpl::if_c<(is_member_pointer<F>::value), |
| member_ptr_tag, |
| ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag; |
| |
| typedef typename mpl::if_c<(is_reference_wrapper<F>::value), |
| function_obj_ref_tag, |
| ptr_or_obj_or_mem_tag>::type or_ref_tag; |
| |
| public: |
| typedef or_ref_tag type; |
| }; |
| |
| // The trivial manager does nothing but return the same pointer (if we |
| // are cloning) or return the null pointer (if we are deleting). |
| template<typename F> |
| struct reference_manager |
| { |
| static inline void |
| manage(const function_buffer& in_buffer, function_buffer& out_buffer, |
| functor_manager_operation_type op) |
| { |
| switch (op) { |
| case clone_functor_tag: |
| out_buffer.obj_ref = in_buffer.obj_ref; |
| return; |
| |
| case move_functor_tag: |
| out_buffer.obj_ref = in_buffer.obj_ref; |
| in_buffer.obj_ref.obj_ptr = 0; |
| return; |
| |
| case destroy_functor_tag: |
| out_buffer.obj_ref.obj_ptr = 0; |
| return; |
| |
| case check_functor_type_tag: |
| { |
| const detail::sp_typeinfo& check_type |
| = *out_buffer.type.type; |
| |
| // Check whether we have the same type. We can add |
| // cv-qualifiers, but we can't take them away. |
| if (NDNBOOST_FUNCTION_COMPARE_TYPE_ID(check_type, NDNBOOST_SP_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.type.type = &NDNBOOST_SP_TYPEID(F); |
| out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified; |
| out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified; |
| return; |
| } |
| } |
| }; |
| |
| /** |
| * Determine if ndnboost::function can use the small-object |
| * optimization with the function object type F. |
| */ |
| template<typename F> |
| struct function_allows_small_object_optimization |
| { |
| NDNBOOST_STATIC_CONSTANT |
| (bool, |
| value = ((sizeof(F) <= sizeof(function_buffer) && |
| (alignment_of<function_buffer>::value |
| % alignment_of<F>::value == 0)))); |
| }; |
| |
| template <typename F,typename A> |
| struct functor_wrapper: public F, public A |
| { |
| functor_wrapper( F f, A a ): |
| F(f), |
| A(a) |
| { |
| } |
| |
| functor_wrapper(const functor_wrapper& f) : |
| F(static_cast<const F&>(f)), |
| A(static_cast<const A&>(f)) |
| { |
| } |
| }; |
| |
| /** |
| * The functor_manager class contains a static function "manage" which |
| * can clone or destroy the given function/function object pointer. |
| */ |
| template<typename Functor> |
| 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 detail::sp_typeinfo& check_type |
| = *out_buffer.type.type; |
| if (NDNBOOST_FUNCTION_COMPARE_TYPE_ID(check_type, NDNBOOST_SP_TYPEID(Functor))) |
| out_buffer.obj_ptr = &in_buffer.func_ptr; |
| else |
| out_buffer.obj_ptr = 0; |
| } else /* op == get_functor_type_tag */ { |
| out_buffer.type.type = &NDNBOOST_SP_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<const functor_type*>(&in_buffer.data); |
| new (reinterpret_cast<void*>(&out_buffer.data)) functor_type(*in_functor); |
| |
| if (op == move_functor_tag) { |
| functor_type* f = reinterpret_cast<functor_type*>(&in_buffer.data); |
| (void)f; // suppress warning about the value of f not being used (MSVC) |
| f->~Functor(); |
| } |
| } else if (op == destroy_functor_tag) { |
| // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. |
| functor_type* f = reinterpret_cast<functor_type*>(&out_buffer.data); |
| (void)f; // suppress warning about the value of f not being used (MSVC) |
| f->~Functor(); |
| } else if (op == check_functor_type_tag) { |
| const detail::sp_typeinfo& check_type |
| = *out_buffer.type.type; |
| if (NDNBOOST_FUNCTION_COMPARE_TYPE_ID(check_type, NDNBOOST_SP_TYPEID(Functor))) |
| out_buffer.obj_ptr = &in_buffer.data; |
| else |
| out_buffer.obj_ptr = 0; |
| } else /* op == get_functor_type_tag */ { |
| out_buffer.type.type = &NDNBOOST_SP_TYPEID(Functor); |
| out_buffer.type.const_qualified = false; |
| out_buffer.type.volatile_qualified = false; |
| } |
| } |
| }; |
| |
| template<typename Functor> |
| struct functor_manager |
| { |
| private: |
| typedef Functor functor_type; |
| |
| // Function pointers |
| static inline void |
| manager(const function_buffer& in_buffer, function_buffer& out_buffer, |
| functor_manager_operation_type op, function_ptr_tag) |
| { |
| functor_manager_common<Functor>::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<Functor>::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_) |
| { |
| 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. |
| // jewillco: Changing this to static_cast because GCC 2.95.3 is |
| // obsolete. |
| const functor_type* f = |
| static_cast<const functor_type*>(in_buffer.obj_ptr); |
| functor_type* new_f = new functor_type(*f); |
| out_buffer.obj_ptr = new_f; |
| } else if (op == move_functor_tag) { |
| out_buffer.obj_ptr = in_buffer.obj_ptr; |
| in_buffer.obj_ptr = 0; |
| } else if (op == destroy_functor_tag) { |
| /* Cast from the void pointer to the functor pointer type */ |
| functor_type* f = |
| static_cast<functor_type*>(out_buffer.obj_ptr); |
| delete f; |
| out_buffer.obj_ptr = 0; |
| } else if (op == check_functor_type_tag) { |
| const detail::sp_typeinfo& check_type |
| = *out_buffer.type.type; |
| if (NDNBOOST_FUNCTION_COMPARE_TYPE_ID(check_type, NDNBOOST_SP_TYPEID(Functor))) |
| out_buffer.obj_ptr = in_buffer.obj_ptr; |
| else |
| out_buffer.obj_ptr = 0; |
| } else /* op == get_functor_type_tag */ { |
| out_buffer.type.type = &NDNBOOST_SP_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<functor_type>::value)>()); |
| } |
| |
| // For member pointers, we use the small-object optimization buffer. |
| static inline void |
| manager(const function_buffer& in_buffer, function_buffer& out_buffer, |
| functor_manager_operation_type op, member_ptr_tag) |
| { |
| manager(in_buffer, out_buffer, op, mpl::true_()); |
| } |
| |
| public: |
| /* Dispatch to an appropriate manager based on whether we have a |
| function pointer or a function object pointer. */ |
| static inline void |
| manage(const function_buffer& in_buffer, function_buffer& out_buffer, |
| functor_manager_operation_type op) |
| { |
| typedef typename get_function_tag<functor_type>::type tag_type; |
| switch (op) { |
| case get_functor_type_tag: |
| out_buffer.type.type = &NDNBOOST_SP_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<typename Functor, typename Allocator> |
| 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, function_ptr_tag) |
| { |
| functor_manager_common<Functor>::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<Functor>::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,Allocator> functor_wrapper_type; |
| typedef typename Allocator::template rebind<functor_wrapper_type>::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 = |
| static_cast<const functor_wrapper_type*>(in_buffer.obj_ptr); |
| wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*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<functor_wrapper_type*>(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<functor_wrapper_type*>(in_buffer.obj_ptr); |
| wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim)); |
| wrapper_allocator.destroy(victim); |
| wrapper_allocator.deallocate(victim,1); |
| out_buffer.obj_ptr = 0; |
| } else if (op == check_functor_type_tag) { |
| const detail::sp_typeinfo& check_type |
| = *out_buffer.type.type; |
| if (NDNBOOST_FUNCTION_COMPARE_TYPE_ID(check_type, NDNBOOST_SP_TYPEID(Functor))) |
| out_buffer.obj_ptr = in_buffer.obj_ptr; |
| else |
| out_buffer.obj_ptr = 0; |
| } else /* op == get_functor_type_tag */ { |
| out_buffer.type.type = &NDNBOOST_SP_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<functor_type>::value)>()); |
| } |
| |
| 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<functor_type>::type tag_type; |
| switch (op) { |
| case get_functor_type_tag: |
| out_buffer.type.type = &NDNBOOST_SP_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; |
| } |
| } |
| }; |
| |
| // A type that is only used for comparisons against zero |
| struct useless_clear_type {}; |
| |
| #ifdef NDNBOOST_NO_SFINAE |
| // These routines perform comparisons between a Boost.Function |
| // object and an arbitrary function object (when the last |
| // parameter is mpl::bool_<false>) or against zero (when the |
| // last parameter is mpl::bool_<true>). They are only necessary |
| // for compilers that don't support SFINAE. |
| template<typename Function, typename Functor> |
| bool |
| compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>) |
| { return f.empty(); } |
| |
| template<typename Function, typename Functor> |
| bool |
| compare_not_equal(const Function& f, const Functor&, int, |
| mpl::bool_<true>) |
| { return !f.empty(); } |
| |
| template<typename Function, typename Functor> |
| bool |
| compare_equal(const Function& f, const Functor& g, long, |
| mpl::bool_<false>) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return function_equal(*fp, g); |
| else return false; |
| } |
| |
| template<typename Function, typename Functor> |
| bool |
| compare_equal(const Function& f, const reference_wrapper<Functor>& g, |
| int, mpl::bool_<false>) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return fp == g.get_pointer(); |
| else return false; |
| } |
| |
| template<typename Function, typename Functor> |
| bool |
| compare_not_equal(const Function& f, const Functor& g, long, |
| mpl::bool_<false>) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return !function_equal(*fp, g); |
| else return true; |
| } |
| |
| template<typename Function, typename Functor> |
| bool |
| compare_not_equal(const Function& f, |
| const reference_wrapper<Functor>& g, int, |
| mpl::bool_<false>) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return fp != g.get_pointer(); |
| else return true; |
| } |
| #endif // NDNBOOST_NO_SFINAE |
| |
| /** |
| * Stores the "manager" portion of the vtable for a |
| * ndnboost::function object. |
| */ |
| struct vtable_base |
| { |
| void (*manager)(const function_buffer& in_buffer, |
| function_buffer& out_buffer, |
| functor_manager_operation_type op); |
| }; |
| } // end namespace function |
| } // end namespace detail |
| |
| /** |
| * The function_base class contains the basic elements needed for the |
| * function1, function2, function3, etc. classes. It is common to all |
| * functions (and as such can be used to tell if we have one of the |
| * functionN objects). |
| */ |
| class function_base |
| { |
| public: |
| function_base() : vtable(0) { } |
| |
| /** Determine if the function is empty (i.e., has no target). */ |
| bool empty() const { return !vtable; } |
| |
| /** Retrieve the type of the stored function object, or NDNBOOST_SP_TYPEID(void) |
| if this is empty. */ |
| const detail::sp_typeinfo& target_type() const |
| { |
| if (!vtable) return NDNBOOST_SP_TYPEID(void); |
| |
| detail::function::function_buffer type; |
| get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); |
| return *type.type.type; |
| } |
| |
| template<typename Functor> |
| Functor* target() |
| { |
| if (!vtable) return 0; |
| |
| detail::function::function_buffer type_result; |
| type_result.type.type = &NDNBOOST_SP_TYPEID(Functor); |
| type_result.type.const_qualified = is_const<Functor>::value; |
| type_result.type.volatile_qualified = is_volatile<Functor>::value; |
| get_vtable()->manager(functor, type_result, |
| detail::function::check_functor_type_tag); |
| return static_cast<Functor*>(type_result.obj_ptr); |
| } |
| |
| template<typename Functor> |
| #if defined(NDNBOOST_MSVC) && NDNBOOST_WORKAROUND(NDNBOOST_MSVC, < 1300) |
| const Functor* target( Functor * = 0 ) const |
| #else |
| const Functor* target() const |
| #endif |
| { |
| if (!vtable) return 0; |
| |
| detail::function::function_buffer type_result; |
| type_result.type.type = &NDNBOOST_SP_TYPEID(Functor); |
| type_result.type.const_qualified = true; |
| type_result.type.volatile_qualified = is_volatile<Functor>::value; |
| get_vtable()->manager(functor, type_result, |
| detail::function::check_functor_type_tag); |
| // GCC 2.95.3 gets the CV qualifiers wrong here, so we |
| // can't do the static_cast that we should do. |
| return static_cast<const Functor*>(type_result.obj_ptr); |
| } |
| |
| template<typename F> |
| bool contains(const F& f) const |
| { |
| #if defined(NDNBOOST_MSVC) && NDNBOOST_WORKAROUND(NDNBOOST_MSVC, < 1300) |
| if (const F* fp = this->target( (F*)0 )) |
| #else |
| if (const F* fp = this->template target<F>()) |
| #endif |
| { |
| return function_equal(*fp, f); |
| } else { |
| return false; |
| } |
| } |
| |
| #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3 |
| // GCC 3.3 and newer cannot copy with the global operator==, due to |
| // problems with instantiation of function return types before it |
| // has been verified that the argument types match up. |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator==(Functor g) const |
| { |
| if (const Functor* fp = target<Functor>()) |
| return function_equal(*fp, g); |
| else return false; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator!=(Functor g) const |
| { |
| if (const Functor* fp = target<Functor>()) |
| return !function_equal(*fp, g); |
| else return true; |
| } |
| #endif |
| |
| public: // should be protected, but GCC 2.95.3 will fail to allow access |
| detail::function::vtable_base* get_vtable() const { |
| return reinterpret_cast<detail::function::vtable_base*>( |
| reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01)); |
| } |
| |
| bool has_trivial_copy_and_destroy() const { |
| return reinterpret_cast<std::size_t>(vtable) & 0x01; |
| } |
| |
| detail::function::vtable_base* vtable; |
| mutable detail::function::function_buffer functor; |
| }; |
| |
| /** |
| * The bad_function_call exception class is thrown when a ndnboost::function |
| * object is invoked |
| */ |
| class bad_function_call : public std::runtime_error |
| { |
| public: |
| bad_function_call() : std::runtime_error("call to empty ndnboost::function") {} |
| }; |
| |
| #ifndef NDNBOOST_NO_SFINAE |
| inline bool operator==(const function_base& f, |
| detail::function::useless_clear_type*) |
| { |
| return f.empty(); |
| } |
| |
| inline bool operator!=(const function_base& f, |
| detail::function::useless_clear_type*) |
| { |
| return !f.empty(); |
| } |
| |
| inline bool operator==(detail::function::useless_clear_type*, |
| const function_base& f) |
| { |
| return f.empty(); |
| } |
| |
| inline bool operator!=(detail::function::useless_clear_type*, |
| const function_base& f) |
| { |
| return !f.empty(); |
| } |
| #endif |
| |
| #ifdef NDNBOOST_NO_SFINAE |
| // Comparisons between ndnboost::function objects and arbitrary function objects |
| template<typename Functor> |
| inline bool operator==(const function_base& f, Functor g) |
| { |
| typedef mpl::bool_<(is_integral<Functor>::value)> integral; |
| return detail::function::compare_equal(f, g, 0, integral()); |
| } |
| |
| template<typename Functor> |
| inline bool operator==(Functor g, const function_base& f) |
| { |
| typedef mpl::bool_<(is_integral<Functor>::value)> integral; |
| return detail::function::compare_equal(f, g, 0, integral()); |
| } |
| |
| template<typename Functor> |
| inline bool operator!=(const function_base& f, Functor g) |
| { |
| typedef mpl::bool_<(is_integral<Functor>::value)> integral; |
| return detail::function::compare_not_equal(f, g, 0, integral()); |
| } |
| |
| template<typename Functor> |
| inline bool operator!=(Functor g, const function_base& f) |
| { |
| typedef mpl::bool_<(is_integral<Functor>::value)> integral; |
| return detail::function::compare_not_equal(f, g, 0, integral()); |
| } |
| #else |
| |
| # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3) |
| // Comparisons between ndnboost::function objects and arbitrary function |
| // objects. GCC 3.3 and before has an obnoxious bug that prevents this |
| // from working. |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator==(const function_base& f, Functor g) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return function_equal(*fp, g); |
| else return false; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator==(Functor g, const function_base& f) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return function_equal(g, *fp); |
| else return false; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator!=(const function_base& f, Functor g) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return !function_equal(*fp, g); |
| else return true; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator!=(Functor g, const function_base& f) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return !function_equal(g, *fp); |
| else return true; |
| } |
| # endif |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator==(const function_base& f, reference_wrapper<Functor> g) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return fp == g.get_pointer(); |
| else return false; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator==(reference_wrapper<Functor> g, const function_base& f) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return g.get_pointer() == fp; |
| else return false; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator!=(const function_base& f, reference_wrapper<Functor> g) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return fp != g.get_pointer(); |
| else return true; |
| } |
| |
| template<typename Functor> |
| NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool) |
| operator!=(reference_wrapper<Functor> g, const function_base& f) |
| { |
| if (const Functor* fp = f.template target<Functor>()) |
| return g.get_pointer() != fp; |
| else return true; |
| } |
| |
| #endif // Compiler supporting SFINAE |
| |
| namespace detail { |
| namespace function { |
| inline bool has_empty_target(const function_base* f) |
| { |
| return f->empty(); |
| } |
| |
| #if NDNBOOST_WORKAROUND(NDNBOOST_MSVC, <= 1310) |
| inline bool has_empty_target(const void*) |
| { |
| return false; |
| } |
| #else |
| inline bool has_empty_target(...) |
| { |
| return false; |
| } |
| #endif |
| } // end namespace function |
| } // end namespace detail |
| } // end namespace ndnboost |
| |
| #undef NDNBOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL |
| #undef NDNBOOST_FUNCTION_COMPARE_TYPE_ID |
| |
| #if defined(NDNBOOST_MSVC) |
| # pragma warning( pop ) |
| #endif |
| |
| #endif // NDNBOOST_FUNCTION_BASE_HEADER |