forked from boostorg/function
https://svn.boost.org/svn/boost/trunk ................ r43810 | eric_niebler | 2008-03-23 14:51:40 -0700 (Sun, 23 Mar 2008) | 1 line mark up new foreach tests ................ r43823 | fmhess | 2008-03-24 08:07:00 -0700 (Mon, 24 Mar 2008) | 3 lines Fixed compile error with new enable_shared_from_this code, reported by Tim Blechmann ................ r43825 | ramey | 2008-03-24 08:46:09 -0700 (Mon, 24 Mar 2008) | 1 line removed EXIT_SUCCESS ................ r43826 | ramey | 2008-03-24 08:46:43 -0700 (Mon, 24 Mar 2008) | 1 line fixed minor typo ................ r43829 | pdimov | 2008-03-24 09:00:28 -0700 (Mon, 24 Mar 2008) | 1 line New enable_shared_from_this tests, fix. ................ r43838 | danieljames | 2008-03-24 10:03:15 -0700 (Mon, 24 Mar 2008) | 12 lines Merge new changes to unordered & hash. - Unordered tests can run lightweight test or Boost.Test (at least theoretically). - Workaround Open BSD's incorrect numeric_limits. - Move the hash extensions in their own file. - Various small improvements to the unordered docs. - Fix some unordered examples. Merged revisions 43117-43837 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r43845 | dave | 2008-03-24 11:27:22 -0700 (Mon, 24 Mar 2008) | 1 line Work around vc9 bugs ................ r43847 | anthonyw | 2008-03-24 14:44:36 -0700 (Mon, 24 Mar 2008) | 1 line removed forward declaration for undefined type exclusive_lock ................ r43852 | hkaiser | 2008-03-25 06:40:53 -0700 (Tue, 25 Mar 2008) | 1 line Wave: Removed an assertion causing compilation problems on certain platforms. ................ r43856 | pdimov | 2008-03-25 08:46:40 -0700 (Tue, 25 Mar 2008) | 1 line _internal_accept_owner now checks if _owned isn't already true. ................ r43861 | dave | 2008-03-25 13:47:38 -0700 (Tue, 25 Mar 2008) | 2 lines Work around intel-10.0-win compiler bug ................ r43864 | dave | 2008-03-25 15:28:59 -0700 (Tue, 25 Mar 2008) | 2 lines Account for intel 10.x compiler bug ................ r43865 | dave | 2008-03-25 16:06:50 -0700 (Tue, 25 Mar 2008) | 2 lines Work around intel-win-10.0 preprocessor bug ................ r43866 | danieljames | 2008-03-26 02:10:29 -0700 (Wed, 26 Mar 2008) | 3 lines Boost.Thread's documentation no longer has a build section - so just link to the library's documentation like we do for other libraries. ................ r43867 | bemandawes | 2008-03-26 08:59:52 -0700 (Wed, 26 Mar 2008) | 1 line Initial commit ................ r43873 | pdimov | 2008-03-26 11:34:29 -0700 (Wed, 26 Mar 2008) | 1 line Added "Throws: nothing" to get_deleter. ................ r43875 | bemandawes | 2008-03-26 14:26:55 -0700 (Wed, 26 Mar 2008) | 1 line Initial commit ................ r43876 | danieljames | 2008-03-26 22:49:45 -0700 (Wed, 26 Mar 2008) | 2 lines Update the thread links in the generated getting started documentation. ................ r43879 | chris_kohlhoff | 2008-03-27 07:18:07 -0700 (Thu, 27 Mar 2008) | 3 lines Fix double-free error that occurs when an exception is thrown from a handler that has been dispatched (i.e. not posted) through a strand. ................ r43880 | ramey | 2008-03-27 08:53:37 -0700 (Thu, 27 Mar 2008) | 1 line removed suppression of builds for certain platforms with shared libraries ................ r43882 | ramey | 2008-03-27 10:11:23 -0700 (Thu, 27 Mar 2008) | 1 line tweaks to sneak past PGI compiler error message ................ r43883 | ramey | 2008-03-27 10:12:22 -0700 (Thu, 27 Mar 2008) | 1 line added test to check warnings on type trait ................ r43884 | dgregor | 2008-03-27 12:44:37 -0700 (Thu, 27 Mar 2008) | 1 line Change Boost.Function allocator behavior, from Emil Dotchevski ................ r43887 | pdimov | 2008-03-27 15:13:55 -0700 (Thu, 27 Mar 2008) | 1 line Silence unused parameter warning. ................ r43888 | pdimov | 2008-03-27 15:20:11 -0700 (Thu, 27 Mar 2008) | 1 line detail::yield(k) added. ................ r43895 | danieljames | 2008-03-27 16:38:01 -0700 (Thu, 27 Mar 2008) | 25 lines Merged revisions 43838-43894 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ........ r43840 | danieljames | 2008-03-24 17:25:07 +0000 (Mon, 24 Mar 2008) | 1 line Fix a g++ warning. ........ r43844 | danieljames | 2008-03-24 17:56:28 +0000 (Mon, 24 Mar 2008) | 1 line It's a new-ish year. ........ r43885 | danieljames | 2008-03-27 20:36:10 +0000 (Thu, 27 Mar 2008) | 1 line The release script doesn't need to copy images and css - because that's now done in the jamfiles. Also tweak the shell script a tad bit. ........ r43890 | danieljames | 2008-03-27 23:01:40 +0000 (Thu, 27 Mar 2008) | 1 line Starting to add a docbook bibliography. ........ r43894 | danieljames | 2008-03-27 23:24:18 +0000 (Thu, 27 Mar 2008) | 1 line Redeclare 'data' in iterator_base to help compilers which have trouble with accessing the nested typedef. ........ ................ r43900 | noel_belcourt | 2008-03-27 19:10:04 -0700 (Thu, 27 Mar 2008) | 4 lines Fix address-model support for 32/64 bit code generation. Replaced -mcmodel with -m32 / -m64. ................ r43901 | bemandawes | 2008-03-27 19:11:13 -0700 (Thu, 27 Mar 2008) | 1 line Remove per email from Dave ................ r43906 | eric_niebler | 2008-03-27 23:10:55 -0700 (Thu, 27 Mar 2008) | 1 line proto support for BOOST_PROTO_MAX_FUNCTION_CALL_ARITY ................ [SVN r43910]
837 lines
28 KiB
C++
837 lines
28 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/type_traits/is_integral.hpp>
|
|
#include <boost/type_traits/composite_traits.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>
|
|
|
|
#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_EXCEPTION_STD_NAMESPACE
|
|
// Embedded VC++ does not have type_info in namespace std
|
|
# define BOOST_FUNCTION_STD_NS
|
|
#else
|
|
# define BOOST_FUNCTION_STD_NS std
|
|
#endif
|
|
|
|
// Borrowed from Boost.Python library: determines the cases where we
|
|
// need to use std::type_info::name to compare instead of operator==.
|
|
# if (defined(__GNUC__) && __GNUC__ >= 3) \
|
|
|| 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 defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
|
|
// Work around a compiler bug.
|
|
// boost::python::objects::function has to be seen by the compiler before the
|
|
// boost::function class template.
|
|
namespace boost { namespace python { namespace objects {
|
|
class function;
|
|
}}}
|
|
#endif
|
|
|
|
#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
|
|
|| defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
|
|
|| !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
|
|
# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
|
|
#endif
|
|
|
|
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
|
# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
|
|
typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
|
|
(::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
|
|
|
|
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
|
namespace boost {
|
|
|
|
template<typename Signature>
|
|
class function;
|
|
|
|
template<typename Signature>
|
|
inline void swap(function<Signature>& f1,
|
|
function<Signature>& f2)
|
|
{
|
|
f1.swap(f2);
|
|
}
|
|
|
|
} // end namespace boost
|
|
#endif // have partial specialization
|
|
|
|
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
|
|
void* obj_ptr;
|
|
|
|
// For pointers to std::type_info objects
|
|
// (get_functor_type_tag, check_functor_type_tag).
|
|
const void* const_obj_ptr;
|
|
|
|
// 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;
|
|
|
|
// 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,
|
|
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
|
|
get(const function_buffer& in_buffer, function_buffer& out_buffer,
|
|
functor_manager_operation_type op)
|
|
{
|
|
switch (op) {
|
|
case clone_functor_tag:
|
|
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
|
return;
|
|
|
|
case destroy_functor_tag:
|
|
out_buffer.obj_ptr = 0;
|
|
return;
|
|
|
|
case check_functor_type_tag:
|
|
{
|
|
// DPG TBD: Since we're only storing a pointer, it's
|
|
// possible that the user could ask for a base class or
|
|
// derived class. Is that okay?
|
|
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
|
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
|
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
|
|
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
|
else
|
|
out_buffer.obj_ptr = 0;
|
|
}
|
|
return;
|
|
|
|
case get_functor_type_tag:
|
|
out_buffer.const_obj_ptr = &typeid(F);
|
|
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)
|
|
{
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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 == destroy_functor_tag)
|
|
out_buffer.func_ptr = 0;
|
|
else /* op == check_functor_type_tag */ {
|
|
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
|
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
|
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
|
out_buffer.obj_ptr = &in_buffer.func_ptr;
|
|
else
|
|
out_buffer.obj_ptr = 0;
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
const functor_type* in_functor =
|
|
reinterpret_cast<const functor_type*>(&in_buffer.data);
|
|
new ((void*)&out_buffer.data) functor_type(*in_functor);
|
|
} else if (op == destroy_functor_tag) {
|
|
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
|
|
reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
|
|
} else /* op == check_functor_type_tag */ {
|
|
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
|
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
|
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
|
out_buffer.obj_ptr = &in_buffer.data;
|
|
else
|
|
out_buffer.obj_ptr = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
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 == 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 /* op == check_functor_type_tag */ {
|
|
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
|
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
|
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
|
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
|
else
|
|
out_buffer.obj_ptr = 0;
|
|
}
|
|
}
|
|
|
|
// For function objects, we determine whether the function
|
|
// object can use the small-object optimization buffer or
|
|
// whether we need to allocate it on the heap.
|
|
static inline void
|
|
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
|
|
functor_manager_operation_type op, function_obj_tag)
|
|
{
|
|
manager(in_buffer, out_buffer, op,
|
|
mpl::bool_<(function_allows_small_object_optimization<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.const_obj_ptr = &typeid(functor_type);
|
|
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<wrapper_allocator_type 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 == 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<wrapper_allocator_type const &>(*victim));
|
|
wrapper_allocator.destroy(victim);
|
|
wrapper_allocator.deallocate(victim,1);
|
|
out_buffer.obj_ptr = 0;
|
|
} else /* op == check_functor_type_tag */ {
|
|
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
|
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
|
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
|
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
|
else
|
|
out_buffer.obj_ptr = 0;
|
|
}
|
|
}
|
|
|
|
// For function objects, we determine whether the function
|
|
// object can use the small-object optimization buffer or
|
|
// whether we need to allocate it on the heap.
|
|
static inline void
|
|
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
|
|
functor_manager_operation_type op, function_obj_tag)
|
|
{
|
|
manager(in_buffer, out_buffer, op,
|
|
mpl::bool_<(function_allows_small_object_optimization<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.const_obj_ptr = &typeid(functor_type);
|
|
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
|
|
{
|
|
vtable_base() : manager(0) { }
|
|
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;
|
|
vtable->manager(functor, type, detail::function::get_functor_type_tag);
|
|
return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
|
|
}
|
|
|
|
template<typename Functor>
|
|
Functor* target()
|
|
{
|
|
if (!vtable) return 0;
|
|
|
|
detail::function::function_buffer type_result;
|
|
type_result.const_obj_ptr = &typeid(Functor);
|
|
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.const_obj_ptr = &typeid(Functor);
|
|
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* 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
|
|
|
|
#endif // BOOST_FUNCTION_BASE_HEADER
|