// Boost.Function library
-// Copyright Douglas Gregor 2001-2006. Use, modification and
-// distribution is subject to the Boost Software License, Version
-// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// Copyright Douglas Gregor 2001-2006
+// Copyright Emil Dotchevski 2007
+// Use, modification and distribution is subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// For more information, see http://www.boost.org
#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/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==.
# 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)
+#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
#endif
-#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
-namespace boost {
-
-#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
-// The library shipping with MIPSpro 7.3.1.3m has a broken allocator<void>
-class function_base;
-
-template<typename Signature,
- typename Allocator = std::allocator<function_base> >
-class function;
-#else
-template<typename Signature, typename Allocator = std::allocator<void> >
-class function;
-#endif
-
-template<typename Signature, typename Allocator>
-inline void swap(function<Signature, Allocator>& f1,
- function<Signature, Allocator>& f2)
-{
- f1.swap(f2);
-}
-
-} // end namespace boost
-#endif // have partial specialization
-
namespace boost {
namespace detail {
namespace function {
union function_buffer
{
// For pointers to function objects
- void* obj_ptr;
+ mutable void* obj_ptr;
// For pointers to std::type_info objects
- // (get_functor_type_tag, check_functor_type_tag).
- const void* const_obj_ptr;
+ struct type_t {
+ // (get_functor_type_tag, check_functor_type_tag).
+ const BOOST_FUNCTION_STD_NS::type_info* type;
+
+ // Whether the type is const-qualified.
+ bool const_qualified;
+ // Whether the type is volatile-qualified.
+ bool volatile_qualified;
+ } type;
// For function pointers of all kinds
mutable void (*func_ptr)();
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 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
struct reference_manager
{
static inline void
- get(const function_buffer& in_buffer, function_buffer& out_buffer,
- functor_manager_operation_type op)
+ manage(const function_buffer& in_buffer, function_buffer& out_buffer,
+ functor_manager_operation_type op)
{
switch (op) {
case clone_functor_tag:
- out_buffer.obj_ptr = in_buffer.obj_ptr;
+ out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
+ return;
+
+ case move_functor_tag:
+ out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
+ in_buffer.obj_ref.obj_ptr = 0;
return;
case destroy_functor_tag:
- out_buffer.obj_ptr = 0;
+ out_buffer.obj_ref.obj_ptr = 0;
return;
case check_functor_type_tag:
{
- // DPG TBD: Since we're only storing a pointer, it's
- // possible that the user could ask for a base class or
- // derived class. Is that okay?
- const std::type_info& check_type =
- *static_cast<const std::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;
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
+
+ // Check whether we have the same type. We can add
+ // cv-qualifiers, but we can't take them away.
+ if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
+ && (!in_buffer.obj_ref.is_const_qualified
+ || out_buffer.type.const_qualified)
+ && (!in_buffer.obj_ref.is_volatile_qualified
+ || out_buffer.type.volatile_qualified))
+ out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
else
out_buffer.obj_ptr = 0;
}
return;
case get_functor_type_tag:
- out_buffer.const_obj_ptr = &typeid(F);
+ out_buffer.type.type = &typeid(F);
+ out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
+ out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
return;
}
}
% 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, typename Allocator>
- struct functor_manager
+ template<typename Functor>
+ struct functor_manager_common
{
- private:
typedef Functor functor_type;
- // For function pointers, the manager is trivial
+ // Function pointers
static inline void
- manager(const function_buffer& in_buffer, function_buffer& out_buffer,
- functor_manager_operation_type op, function_ptr_tag)
+ 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)
+ 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 /* op == check_functor_type_tag */ {
- const std::type_info& check_type =
- *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+ else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.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
- manager(const function_buffer& in_buffer, function_buffer& out_buffer,
- functor_manager_operation_type op, mpl::true_)
+ manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
+ functor_manager_operation_type op)
{
- if (op == clone_functor_tag) {
+ 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 /* op == check_functor_type_tag */ {
- const std::type_info& check_type =
- *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+ } else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = &in_buffer.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_)
{
-#ifndef BOOST_NO_STD_ALLOCATOR
- typedef typename Allocator::template rebind<functor_type>::other
- allocator_type;
- typedef typename allocator_type::pointer pointer_type;
-#else
- typedef functor_type* pointer_type;
-#endif // BOOST_NO_STD_ALLOCATOR
-
-# ifndef BOOST_NO_STD_ALLOCATOR
- allocator_type allocator;
-# endif // BOOST_NO_STD_ALLOCATOR
-
if (op == clone_functor_tag) {
+ // Clone the functor
// GCC 2.95.3 gets the CV qualifiers wrong here, so we
// can't do the static_cast that we should do.
const functor_type* f =
(const functor_type*)(in_buffer.obj_ptr);
-
- // Clone the functor
-# ifndef BOOST_NO_STD_ALLOCATOR
- pointer_type copy = allocator.allocate(1);
- allocator.construct(copy, *f);
-
- // Get back to the original pointer type
- functor_type* new_f = static_cast<functor_type*>(copy);
-# else
functor_type* new_f = new functor_type(*f);
-# endif // BOOST_NO_STD_ALLOCATOR
out_buffer.obj_ptr = new_f;
+ } else if (op == move_functor_tag) {
+ out_buffer.obj_ptr = in_buffer.obj_ptr;
+ in_buffer.obj_ptr = 0;
} else if (op == destroy_functor_tag) {
/* Cast from the void pointer to the functor pointer type */
functor_type* f =
static_cast<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;
+ }
+ }
-# ifndef BOOST_NO_STD_ALLOCATOR
- /* Cast from the functor pointer type to the allocator's pointer
- type */
- pointer_type victim = static_cast<pointer_type>(f);
+ // 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)>());
+ }
- // Destroy and deallocate the functor
- allocator.destroy(victim);
- allocator.deallocate(victim, 1);
-# else
- delete f;
-# endif // BOOST_NO_STD_ALLOCATOR
+ // 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 /* op == check_functor_type_tag */ {
- const std::type_info& check_type =
- *static_cast<const std::type_info*>(out_buffer.const_obj_ptr);
+ } else if (op == check_functor_type_tag) {
+ const BOOST_FUNCTION_STD_NS::type_info& check_type
+ = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else
out_buffer.obj_ptr = 0;
+ } else /* op == get_functor_type_tag */ {
+ out_buffer.type.type = &typeid(Functor);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
}
}
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);
+ out_buffer.type.type = &typeid(functor_type);
+ out_buffer.type.const_qualified = false;
+ out_buffer.type.volatile_qualified = false;
return;
default:
*/
struct vtable_base
{
- vtable_base() : manager(0) { }
void (*manager)(const function_buffer& in_buffer,
function_buffer& out_buffer,
functor_manager_operation_type op);
/** Retrieve the type of the stored function object, or typeid(void)
if this is empty. */
- const std::type_info& target_type() const
+ 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 std::type_info*>(type.const_obj_ptr);
+ get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
+ return *type.type.type;
}
template<typename Functor>
if (!vtable) return 0;
detail::function::function_buffer type_result;
- type_result.const_obj_ptr = &typeid(Functor);
- vtable->manager(functor, 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);
}
if (!vtable) return 0;
detail::function::function_buffer type_result;
- type_result.const_obj_ptr = &typeid(Functor);
- vtable->manager(functor, 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.
#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;
};
#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