diff --git a/doc/history.xml b/doc/history.xml
index 5cbdb7e..f30db79 100644
--- a/doc/history.xml
+++ b/doc/history.xml
@@ -5,6 +5,13 @@
History & Compatibility Notes
+
+ Version 1.34.0:
+
+ Boost.Function now implements a small buffer optimization, which can drastically improve the performance when copying or construction Boost.Function objects storing small function objects. For instance, bind(&X:foo, &x, _1, _2)
requires no heap allocation when placed into a Boost.Function object. Note that some exception-safety guarantees have changed: assignment provides the basic exception guarantee and swap()
may throw.
+
+
+
Version 1.30.0:
All features deprecated in version 1.29.0 have
diff --git a/doc/reference.xml b/doc/reference.xml
index fd66fdb..8d69d7a 100644
--- a/doc/reference.xml
+++ b/doc/reference.xml
@@ -118,6 +118,12 @@
true
if this->target<Functor>()
is non-NULL and function_equal(*(this->target<Functor>()), f)
+
+
+ const std::type_info&
+ typeid
of the target function object, or typeid(void)
if this->empty()
.
+ Will not throw.
+
@@ -182,7 +188,7 @@
- this->empty()
+ this->empty()
Will not throw.
@@ -201,11 +207,10 @@
F
F is a function object Callable from this
.
*this
targets a copy of f
if f
is nonempty, or this->empty()
if f
is empty.
- Will not throw when f
is a stateless function object.
- If !this->empty()
, destroys the target of this.
+ If !this->empty()
, destroys the target of this.
@@ -213,8 +218,7 @@
const functionN&
- *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
.
- Will not throw when the target of f
is a stateless function object or a reference to the function object.
+ If copy construction does not throw, *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
. If copy construction does throw, this->empty()
.
@@ -222,13 +226,11 @@
void
const functionN&
Interchanges the targets of *this
and f
.
- Will not throw.
void
this->empty()
- Will not throw.
@@ -286,6 +288,13 @@
true
if this->target<Functor>()
is non-NULL and function_equal(*(this->target<Functor>()), f)
+
+
+ const std::type_info&
+ typeid
of the target function object, or typeid(void)
if this->empty()
.
+ Will not throw.
+
+
@@ -314,7 +323,6 @@
functionN<T1, T2, ..., TN, Allocator>&
functionN<T1, T2, ..., TN, Allocator>&
f1.swap(f2)
- Will not throw.
@@ -589,7 +597,7 @@
- this->empty()
+ this->empty()
Will not throw.
@@ -616,28 +624,26 @@
F
F is a function object Callable from this
.
*this
targets a copy of f
if f
is nonempty, or this->empty()
if f
is empty.
- Will not throw when f
is a stateless function object.
- If !this->empty()
, destroys the target of this
.
+ If !this->empty()
, destroys the target of this
.
- const functionN&
+ const function&
- *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
- Will not throw when the target of f
is a stateless function object or a reference to the function object.
+ If copy construction does not throw, *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
. If copy construction does throw, this->empty()
.
const function&
- *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
- Will not throw when the target of f
is a stateless function object or a reference to the function object.
+ If copy construction of the target of f
does not throw, *this
targets a copy of f
's target, if it has one, or is empty if f.empty()
.
+ Will not throw when the target of f
is a stateless function object or a reference to the function object. If copy construction does throw, this->empty()
.
@@ -645,7 +651,6 @@
void
const function&
Interchanges the targets of *this
and f
.
- Will not throw.
@@ -708,6 +713,12 @@
true
if this->target<Functor>()
is non-NULL and function_equal(*(this->target<Functor>()), f)
+
+
+ const std::type_info&
+ typeid
of the target function object, or typeid(void)
if this->empty()
.
+ Will not throw.
+
@@ -733,7 +744,6 @@
function<Signature, Allocator>&
function<Signature, Allocator>&
f1.swap(f2)
- Will not throw.
diff --git a/include/boost/function/function_base.hpp b/include/boost/function/function_base.hpp
index 9f5e20f..c16bfaa 100644
--- a/include/boost/function/function_base.hpp
+++ b/include/boost/function/function_base.hpp
@@ -1,6 +1,6 @@
// Boost.Function library
-// Copyright Douglas Gregor 2001-2004. Use, modification and
+// 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
// http://www.boost.org/LICENSE_1_0.txt)
@@ -19,10 +19,10 @@
#include
#include
#include
-#include
#include
-#include
+#include
#include
+#include
#ifndef BOOST_NO_SFINAE
# include "boost/utility/enable_if.hpp"
#else
@@ -105,42 +105,36 @@ inline void swap(function& f1,
namespace boost {
namespace detail {
namespace function {
+ class X;
+
/**
- * A union of a function pointer and a void pointer. This is necessary
- * because 5.2.10/6 allows reinterpret_cast<> to safely cast between
- * function pointer types and 5.2.9/10 allows static_cast<> to safely
- * cast between a void pointer and an object pointer. But it is not legal
- * to cast between a function pointer and a void* (in either direction),
- * so function requires a union of the two. */
- union any_pointer
+ * 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;
- void (*func_ptr)();
- char data[1];
+
+ // 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;
};
- inline any_pointer make_any_pointer(void* o)
- {
- any_pointer p;
- p.obj_ptr = o;
- return p;
- }
-
- inline any_pointer make_any_pointer(const void* o)
- {
- any_pointer p;
- p.const_obj_ptr = o;
- return p;
- }
-
- inline any_pointer make_any_pointer(void (*f)())
- {
- any_pointer p;
- p.func_ptr = f;
- return p;
- }
-
/**
* The unusable class is a placeholder for unused function arguments
* It is also completely unusable except that it constructable from
@@ -169,7 +163,8 @@ namespace boost {
enum functor_manager_operation_type {
clone_functor_tag,
destroy_functor_tag,
- check_functor_type_tag
+ check_functor_type_tag,
+ get_functor_type_tag
};
// Tags used to decide between different types of functions
@@ -177,57 +172,79 @@ namespace boost {
struct function_obj_tag {};
struct member_ptr_tag {};
struct function_obj_ref_tag {};
- struct stateless_function_obj_tag {};
template
class get_function_tag
{
- typedef typename ct_if<(is_pointer::value),
- function_ptr_tag,
- function_obj_tag>::type ptr_or_obj_tag;
+ typedef typename mpl::if_c<(is_pointer::value),
+ function_ptr_tag,
+ function_obj_tag>::type ptr_or_obj_tag;
- typedef typename ct_if<(is_member_pointer::value),
- member_ptr_tag,
- ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
+ typedef typename mpl::if_c<(is_member_pointer::value),
+ member_ptr_tag,
+ ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
- typedef typename ct_if<(is_reference_wrapper::value),
- function_obj_ref_tag,
- ptr_or_obj_or_mem_tag>::type or_ref_tag;
+ typedef typename mpl::if_c<(is_reference_wrapper::value),
+ function_obj_ref_tag,
+ ptr_or_obj_or_mem_tag>::type or_ref_tag;
public:
- typedef typename ct_if<(is_stateless::value),
- stateless_function_obj_tag,
- or_ref_tag>::type type;
+ 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
- struct trivial_manager
+ struct reference_manager
{
- static inline any_pointer
- get(any_pointer f, functor_manager_operation_type op)
+ static inline void
+ get(const function_buffer& in_buffer, function_buffer& out_buffer,
+ functor_manager_operation_type op)
{
switch (op) {
- case clone_functor_tag: return f;
+ case clone_functor_tag:
+ out_buffer.obj_ptr = in_buffer.obj_ptr;
+ return;
case destroy_functor_tag:
- return make_any_pointer(reinterpret_cast(0));
+ out_buffer.obj_ptr = 0;
+ return;
case check_functor_type_tag:
{
- std::type_info* t = static_cast(f.obj_ptr);
- return BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(F), *t)?
- f
- : make_any_pointer(reinterpret_cast(0));
+ // 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(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;
- // Clears up a warning with GCC 3.2.3
- return make_any_pointer(reinterpret_cast(0));
+ 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
+ struct function_allows_small_object_optimization
+ {
+ BOOST_STATIC_CONSTANT
+ (bool,
+ value = ((sizeof(F) <= sizeof(function_buffer) &&
+ (alignment_of::value
+ % alignment_of::value == 0))));
+ };
+
/**
* The functor_manager class contains a static function "manage" which
* can clone or destroy the given function/function object pointer.
@@ -239,30 +256,58 @@ namespace boost {
typedef Functor functor_type;
// For function pointers, the manager is trivial
- static inline any_pointer
- manager(any_pointer function_ptr,
- functor_manager_operation_type op,
- function_ptr_tag)
+ static inline void
+ manager(const function_buffer& in_buffer, function_buffer& out_buffer,
+ functor_manager_operation_type op, function_ptr_tag)
{
if (op == clone_functor_tag)
- return function_ptr;
- else
- return make_any_pointer(static_cast(0));
+ 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 std::type_info& check_type =
+ *static_cast(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;
+ }
}
- // For function object pointers, we clone the pointer to each
- // function has its own version.
- static inline any_pointer
- manager(any_pointer function_obj_ptr,
- functor_manager_operation_type op,
- function_obj_tag)
+ // 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_)
+ {
+ if (op == clone_functor_tag) {
+ const functor_type* in_functor =
+ reinterpret_cast(&in_buffer.data);
+ new ((void*)&out_buffer.data) functor_type(*in_functor);
+ } else if (op == destroy_functor_tag) {
+ functor_type* out_functor =
+ reinterpret_cast(&out_buffer.data);
+ out_functor->~functor_type();
+ } else /* op == check_functor_type_tag */ {
+ const std::type_info& check_type =
+ *static_cast(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;
+ }
+ }
+
+ // 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::other
- allocator_type;
- typedef typename allocator_type::pointer pointer_type;
+ typedef typename Allocator::template rebind::other
+ allocator_type;
+ typedef typename allocator_type::pointer pointer_type;
#else
- typedef functor_type* pointer_type;
+ typedef functor_type* pointer_type;
#endif // BOOST_NO_STD_ALLOCATOR
# ifndef BOOST_NO_STD_ALLOCATOR
@@ -270,8 +315,8 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR
if (op == clone_functor_tag) {
- functor_type* f =
- static_cast(function_obj_ptr.obj_ptr);
+ const functor_type* f =
+ static_cast(in_buffer.obj_ptr);
// Clone the functor
# ifndef BOOST_NO_STD_ALLOCATOR
@@ -283,12 +328,11 @@ namespace boost {
# else
functor_type* new_f = new functor_type(*f);
# endif // BOOST_NO_STD_ALLOCATOR
- return make_any_pointer(static_cast(new_f));
- }
- else {
+ 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 =
- reinterpret_cast(function_obj_ptr.obj_ptr);
+ static_cast(out_buffer.obj_ptr);
# ifndef BOOST_NO_STD_ALLOCATOR
/* Cast from the functor pointer type to the allocator's pointer
@@ -301,26 +345,43 @@ namespace boost {
# else
delete f;
# endif // BOOST_NO_STD_ALLOCATOR
-
- return make_any_pointer(static_cast(0));
+ out_buffer.obj_ptr = 0;
+ } else /* op == check_functor_type_tag */ {
+ const std::type_info& check_type =
+ *static_cast(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::value)>());
+ }
+
public:
/* Dispatch to an appropriate manager based on whether we have a
function pointer or a function object pointer. */
- static any_pointer
- manage(any_pointer functor_ptr, functor_manager_operation_type op)
+ static inline void
+ manage(const function_buffer& in_buffer, function_buffer& out_buffer,
+ functor_manager_operation_type op)
{
- if (op == check_functor_type_tag) {
- std::type_info* type =
- static_cast(functor_ptr.obj_ptr);
- return (BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(Functor), *type)?
- functor_ptr
- : make_any_pointer(reinterpret_cast(0)));
- }
- else {
- typedef typename get_function_tag::type tag_type;
- return manager(functor_ptr, op, tag_type());
+ typedef typename get_function_tag::type tag_type;
+ switch (op) {
+ case get_functor_type_tag:
+ out_buffer.const_obj_ptr = &typeid(functor_type);
+ return;
+
+ default:
+ return manager(in_buffer, out_buffer, op, tag_type());
}
}
};
@@ -394,7 +455,9 @@ namespace boost {
struct vtable_base
{
vtable_base() : manager(0) { }
- any_pointer (*manager)(any_pointer, functor_manager_operation_type);
+ void (*manager)(const function_buffer& in_buffer,
+ function_buffer& out_buffer,
+ functor_manager_operation_type op);
};
} // end namespace function
} // end namespace detail
@@ -408,27 +471,32 @@ namespace boost {
class function_base
{
public:
- function_base() : vtable(0)
- {
- functor.obj_ptr = 0;
- }
+ function_base() : vtable(0) { }
- // Is this function empty?
+ /** 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 std::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(type.const_obj_ptr);
+ }
+
template
Functor* target()
{
if (!vtable) return 0;
- detail::function::any_pointer result =
- vtable->manager(detail::function::make_any_pointer(&typeid(Functor)),
- detail::function::check_functor_type_tag);
- if (!result.obj_ptr) return 0;
- else {
- typedef typename detail::function::get_function_tag::type tag;
- return get_functor_pointer(tag(), 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(type_result.obj_ptr);
}
template
@@ -440,19 +508,11 @@ public:
{
if (!vtable) return 0;
- detail::function::any_pointer result =
- vtable->manager(detail::function::make_any_pointer(&typeid(Functor)),
- detail::function::check_functor_type_tag);
- if (!result.obj_ptr) return 0;
- else {
- typedef typename detail::function::get_function_tag::type tag;
-
-#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- return get_functor_pointer(tag(), 0, (Functor*)0);
-#else
- return get_functor_pointer(tag(), 0);
-#endif
- }
+ 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(type_result.obj_ptr);
}
template
@@ -495,41 +555,7 @@ public:
public: // should be protected, but GCC 2.95.3 will fail to allow access
detail::function::vtable_base* vtable;
- detail::function::any_pointer functor;
-
-private:
- template
-#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- Functor* get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0)
-#else
- Functor* get_functor_pointer(detail::function::function_ptr_tag, int)
-#endif
- { return reinterpret_cast(&functor.func_ptr); }
-
- template
-#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- Functor* get_functor_pointer(Tag, long, Functor * = 0)
-#else
- Functor* get_functor_pointer(Tag, long)
-#endif
- { return static_cast(functor.obj_ptr); }
-
- template
- const Functor*
-#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- get_functor_pointer(detail::function::function_ptr_tag, int, Functor * = 0) const
-#else
- get_functor_pointer(detail::function::function_ptr_tag, int) const
-#endif
- { return reinterpret_cast(&functor.func_ptr); }
-
- template
-#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
- const Functor* get_functor_pointer(Tag, long, Functor * = 0) const
-#else
- const Functor* get_functor_pointer(Tag, long) const
-#endif
- { return static_cast(functor.const_obj_ptr); }
+ mutable detail::function::function_buffer functor;
};
/**
diff --git a/include/boost/function/function_template.hpp b/include/boost/function/function_template.hpp
index 0bda1ca..b0d01b8 100644
--- a/include/boost/function/function_template.hpp
+++ b/include/boost/function/function_template.hpp
@@ -1,6 +1,6 @@
// Boost.Function library
-// Copyright Douglas Gregor 2001-2003. Use, modification and
+// 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
// http://www.boost.org/LICENSE_1_0.txt)
@@ -50,16 +50,16 @@
BOOST_JOIN(function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
#define BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER \
BOOST_JOIN(void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
-#define BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER \
- BOOST_JOIN(stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
-#define BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER \
- BOOST_JOIN(stateless_void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
+#define BOOST_FUNCTION_FUNCTION_REF_INVOKER \
+ BOOST_JOIN(function_ref_invoker,BOOST_FUNCTION_NUM_ARGS)
+#define BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER \
+ BOOST_JOIN(void_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS)
#define BOOST_FUNCTION_GET_FUNCTION_INVOKER \
BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS)
#define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \
BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
-#define BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER \
- BOOST_JOIN(get_stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
+#define BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER \
+ BOOST_JOIN(get_function_ref_invoker,BOOST_FUNCTION_NUM_ARGS)
#define BOOST_FUNCTION_VTABLE BOOST_JOIN(basic_vtable,BOOST_FUNCTION_NUM_ARGS)
#ifndef BOOST_NO_VOID_RETURNS
@@ -80,7 +80,7 @@ namespace boost {
>
struct BOOST_FUNCTION_FUNCTION_INVOKER
{
- static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
+ static R invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS)
{
FunctionPtr f = reinterpret_cast(function_ptr.func_ptr);
@@ -96,7 +96,7 @@ namespace boost {
struct BOOST_FUNCTION_VOID_FUNCTION_INVOKER
{
static BOOST_FUNCTION_VOID_RETURN_TYPE
- invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
+ invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS)
{
@@ -112,11 +112,15 @@ namespace boost {
>
struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
{
- static R invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA
+ static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS)
{
- FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
+ FunctionObj* f;
+ if (function_allows_small_object_optimization::value)
+ f = reinterpret_cast(&function_obj_ptr.data);
+ else
+ f = reinterpret_cast(function_obj_ptr.obj_ptr);
return (*f)(BOOST_FUNCTION_ARGS);
}
};
@@ -129,11 +133,15 @@ namespace boost {
struct BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
{
static BOOST_FUNCTION_VOID_RETURN_TYPE
- invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA
+ invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS)
{
- FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
+ FunctionObj* f;
+ if (function_allows_small_object_optimization::value)
+ f = reinterpret_cast(&function_obj_ptr.data);
+ else
+ f = reinterpret_cast(function_obj_ptr.obj_ptr);
BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS));
}
};
@@ -143,12 +151,15 @@ namespace boost {
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS
>
- struct BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
+ struct BOOST_FUNCTION_FUNCTION_REF_INVOKER
{
- static R invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS)
+ static R invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA
+ BOOST_FUNCTION_PARMS)
+
{
- FunctionObj f = FunctionObj();
- return f(BOOST_FUNCTION_ARGS);
+ FunctionObj* f =
+ reinterpret_cast(function_obj_ptr.obj_ptr);
+ return (*f)(BOOST_FUNCTION_ARGS);
}
};
@@ -157,14 +168,16 @@ namespace boost {
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS
>
- struct BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
+ struct BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER
{
static BOOST_FUNCTION_VOID_RETURN_TYPE
- invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS)
+ invoke(function_buffer& function_obj_ptr BOOST_FUNCTION_COMMA
+ BOOST_FUNCTION_PARMS)
{
- FunctionObj f = FunctionObj();
- BOOST_FUNCTION_RETURN(f(BOOST_FUNCTION_ARGS));
+ FunctionObj* f =
+ reinterpret_cast(function_obj_ptr.obj_ptr);
+ BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS));
}
};
@@ -175,7 +188,7 @@ namespace boost {
>
struct BOOST_FUNCTION_GET_FUNCTION_INVOKER
{
- typedef typename ct_if<(is_void::value),
+ typedef typename mpl::if_c<(is_void::value),
BOOST_FUNCTION_VOID_FUNCTION_INVOKER<
FunctionPtr,
R BOOST_FUNCTION_COMMA
@@ -196,7 +209,7 @@ namespace boost {
>
struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
{
- typedef typename ct_if<(is_void::value),
+ typedef typename mpl::if_c<(is_void::value),
BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER<
FunctionObj,
R BOOST_FUNCTION_COMMA
@@ -215,15 +228,15 @@ namespace boost {
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS
>
- struct BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
+ struct BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER
{
- typedef typename ct_if<(is_void::value),
- BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER<
+ typedef typename mpl::if_c<(is_void::value),
+ BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER<
FunctionObj,
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS
>,
- BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER<
+ BOOST_FUNCTION_FUNCTION_REF_INVOKER<
FunctionObj,
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS
@@ -244,7 +257,7 @@ namespace boost {
typedef typename function_return_type::type result_type;
#endif // BOOST_NO_VOID_RETURNS
- typedef result_type (*invoker_type)(any_pointer
+ typedef result_type (*invoker_type)(function_buffer&
BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS);
@@ -255,16 +268,16 @@ namespace boost {
}
template
- bool assign_to(F f, any_pointer& functor)
+ bool assign_to(F f, function_buffer& functor)
{
typedef typename get_function_tag::type tag;
return assign_to(f, functor, tag());
}
- void clear(any_pointer& functor)
+ void clear(function_buffer& functor)
{
if (manager)
- functor = manager(functor, destroy_functor_tag);
+ manager(functor, functor, destroy_functor_tag);
}
private:
@@ -291,14 +304,14 @@ namespace boost {
}
template
- bool assign_to(FunctionPtr f, any_pointer& functor, function_ptr_tag)
+ bool
+ assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag)
{
this->clear(functor);
if (f) {
// should be a reinterpret cast, but some compilers insist
// on giving cv-qualifiers to free functions
- functor = manager(make_any_pointer((void (*)())(f)),
- clone_functor_tag);
+ functor.func_ptr = (void (*)())(f);
return true;
} else {
return false;
@@ -310,12 +323,18 @@ namespace boost {
template
void init(MemberPtr f, member_ptr_tag)
{
+ // DPG TBD: Add explicit support for member function
+ // objects, so we invoke through mem_fn() but we retain the
+ // right target_type() values.
this->init(mem_fn(f));
}
template
- bool assign_to(MemberPtr f, any_pointer& functor, member_ptr_tag)
+ bool assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag)
{
+ // DPG TBD: Add explicit support for member function
+ // objects, so we invoke through mem_fn() but we retain the
+ // right target_type() values.
if (f) {
this->assign_to(mem_fn(f), functor);
return true;
@@ -325,7 +344,7 @@ namespace boost {
}
#endif // BOOST_FUNCTION_NUM_ARGS > 0
- // Stateful function objects
+ // Function objects
template
void init(FunctionObj f, function_obj_tag)
{
@@ -340,24 +359,42 @@ namespace boost {
manager = &functor_manager::manage;
}
+ // Assign to a function object using the small object optimization
template
- bool assign_to(FunctionObj f, any_pointer& functor, function_obj_tag)
+ void
+ assign_functor(FunctionObj f, function_buffer& functor, mpl::true_)
+ {
+ new ((void*)&functor.data) FunctionObj(f);
+ }
+
+ // Assign to a function object allocated on the heap.
+ template
+ void
+ assign_functor(FunctionObj f, function_buffer& functor, mpl::false_)
+ {
+#ifndef BOOST_NO_STD_ALLOCATOR
+ typedef typename Allocator::template rebind::other
+ allocator_type;
+ typedef typename allocator_type::pointer pointer_type;
+
+ allocator_type allocator;
+ pointer_type copy = allocator.allocate(1);
+ allocator.construct(copy, f);
+
+ // Get back to the original pointer type
+ functor.obj_ptr = static_cast(copy);
+# else
+ functor.obj_ptr = new FunctionObj(f);
+# endif // BOOST_NO_STD_ALLOCATOR
+ }
+
+ template
+ bool
+ assign_to(FunctionObj f, function_buffer& functor, function_obj_tag)
{
if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
-#ifndef BOOST_NO_STD_ALLOCATOR
- typedef typename Allocator::template rebind::other
- rebound_allocator_type;
- typedef typename rebound_allocator_type::pointer pointer_type;
- rebound_allocator_type allocator;
- pointer_type copy = allocator.allocate(1);
- allocator.construct(copy, f);
-
- // Get back to the original pointer type
- FunctionObj* new_f = static_cast(copy);
-#else
- FunctionObj* new_f = new FunctionObj(f);
-#endif // BOOST_NO_STD_ALLOCATOR
- functor = make_any_pointer(static_cast(new_f));
+ assign_functor(f, functor,
+ mpl::bool_<(function_allows_small_object_optimization::value)>());
return true;
} else {
return false;
@@ -369,7 +406,7 @@ namespace boost {
void
init(const reference_wrapper& f, function_obj_ref_tag)
{
- typedef typename BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
+ typedef typename BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER<
FunctionObj,
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS
@@ -377,46 +414,20 @@ namespace boost {
actual_invoker_type;
invoker = &actual_invoker_type::invoke;
- manager = &trivial_manager::get;
+ manager = &reference_manager::get;
}
template
bool
- assign_to(const reference_wrapper& f, any_pointer& functor,
- function_obj_ref_tag)
+ assign_to(const reference_wrapper& f,
+ function_buffer& functor, function_obj_ref_tag)
{
if (!boost::detail::function::has_empty_target(f.get_pointer())) {
- functor = manager(make_any_pointer(
- const_cast(f.get_pointer())),
- clone_functor_tag);
- return true;
- } else {
- return false;
- }
- }
-
- // Stateless function object
- template
- void
- init(FunctionObj, stateless_function_obj_tag)
- {
- typedef
- typename BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER<
- FunctionObj,
- R BOOST_FUNCTION_COMMA
- BOOST_FUNCTION_TEMPLATE_ARGS
- >::type actual_invoker_type;
- invoker = &actual_invoker_type::invoke;
- manager = &trivial_manager::get;
- }
-
- template
- bool
- assign_to(FunctionObj f, any_pointer& functor,
- stateless_function_obj_tag)
- {
- if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
- functor = make_any_pointer(this);
+ // DPG TBD: We might need to detect constness of
+ // FunctionObj to assign into obj_ptr or const_obj_ptr to
+ // be truly legit, but no platform in existence makes
+ // const void* different from void*.
+ functor.const_obj_ptr = f.get_pointer();
return true;
} else {
return false;
@@ -539,7 +550,13 @@ namespace boost {
#endif
operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
{
- self_type(f).swap(*this);
+ this->clear();
+ try {
+ this->assign_to(f);
+ } catch (...) {
+ vtable = 0;
+ throw;
+ }
return *this;
}
@@ -564,7 +581,13 @@ namespace boost {
if (&f == this)
return *this;
- self_type(f).swap(*this);
+ this->clear();
+ try {
+ this->assign_to_own(f);
+ } catch (...) {
+ vtable = 0;
+ throw;
+ }
return *this;
}
@@ -573,8 +596,9 @@ namespace boost {
if (&other == this)
return;
- std::swap(this->functor, other.functor);
- std::swap(this->vtable, other.vtable);
+ BOOST_FUNCTION_FUNCTION tmp = *this;
+ *this = other;
+ other = tmp;
}
// Clear out a target, if there is one
@@ -610,9 +634,8 @@ namespace boost {
{
if (!f.empty()) {
this->vtable = f.vtable;
- this->functor =
- f.vtable->manager(f.functor,
- boost::detail::function::clone_functor_tag);
+ f.vtable->manager(f.functor, this->functor,
+ boost::detail::function::clone_functor_tag);
}
}
@@ -779,11 +802,11 @@ public:
#undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER
#undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
#undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
-#undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
-#undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
+#undef BOOST_FUNCTION_FUNCTION_REF_INVOKER
+#undef BOOST_FUNCTION_VOID_FUNCTION_REF_INVOKER
#undef BOOST_FUNCTION_GET_FUNCTION_INVOKER
#undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
-#undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
+#undef BOOST_FUNCTION_GET_FUNCTION_REF_INVOKER
#undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER
#undef BOOST_FUNCTION_TEMPLATE_PARMS
#undef BOOST_FUNCTION_TEMPLATE_ARGS
diff --git a/test/allocator_test.cpp b/test/allocator_test.cpp
index 7e12d48..6411aec 100644
--- a/test/allocator_test.cpp
+++ b/test/allocator_test.cpp
@@ -45,7 +45,7 @@ struct plus_int
{
int operator()(int x, int y) const { return x + y; }
- int unused_state_data;
+ int unused_state_data[32];
};
static int do_minus(int x, int y) { return x-y; }
@@ -54,7 +54,7 @@ struct DoNothing
{
void operator()() const {}
- int unused_state_data;
+ int unused_state_data[32];
};
static void do_nothing() {}
diff --git a/test/stateless_test.cpp b/test/stateless_test.cpp
index cd97054..3bc9e45 100644
--- a/test/stateless_test.cpp
+++ b/test/stateless_test.cpp
@@ -14,23 +14,21 @@
struct stateless_integer_add {
int operator()(int x, int y) const { return x+y; }
- void* operator new(std::size_t, stateless_integer_add*)
+ void* operator new(std::size_t)
{
throw std::runtime_error("Cannot allocate a stateless_integer_add");
}
- void operator delete(void*, stateless_integer_add*) throw()
+ void* operator new(std::size_t, void* p)
+ {
+ return p;
+ }
+
+ void operator delete(void*) throw()
{
}
};
-namespace boost {
- template<>
- struct is_stateless {
- BOOST_STATIC_CONSTANT(bool, value = true);
- };
-}
-
int test_main(int, char*[])
{
boost::function2 f;