forked from boostorg/function
Merged revisions 49571,50064,51743,51745,53722,54616-54619 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r49571 | noel_belcourt | 2008-11-03 18:37:49 +0000 (Mon, 03 Nov 2008) | 9 lines Both Sun and Pgi on Linux correctly put typeinfo into the std namespace, but function_base keys off the BOOST_NO_EXCEPTION_STD_NAMESPACE macro instead of the BOOST_NO_STD_TYPEINFO macro. The attached patch changes function_base to use the typeinfo macro. Because eVC 4.2 doesn't put typeinfo into the std namespace, I need to define BOOST_NO_STD_TYPEINFO only for this eVC version. ........ r50064 | johnmaddock | 2008-12-02 10:10:46 +0000 (Tue, 02 Dec 2008) | 1 line Fix -Wundef warning and suspect usage of BOOST_STRICT_CONFIG. ........ r51743 | dgregor | 2009-03-13 05:23:53 +0000 (Fri, 13 Mar 2009) | 11 lines Implement an optimization that David Abrahams and myself came up with, where Boost.Function uses a bit in the vtable pointer to indicate when the target function object has a trivial copy constructor, trivial destructor, and fits within the small object buffer. In this case, we just copy the bits of the function object rather than performing an indirect call to the manager. This results in a 60% speedup on a micro-benchmark that copies and calls such function objects repeatedly. ........ r51745 | dgregor | 2009-03-13 05:49:02 +0000 (Fri, 13 Mar 2009) | 7 lines Make Boost.Function compile under BOOST_NO_EXCEPTIONS. Fixes #2499 Fixes #2494 Fixes #2469 Fixes #2466 ........ r53722 | vladimir_prus | 2009-06-07 16:44:50 +0100 (Sun, 07 Jun 2009) | 4 lines Make Boost.Function compile with disabled exceptions. Closes #2900. Patch from Gabi Davar. ........ r54616 | danieljames | 2009-07-03 23:20:26 +0100 (Fri, 03 Jul 2009) | 3 lines When copying boost::ref, copy even when the referenced function is empty. Fixes #2642 Patch by Steven Watanabe ........ r54617 | danieljames | 2009-07-03 23:20:52 +0100 (Fri, 03 Jul 2009) | 6 lines Add 'and later versions' to support info for GCC and Visual C++. Fixes #2847. I didn't explicitly specify the versions since no one's updating this list and it's highly unlikely that a future version will break this. The same could probably be done for the other compilers but I don't know them very well so I'm leaving them alone. ........ r54618 | danieljames | 2009-07-03 23:21:40 +0100 (Fri, 03 Jul 2009) | 4 lines Fix Boost.Function unit tests for C++0x. Fixes #3012 Based on a patch from Richard Webb. Changed a bit so that it also works for the Visual C++ 10 beta. ........ r54619 | danieljames | 2009-07-03 23:22:03 +0100 (Fri, 03 Jul 2009) | 3 lines Work around Visual C++ copy constructor bug. Fixes #2929. Based on the patch by Steven Watanabe. ........ [SVN r54824]
903 lines
31 KiB
C++
903 lines
31 KiB
C++
// 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 BOOST_FUNCTION_BASE_HEADER
|
|
#define BOOST_FUNCTION_BASE_HEADER
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <typeinfo>
|
|
#include <boost/config.hpp>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/integer.hpp>
|
|
#include <boost/type_traits/has_trivial_copy.hpp>
|
|
#include <boost/type_traits/has_trivial_destructor.hpp>
|
|
#include <boost/type_traits/is_const.hpp>
|
|
#include <boost/type_traits/is_integral.hpp>
|
|
#include <boost/type_traits/is_volatile.hpp>
|
|
#include <boost/type_traits/composite_traits.hpp>
|
|
#include <boost/type_traits/ice.hpp>
|
|
#include <boost/ref.hpp>
|
|
#include <boost/mpl/if.hpp>
|
|
#include <boost/detail/workaround.hpp>
|
|
#include <boost/type_traits/alignment_of.hpp>
|
|
#ifndef BOOST_NO_SFINAE
|
|
# include "boost/utility/enable_if.hpp"
|
|
#else
|
|
# include "boost/mpl/bool.hpp"
|
|
#endif
|
|
#include <boost/function_equal.hpp>
|
|
#include <boost/function/function_fwd.hpp>
|
|
|
|
#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.
|
|
#ifdef BOOST_NO_STD_TYPEINFO
|
|
// Embedded VC++ does not have type_info in namespace std
|
|
# define BOOST_FUNCTION_STD_NS
|
|
#else
|
|
# define BOOST_FUNCTION_STD_NS std
|
|
#endif
|
|
|
|
// Borrowed from Boost.Python library: determines the cases where we
|
|
// need to use std::type_info::name to compare instead of operator==.
|
|
# if (defined(__GNUC__) && __GNUC__ >= 3) \
|
|
|| defined(_AIX) \
|
|
|| ( defined(__sgi) && defined(__host_mips))
|
|
# include <cstring>
|
|
# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
|
|
(std::strcmp((X).name(),(Y).name()) == 0)
|
|
# else
|
|
# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
|
|
#endif
|
|
|
|
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
|
|
# define BOOST_FUNCTION_TARGET_FIX(x) x
|
|
#else
|
|
# define BOOST_FUNCTION_TARGET_FIX(x)
|
|
#endif // not MSVC
|
|
|
|
#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<Functor>::value)>::value), \
|
|
Type>::type
|
|
#else
|
|
// BCC doesn't recognize this depends on a template argument and complains
|
|
// about the use of 'typename'
|
|
# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
|
|
::boost::enable_if_c<(::boost::type_traits::ice_not< \
|
|
(::boost::is_integral<Functor>::value)>::value), \
|
|
Type>::type
|
|
#endif
|
|
|
|
namespace boost {
|
|
namespace detail {
|
|
namespace function {
|
|
class X;
|
|
|
|
/**
|
|
* A buffer used to store small function objects in
|
|
* boost::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 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)();
|
|
|
|
// 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.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_ref.obj_ptr = 0;
|
|
return;
|
|
|
|
case check_functor_type_tag:
|
|
{
|
|
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.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;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Determine if boost::function can use the small-object
|
|
* optimization with the function object type F.
|
|
*/
|
|
template<typename F>
|
|
struct function_allows_small_object_optimization
|
|
{
|
|
BOOST_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 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<const functor_type*>(&in_buffer.data);
|
|
new ((void*)&out_buffer.data) functor_type(*in_functor);
|
|
|
|
if (op == move_functor_tag) {
|
|
reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
|
|
}
|
|
} else if (op == destroy_functor_tag) {
|
|
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
|
|
reinterpret_cast<functor_type*>(&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<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.
|
|
const functor_type* f =
|
|
(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 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<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 = &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 =
|
|
(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 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<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 = &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 BOOST_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 // BOOST_NO_SFINAE
|
|
|
|
/**
|
|
* Stores the "manager" portion of the vtable for a
|
|
* boost::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 typeid(void)
|
|
if this is empty. */
|
|
const BOOST_FUNCTION_STD_NS::type_info& target_type() const
|
|
{
|
|
if (!vtable) return 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 = &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(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_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 = &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 (const Functor*)(type_result.obj_ptr);
|
|
}
|
|
|
|
template<typename F>
|
|
bool contains(const F& f) const
|
|
{
|
|
#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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) & ~(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 boost::function
|
|
* object is invoked
|
|
*/
|
|
class bad_function_call : public std::runtime_error
|
|
{
|
|
public:
|
|
bad_function_call() : std::runtime_error("call to empty boost::function") {}
|
|
};
|
|
|
|
#ifndef BOOST_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 BOOST_NO_SFINAE
|
|
// Comparisons between boost::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 boost::function objects and arbitrary function
|
|
// objects. GCC 3.3 and before has an obnoxious bug that prevents this
|
|
// from working.
|
|
template<typename Functor>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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>
|
|
BOOST_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 BOOST_WORKAROUND(BOOST_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 boost
|
|
|
|
#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
|