Compare commits

..

1 Commits

Author SHA1 Message Date
a0f7e705f9 Branch for 2nd try at V2 removal
[SVN r77497]
2012-03-23 12:04:44 +00:00
12 changed files with 262 additions and 568 deletions

View File

@ -3,7 +3,7 @@
# Distributed under the Boost Software License, Version 1.0. # Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at # (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt) # http://www.boost.org/LICENSE_1_0.txt)
project function/doc ; project boost/doc ;
import boostbook : boostbook ; import boostbook : boostbook ;
boostbook function-doc boostbook function-doc

View File

@ -13,15 +13,6 @@
<itemizedlist spacing="compact"> <itemizedlist spacing="compact">
<listitem><para><bold>Version 1.52.0</bold>: </para>
<itemizedlist spacing="compact">
<listitem><para>Move constructors and move assignment
operators added (only for compilers with C++11 rvalue
references support). Original patch
contributed by Antony Polukhin.</para></listitem>
</itemizedlist>
</listitem>
<listitem><para><bold>Version 1.37.0</bold>: </para> <listitem><para><bold>Version 1.37.0</bold>: </para>
<itemizedlist spacing="compact"> <itemizedlist spacing="compact">
<listitem><para>Improved the performance of Boost.Function's <listitem><para>Improved the performance of Boost.Function's

View File

@ -58,7 +58,7 @@
<para>A function object <code>f</code> of <para>A function object <code>f</code> of
type <code>F</code> is type <code>F</code> is
<emphasis>stateless</emphasis> if it is a function pointer or if <emphasis>stateless</emphasis> if it is a function pointer or if
<code><classname>boost::is_stateless</classname>&lt;F&gt;</code> <code><classname>boost::is_stateless</classname>&lt;T&gt;</code>
is true. The construction of or copy to a Boost.Function object is true. The construction of or copy to a Boost.Function object
from a stateless function object will not cause exceptions to be from a stateless function object will not cause exceptions to be
thrown and will not allocate any storage. thrown and will not allocate any storage.
@ -128,7 +128,7 @@
<method name="target_type" cv="const"> <method name="target_type" cv="const">
<type>const std::type_info&amp;</type> <type>const std::type_info&amp;</type>
<returns><simpara><code>typeid</code> of the target function object, or <code>typeid(void)</code> if <code>this-&gt;<methodname>empty</methodname>()</code>. Works even with RTTI off.</simpara></returns> <returns><simpara><code>typeid</code> of the target function object, or <code>typeid(void)</code> if <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></returns>
<throws><simpara>Will not throw.</simpara></throws> <throws><simpara>Will not throw.</simpara></throws>
</method> </method>
</method-group> </method-group>
@ -203,15 +203,6 @@
<throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws> <throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws>
</constructor> </constructor>
<constructor>
<parameter name="f">
<paramtype><classname>functionN</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</constructor>
<constructor> <constructor>
<template> <template>
<template-type-parameter name="F"/> <template-type-parameter name="F"/>
@ -245,15 +236,6 @@
</parameter> </parameter>
<postconditions><simpara>If copy construction does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></postconditions> <postconditions><simpara>If copy construction does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></postconditions>
</copy-assignment> </copy-assignment>
<copy-assignment>
<parameter name="f">
<paramtype><classname>functionN</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</copy-assignment>
<method-group name="modifiers"> <method-group name="modifiers">
<method name="swap"> <method name="swap">
@ -625,16 +607,7 @@
<postconditions><simpara>Contains a copy of the <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>.</simpara></postconditions> <postconditions><simpara>Contains a copy of the <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>.</simpara></postconditions>
<throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws> <throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws>
</constructor> </constructor>
<constructor>
<parameter name="f">
<paramtype><classname>functionN</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</constructor>
<constructor> <constructor>
<parameter name="f"> <parameter name="f">
<paramtype>const <classname>function</classname>&amp;</paramtype> <paramtype>const <classname>function</classname>&amp;</paramtype>
@ -643,15 +616,6 @@
<throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws> <throws><simpara>Will not throw unless copying the target of <code>f</code> throws.</simpara></throws>
</constructor> </constructor>
<constructor>
<parameter name="f">
<paramtype><classname>function</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</constructor>
<constructor> <constructor>
<template> <template>
<template-type-parameter name="F"/> <template-type-parameter name="F"/>
@ -681,19 +645,10 @@
<copy-assignment> <copy-assignment>
<parameter name="f"> <parameter name="f">
<paramtype>const <classname>functionN</classname>&amp;</paramtype> <paramtype>const <classname>function</classname>&amp;</paramtype>
</parameter> </parameter>
<postconditions><simpara>If copy construction does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></postconditions> <postconditions><simpara>If copy construction does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></postconditions>
</copy-assignment> </copy-assignment>
<copy-assignment>
<parameter name="f">
<paramtype><classname>functionN</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</copy-assignment>
<copy-assignment> <copy-assignment>
<parameter name="f"> <parameter name="f">
@ -702,15 +657,6 @@
<postconditions><simpara>If copy construction of the target of <code>f</code> does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. </simpara></postconditions> <postconditions><simpara>If copy construction of the target of <code>f</code> does not throw, <code>*this</code> targets a copy of <code>f</code>'s target, if it has one, or is empty if <code>f.<methodname>empty</methodname>()</code>. </simpara></postconditions>
<throws><simpara>Will not throw when the target of <code>f</code> is a stateless function object or a reference to the function object. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></throws> <throws><simpara>Will not throw when the target of <code>f</code> is a stateless function object or a reference to the function object. If copy construction does throw, <code>this-&gt;<methodname>empty</methodname>()</code>.</simpara></throws>
</copy-assignment> </copy-assignment>
<copy-assignment>
<parameter name="f">
<paramtype><classname>function</classname>&amp;&amp;</paramtype>
</parameter>
<requires><simpara>C++11 compatible compiler.</simpara></requires>
<postconditions><simpara>Moves the value from <code>f</code> to <code>*this</code>. If the argument has its function object allocated on the heap, its buffer will be assigned to <code>*this</code> leaving argument empty.</simpara></postconditions>
<throws><simpara>Will not throw unless argument has its function object allocated not on the heap and copying the target of <code>f</code> throws.</simpara></throws>
</copy-assignment>
<method-group name="modifiers"> <method-group name="modifiers">
<method name="swap"> <method name="swap">

View File

@ -16,15 +16,16 @@
#include <memory> #include <memory>
#include <new> #include <new>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/detail/sp_typeinfo.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/integer.hpp> #include <boost/integer.hpp>
#include <boost/type_index.hpp>
#include <boost/type_traits/has_trivial_copy.hpp> #include <boost/type_traits/has_trivial_copy.hpp>
#include <boost/type_traits/has_trivial_destructor.hpp> #include <boost/type_traits/has_trivial_destructor.hpp>
#include <boost/type_traits/is_const.hpp> #include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_volatile.hpp> #include <boost/type_traits/is_volatile.hpp>
#include <boost/type_traits/composite_traits.hpp> #include <boost/type_traits/composite_traits.hpp>
#include <boost/type_traits/ice.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <boost/mpl/if.hpp> #include <boost/mpl/if.hpp>
#include <boost/detail/workaround.hpp> #include <boost/detail/workaround.hpp>
@ -41,18 +42,49 @@
# pragma warning( push ) # pragma warning( push )
# pragma warning( disable : 4793 ) // complaint about native code generation # pragma warning( disable : 4793 ) // complaint about native code generation
# pragma warning( disable : 4127 ) // "conditional expression is constant" # 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 #endif
#if defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG) // Borrowed from Boost.Python library: determines the cases where we
// need to use std::type_info::name to compare instead of operator==.
#if defined( BOOST_NO_TYPEID )
# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
#elif (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 # define BOOST_FUNCTION_TARGET_FIX(x) x
#else #else
# define BOOST_FUNCTION_TARGET_FIX(x) # define BOOST_FUNCTION_TARGET_FIX(x)
#endif // __ICL etc #endif // not MSVC
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \ # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
typename ::boost::enable_if_c< \ typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
!(::boost::is_integral<Functor>::value), \ (::boost::is_integral<Functor>::value)>::value), \
Type>::type 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 boost {
namespace detail { namespace detail {
@ -65,16 +97,15 @@ namespace boost {
* object pointers, and a structure that resembles a bound * object pointers, and a structure that resembles a bound
* member function pointer. * member function pointer.
*/ */
union function_buffer_members union function_buffer
{ {
// For pointers to function objects // For pointers to function objects
typedef void* obj_ptr_t; mutable void* obj_ptr;
mutable obj_ptr_t obj_ptr;
// For pointers to std::type_info objects // For pointers to std::type_info objects
struct type_t { struct type_t {
// (get_functor_type_tag, check_functor_type_tag). // (get_functor_type_tag, check_functor_type_tag).
const boost::typeindex::type_info* type; const detail::sp_typeinfo* type;
// Whether the type is const-qualified. // Whether the type is const-qualified.
bool const_qualified; bool const_qualified;
@ -83,8 +114,7 @@ namespace boost {
} type; } type;
// For function pointers of all kinds // For function pointers of all kinds
typedef void (*func_ptr_t)(); mutable void (*func_ptr)();
mutable func_ptr_t func_ptr;
// For bound member pointers // For bound member pointers
struct bound_memfunc_ptr_t { struct bound_memfunc_ptr_t {
@ -99,15 +129,9 @@ namespace boost {
bool is_const_qualified; bool is_const_qualified;
bool is_volatile_qualified; bool is_volatile_qualified;
} obj_ref; } obj_ref;
};
union function_buffer
{
// Type-specific union members
mutable function_buffer_members members;
// To relax aliasing constraints // To relax aliasing constraints
mutable char data[sizeof(function_buffer_members)]; mutable char data;
}; };
/** /**
@ -174,42 +198,45 @@ namespace boost {
struct reference_manager struct reference_manager
{ {
static inline void static inline void
manage(const function_buffer& in_buffer, function_buffer& out_buffer, manage(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op) functor_manager_operation_type op)
{ {
switch (op) { switch (op) {
case clone_functor_tag: case clone_functor_tag:
out_buffer.members.obj_ref = in_buffer.members.obj_ref; out_buffer.obj_ref = in_buffer.obj_ref;
return; return;
case move_functor_tag: case move_functor_tag:
out_buffer.members.obj_ref = in_buffer.members.obj_ref; out_buffer.obj_ref = in_buffer.obj_ref;
in_buffer.members.obj_ref.obj_ptr = 0; in_buffer.obj_ref.obj_ptr = 0;
return; return;
case destroy_functor_tag: case destroy_functor_tag:
out_buffer.members.obj_ref.obj_ptr = 0; out_buffer.obj_ref.obj_ptr = 0;
return; return;
case check_functor_type_tag: case check_functor_type_tag:
{ {
const detail::sp_typeinfo& check_type
= *out_buffer.type.type;
// Check whether we have the same type. We can add // Check whether we have the same type. We can add
// cv-qualifiers, but we can't take them away. // cv-qualifiers, but we can't take them away.
if (*out_buffer.members.type.type == boost::typeindex::type_id<F>() if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(F))
&& (!in_buffer.members.obj_ref.is_const_qualified && (!in_buffer.obj_ref.is_const_qualified
|| out_buffer.members.type.const_qualified) || out_buffer.type.const_qualified)
&& (!in_buffer.members.obj_ref.is_volatile_qualified && (!in_buffer.obj_ref.is_volatile_qualified
|| out_buffer.members.type.volatile_qualified)) || out_buffer.type.volatile_qualified))
out_buffer.members.obj_ptr = in_buffer.members.obj_ref.obj_ptr; out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
else else
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} }
return; return;
case get_functor_type_tag: case get_functor_type_tag:
out_buffer.members.type.type = &boost::typeindex::type_id<F>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(F);
out_buffer.members.type.const_qualified = in_buffer.members.obj_ref.is_const_qualified; out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
out_buffer.members.type.volatile_qualified = in_buffer.members.obj_ref.is_volatile_qualified; out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
return; return;
} }
} }
@ -223,9 +250,9 @@ namespace boost {
struct function_allows_small_object_optimization struct function_allows_small_object_optimization
{ {
BOOST_STATIC_CONSTANT BOOST_STATIC_CONSTANT
(bool, (bool,
value = ((sizeof(F) <= sizeof(function_buffer) && value = ((sizeof(F) <= sizeof(function_buffer) &&
(alignment_of<function_buffer>::value (alignment_of<function_buffer>::value
% alignment_of<F>::value == 0)))); % alignment_of<F>::value == 0))));
}; };
@ -237,7 +264,7 @@ namespace boost {
A(a) A(a)
{ {
} }
functor_wrapper(const functor_wrapper& f) : functor_wrapper(const functor_wrapper& f) :
F(static_cast<const F&>(f)), F(static_cast<const F&>(f)),
A(static_cast<const A&>(f)) A(static_cast<const A&>(f))
@ -256,57 +283,61 @@ namespace boost {
// Function pointers // Function pointers
static inline void static inline void
manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer, manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op) functor_manager_operation_type op)
{ {
if (op == clone_functor_tag) if (op == clone_functor_tag)
out_buffer.members.func_ptr = in_buffer.members.func_ptr; out_buffer.func_ptr = in_buffer.func_ptr;
else if (op == move_functor_tag) { else if (op == move_functor_tag) {
out_buffer.members.func_ptr = in_buffer.members.func_ptr; out_buffer.func_ptr = in_buffer.func_ptr;
in_buffer.members.func_ptr = 0; in_buffer.func_ptr = 0;
} else if (op == destroy_functor_tag) } else if (op == destroy_functor_tag)
out_buffer.members.func_ptr = 0; out_buffer.func_ptr = 0;
else if (op == check_functor_type_tag) { else if (op == check_functor_type_tag) {
if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>()) const detail::sp_typeinfo& check_type
out_buffer.members.obj_ptr = &in_buffer.members.func_ptr; = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
out_buffer.obj_ptr = &in_buffer.func_ptr;
else else
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else /* op == get_functor_type_tag */ { } else /* op == get_functor_type_tag */ {
out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
} }
} }
// Function objects that fit in the small-object buffer. // Function objects that fit in the small-object buffer.
static inline void static inline void
manage_small(const function_buffer& in_buffer, function_buffer& out_buffer, manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op) functor_manager_operation_type op)
{ {
if (op == clone_functor_tag || op == move_functor_tag) { if (op == clone_functor_tag || op == move_functor_tag) {
const functor_type* in_functor = const functor_type* in_functor =
reinterpret_cast<const functor_type*>(in_buffer.data); reinterpret_cast<const functor_type*>(&in_buffer.data);
new (reinterpret_cast<void*>(out_buffer.data)) functor_type(*in_functor); new (reinterpret_cast<void*>(&out_buffer.data)) functor_type(*in_functor);
if (op == move_functor_tag) { if (op == move_functor_tag) {
functor_type* f = reinterpret_cast<functor_type*>(in_buffer.data); functor_type* f = reinterpret_cast<functor_type*>(&in_buffer.data);
(void)f; // suppress warning about the value of f not being used (MSVC) (void)f; // suppress warning about the value of f not being used (MSVC)
f->~Functor(); f->~Functor();
} }
} else if (op == destroy_functor_tag) { } else if (op == destroy_functor_tag) {
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type. // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
functor_type* f = reinterpret_cast<functor_type*>(out_buffer.data); functor_type* f = reinterpret_cast<functor_type*>(&out_buffer.data);
(void)f; // suppress warning about the value of f not being used (MSVC) (void)f; // suppress warning about the value of f not being used (MSVC)
f->~Functor(); f->~Functor();
} else if (op == check_functor_type_tag) { } else if (op == check_functor_type_tag) {
if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>()) const detail::sp_typeinfo& check_type
out_buffer.members.obj_ptr = in_buffer.data; = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
out_buffer.obj_ptr = &in_buffer.data;
else else
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else /* op == get_functor_type_tag */ { } else /* op == get_functor_type_tag */ {
out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
} }
} }
}; };
@ -319,7 +350,7 @@ namespace boost {
// Function pointers // Function pointers
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, function_ptr_tag) functor_manager_operation_type op, function_ptr_tag)
{ {
functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op); functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
@ -327,15 +358,15 @@ namespace boost {
// Function objects that fit in the small-object buffer. // Function objects that fit in the small-object buffer.
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::true_) functor_manager_operation_type op, mpl::true_)
{ {
functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op); functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
} }
// Function objects that require heap allocation // Function objects that require heap allocation
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::false_) functor_manager_operation_type op, mpl::false_)
{ {
if (op == clone_functor_tag) { if (op == clone_functor_tag) {
@ -345,27 +376,29 @@ namespace boost {
// jewillco: Changing this to static_cast because GCC 2.95.3 is // jewillco: Changing this to static_cast because GCC 2.95.3 is
// obsolete. // obsolete.
const functor_type* f = const functor_type* f =
static_cast<const functor_type*>(in_buffer.members.obj_ptr); static_cast<const functor_type*>(in_buffer.obj_ptr);
functor_type* new_f = new functor_type(*f); functor_type* new_f = new functor_type(*f);
out_buffer.members.obj_ptr = new_f; out_buffer.obj_ptr = new_f;
} else if (op == move_functor_tag) { } else if (op == move_functor_tag) {
out_buffer.members.obj_ptr = in_buffer.members.obj_ptr; out_buffer.obj_ptr = in_buffer.obj_ptr;
in_buffer.members.obj_ptr = 0; in_buffer.obj_ptr = 0;
} else if (op == destroy_functor_tag) { } else if (op == destroy_functor_tag) {
/* Cast from the void pointer to the functor pointer type */ /* Cast from the void pointer to the functor pointer type */
functor_type* f = functor_type* f =
static_cast<functor_type*>(out_buffer.members.obj_ptr); static_cast<functor_type*>(out_buffer.obj_ptr);
delete f; delete f;
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else if (op == check_functor_type_tag) { } else if (op == check_functor_type_tag) {
if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>()) const detail::sp_typeinfo& check_type
out_buffer.members.obj_ptr = in_buffer.members.obj_ptr; = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else else
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else /* op == get_functor_type_tag */ { } else /* op == get_functor_type_tag */ {
out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
} }
} }
@ -373,7 +406,7 @@ namespace boost {
// object can use the small-object optimization buffer or // object can use the small-object optimization buffer or
// whether we need to allocate it on the heap. // whether we need to allocate it on the heap.
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, function_obj_tag) functor_manager_operation_type op, function_obj_tag)
{ {
manager(in_buffer, out_buffer, op, manager(in_buffer, out_buffer, op,
@ -382,7 +415,7 @@ namespace boost {
// For member pointers, we use the small-object optimization buffer. // For member pointers, we use the small-object optimization buffer.
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, member_ptr_tag) functor_manager_operation_type op, member_ptr_tag)
{ {
manager(in_buffer, out_buffer, op, mpl::true_()); manager(in_buffer, out_buffer, op, mpl::true_());
@ -392,15 +425,15 @@ namespace boost {
/* Dispatch to an appropriate manager based on whether we have a /* Dispatch to an appropriate manager based on whether we have a
function pointer or a function object pointer. */ function pointer or a function object pointer. */
static inline void static inline void
manage(const function_buffer& in_buffer, function_buffer& out_buffer, manage(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op) functor_manager_operation_type op)
{ {
typedef typename get_function_tag<functor_type>::type tag_type; typedef typename get_function_tag<functor_type>::type tag_type;
switch (op) { switch (op) {
case get_functor_type_tag: case get_functor_type_tag:
out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
return; return;
default: default:
@ -418,7 +451,7 @@ namespace boost {
// Function pointers // Function pointers
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, function_ptr_tag) functor_manager_operation_type op, function_ptr_tag)
{ {
functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op); functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
@ -426,15 +459,15 @@ namespace boost {
// Function objects that fit in the small-object buffer. // Function objects that fit in the small-object buffer.
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::true_) functor_manager_operation_type op, mpl::true_)
{ {
functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op); functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
} }
// Function objects that require heap allocation // Function objects that require heap allocation
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, mpl::false_) functor_manager_operation_type op, mpl::false_)
{ {
typedef functor_wrapper<Functor,Allocator> functor_wrapper_type; typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
@ -447,34 +480,36 @@ namespace boost {
// GCC 2.95.3 gets the CV qualifiers wrong here, so we // GCC 2.95.3 gets the CV qualifiers wrong here, so we
// can't do the static_cast that we should do. // can't do the static_cast that we should do.
const functor_wrapper_type* f = const functor_wrapper_type* f =
static_cast<const functor_wrapper_type*>(in_buffer.members.obj_ptr); static_cast<const functor_wrapper_type*>(in_buffer.obj_ptr);
wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f)); wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
wrapper_allocator.construct(copy, *f); wrapper_allocator.construct(copy, *f);
// Get back to the original pointer type // Get back to the original pointer type
functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy); functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
out_buffer.members.obj_ptr = new_f; out_buffer.obj_ptr = new_f;
} else if (op == move_functor_tag) { } else if (op == move_functor_tag) {
out_buffer.members.obj_ptr = in_buffer.members.obj_ptr; out_buffer.obj_ptr = in_buffer.obj_ptr;
in_buffer.members.obj_ptr = 0; in_buffer.obj_ptr = 0;
} else if (op == destroy_functor_tag) { } else if (op == destroy_functor_tag) {
/* Cast from the void pointer to the functor_wrapper_type */ /* Cast from the void pointer to the functor_wrapper_type */
functor_wrapper_type* victim = functor_wrapper_type* victim =
static_cast<functor_wrapper_type*>(in_buffer.members.obj_ptr); static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim)); wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
wrapper_allocator.destroy(victim); wrapper_allocator.destroy(victim);
wrapper_allocator.deallocate(victim,1); wrapper_allocator.deallocate(victim,1);
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else if (op == check_functor_type_tag) { } else if (op == check_functor_type_tag) {
if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>()) const detail::sp_typeinfo& check_type
out_buffer.members.obj_ptr = in_buffer.members.obj_ptr; = *out_buffer.type.type;
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
out_buffer.obj_ptr = in_buffer.obj_ptr;
else else
out_buffer.members.obj_ptr = 0; out_buffer.obj_ptr = 0;
} else /* op == get_functor_type_tag */ { } else /* op == get_functor_type_tag */ {
out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
} }
} }
@ -482,7 +517,7 @@ namespace boost {
// object can use the small-object optimization buffer or // object can use the small-object optimization buffer or
// whether we need to allocate it on the heap. // whether we need to allocate it on the heap.
static inline void static inline void
manager(const function_buffer& in_buffer, function_buffer& out_buffer, manager(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op, function_obj_tag) functor_manager_operation_type op, function_obj_tag)
{ {
manager(in_buffer, out_buffer, op, manager(in_buffer, out_buffer, op,
@ -493,15 +528,15 @@ namespace boost {
/* Dispatch to an appropriate manager based on whether we have a /* Dispatch to an appropriate manager based on whether we have a
function pointer or a function object pointer. */ function pointer or a function object pointer. */
static inline void static inline void
manage(const function_buffer& in_buffer, function_buffer& out_buffer, manage(const function_buffer& in_buffer, function_buffer& out_buffer,
functor_manager_operation_type op) functor_manager_operation_type op)
{ {
typedef typename get_function_tag<functor_type>::type tag_type; typedef typename get_function_tag<functor_type>::type tag_type;
switch (op) { switch (op) {
case get_functor_type_tag: case get_functor_type_tag:
out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info(); out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
out_buffer.members.type.const_qualified = false; out_buffer.type.const_qualified = false;
out_buffer.members.type.volatile_qualified = false; out_buffer.type.volatile_qualified = false;
return; return;
default: default:
@ -579,8 +614,8 @@ namespace boost {
*/ */
struct vtable_base struct vtable_base
{ {
void (*manager)(const function_buffer& in_buffer, void (*manager)(const function_buffer& in_buffer,
function_buffer& out_buffer, function_buffer& out_buffer,
functor_manager_operation_type op); functor_manager_operation_type op);
}; };
} // end namespace function } // end namespace function
@ -600,15 +635,15 @@ public:
/** Determine if the function is empty (i.e., has no target). */ /** Determine if the function is empty (i.e., has no target). */
bool empty() const { return !vtable; } bool empty() const { return !vtable; }
/** Retrieve the type of the stored function object, or type_id<void>() /** Retrieve the type of the stored function object, or BOOST_SP_TYPEID(void)
if this is empty. */ if this is empty. */
const boost::typeindex::type_info& target_type() const const detail::sp_typeinfo& target_type() const
{ {
if (!vtable) return boost::typeindex::type_id<void>().type_info(); if (!vtable) return BOOST_SP_TYPEID(void);
detail::function::function_buffer type; detail::function::function_buffer type;
get_vtable()->manager(functor, type, detail::function::get_functor_type_tag); get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
return *type.members.type.type; return *type.type.type;
} }
template<typename Functor> template<typename Functor>
@ -617,34 +652,42 @@ public:
if (!vtable) return 0; if (!vtable) return 0;
detail::function::function_buffer type_result; detail::function::function_buffer type_result;
type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); type_result.type.type = &BOOST_SP_TYPEID(Functor);
type_result.members.type.const_qualified = is_const<Functor>::value; type_result.type.const_qualified = is_const<Functor>::value;
type_result.members.type.volatile_qualified = is_volatile<Functor>::value; type_result.type.volatile_qualified = is_volatile<Functor>::value;
get_vtable()->manager(functor, type_result, get_vtable()->manager(functor, type_result,
detail::function::check_functor_type_tag); detail::function::check_functor_type_tag);
return static_cast<Functor*>(type_result.members.obj_ptr); return static_cast<Functor*>(type_result.obj_ptr);
} }
template<typename Functor> template<typename Functor>
#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
const Functor* target( Functor * = 0 ) const
#else
const Functor* target() const const Functor* target() const
#endif
{ {
if (!vtable) return 0; if (!vtable) return 0;
detail::function::function_buffer type_result; detail::function::function_buffer type_result;
type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info(); type_result.type.type = &BOOST_SP_TYPEID(Functor);
type_result.members.type.const_qualified = true; type_result.type.const_qualified = true;
type_result.members.type.volatile_qualified = is_volatile<Functor>::value; type_result.type.volatile_qualified = is_volatile<Functor>::value;
get_vtable()->manager(functor, type_result, get_vtable()->manager(functor, type_result,
detail::function::check_functor_type_tag); detail::function::check_functor_type_tag);
// GCC 2.95.3 gets the CV qualifiers wrong here, so we // GCC 2.95.3 gets the CV qualifiers wrong here, so we
// can't do the static_cast that we should do. // can't do the static_cast that we should do.
return static_cast<const Functor*>(type_result.members.obj_ptr); return static_cast<const Functor*>(type_result.obj_ptr);
} }
template<typename F> template<typename F>
bool contains(const F& f) const 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>()) if (const F* fp = this->template target<F>())
#endif
{ {
return function_equal(*fp, f); return function_equal(*fp, f);
} else { } else {
@ -858,9 +901,10 @@ namespace detail {
} // end namespace boost } // end namespace boost
#undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
#undef BOOST_FUNCTION_COMPARE_TYPE_ID
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
# pragma warning( pop ) # pragma warning( pop )
#endif #endif
#endif // BOOST_FUNCTION_BASE_HEADER #endif // BOOST_FUNCTION_BASE_HEADER

View File

@ -19,7 +19,8 @@ namespace boost { namespace python { namespace objects {
}}} }}}
#endif #endif
#if defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \ #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
|| defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
|| !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540) || !(defined(BOOST_STRICT_CONFIG) || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX # define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
#endif #endif

View File

@ -16,7 +16,7 @@
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
# pragma warning( push ) # pragma warning( push )
# pragma warning( disable : 4127 ) // "conditional expression is constant" # pragma warning( disable : 4127 ) // "conditional expression is constant"
#endif #endif
#define BOOST_FUNCTION_TEMPLATE_PARMS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, typename T) #define BOOST_FUNCTION_TEMPLATE_PARMS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, typename T)
@ -26,13 +26,7 @@
#define BOOST_FUNCTION_PARMS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_PARM,BOOST_PP_EMPTY) #define BOOST_FUNCTION_PARMS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_PARM,BOOST_PP_EMPTY)
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_FUNCTION_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, a)
# define BOOST_FUNCTION_ARGS BOOST_PP_ENUM_PARAMS(BOOST_FUNCTION_NUM_ARGS, a)
#else
# include <boost/move/utility_core.hpp>
# define BOOST_FUNCTION_ARG(J,I,D) ::boost::forward< BOOST_PP_CAT(T,I) >(BOOST_PP_CAT(a,I))
# define BOOST_FUNCTION_ARGS BOOST_PP_ENUM(BOOST_FUNCTION_NUM_ARGS,BOOST_FUNCTION_ARG,BOOST_PP_EMPTY)
#endif
#define BOOST_FUNCTION_ARG_TYPE(J,I,D) \ #define BOOST_FUNCTION_ARG_TYPE(J,I,D) \
typedef BOOST_PP_CAT(T,I) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(I)),_type); typedef BOOST_PP_CAT(T,I) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(I)),_type);
@ -97,7 +91,7 @@ namespace boost {
static R invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA static R invoke(function_buffer& function_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.members.func_ptr); FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
return f(BOOST_FUNCTION_ARGS); return f(BOOST_FUNCTION_ARGS);
} }
}; };
@ -114,7 +108,7 @@ namespace boost {
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.members.func_ptr); FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
BOOST_FUNCTION_RETURN(f(BOOST_FUNCTION_ARGS)); BOOST_FUNCTION_RETURN(f(BOOST_FUNCTION_ARGS));
} }
}; };
@ -132,9 +126,9 @@ namespace boost {
{ {
FunctionObj* f; FunctionObj* f;
if (function_allows_small_object_optimization<FunctionObj>::value) if (function_allows_small_object_optimization<FunctionObj>::value)
f = reinterpret_cast<FunctionObj*>(function_obj_ptr.data); f = reinterpret_cast<FunctionObj*>(&function_obj_ptr.data);
else else
f = reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr); f = reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
return (*f)(BOOST_FUNCTION_ARGS); return (*f)(BOOST_FUNCTION_ARGS);
} }
}; };
@ -153,9 +147,9 @@ namespace boost {
{ {
FunctionObj* f; FunctionObj* f;
if (function_allows_small_object_optimization<FunctionObj>::value) if (function_allows_small_object_optimization<FunctionObj>::value)
f = reinterpret_cast<FunctionObj*>(function_obj_ptr.data); f = reinterpret_cast<FunctionObj*>(&function_obj_ptr.data);
else else
f = reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr); f = reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS)); BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS));
} }
}; };
@ -171,8 +165,8 @@ namespace boost {
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
FunctionObj* f = FunctionObj* f =
reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr); reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
return (*f)(BOOST_FUNCTION_ARGS); return (*f)(BOOST_FUNCTION_ARGS);
} }
}; };
@ -189,8 +183,8 @@ namespace boost {
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
FunctionObj* f = FunctionObj* f =
reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr); reinterpret_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS)); BOOST_FUNCTION_RETURN((*f)(BOOST_FUNCTION_ARGS));
} }
}; };
@ -208,8 +202,8 @@ namespace boost {
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
MemberPtr* f = MemberPtr* f =
reinterpret_cast<MemberPtr*>(function_obj_ptr.data); reinterpret_cast<MemberPtr*>(&function_obj_ptr.data);
return boost::mem_fn(*f)(BOOST_FUNCTION_ARGS); return boost::mem_fn(*f)(BOOST_FUNCTION_ARGS);
} }
}; };
@ -226,8 +220,8 @@ namespace boost {
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
{ {
MemberPtr* f = MemberPtr* f =
reinterpret_cast<MemberPtr*>(function_obj_ptr.data); reinterpret_cast<MemberPtr*>(&function_obj_ptr.data);
BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS)); BOOST_FUNCTION_RETURN(boost::mem_fn(*f)(BOOST_FUNCTION_ARGS));
} }
}; };
@ -322,7 +316,7 @@ namespace boost {
/* Given the tag returned by get_function_tag, retrieve the /* Given the tag returned by get_function_tag, retrieve the
actual invoker that will be used for the given function actual invoker that will be used for the given function
object. object.
Each specialization contains an "apply" nested class template Each specialization contains an "apply" nested class template
that accepts the function object, return type, function that accepts the function object, return type, function
@ -513,21 +507,21 @@ namespace boost {
private: private:
// Function pointers // Function pointers
template<typename FunctionPtr> template<typename FunctionPtr>
bool bool
assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) const assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) const
{ {
this->clear(functor); this->clear(functor);
if (f) { if (f) {
// should be a reinterpret cast, but some compilers insist // should be a reinterpret cast, but some compilers insist
// on giving cv-qualifiers to free functions // on giving cv-qualifiers to free functions
functor.members.func_ptr = reinterpret_cast<void (*)()>(f); functor.func_ptr = reinterpret_cast<void (*)()>(f);
return true; return true;
} else { } else {
return false; return false;
} }
} }
template<typename FunctionPtr,typename Allocator> template<typename FunctionPtr,typename Allocator>
bool bool
assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) const assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) const
{ {
return assign_to(f,functor,function_ptr_tag()); return assign_to(f,functor,function_ptr_tag());
@ -566,13 +560,13 @@ namespace boost {
// Function objects // Function objects
// Assign to a function object using the small object optimization // Assign to a function object using the small object optimization
template<typename FunctionObj> template<typename FunctionObj>
void void
assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) const assign_functor(FunctionObj f, function_buffer& functor, mpl::true_) const
{ {
new (reinterpret_cast<void*>(functor.data)) FunctionObj(f); new (reinterpret_cast<void*>(&functor.data)) FunctionObj(f);
} }
template<typename FunctionObj,typename Allocator> template<typename FunctionObj,typename Allocator>
void void
assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) const assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, mpl::true_) const
{ {
assign_functor(f,functor,mpl::true_()); assign_functor(f,functor,mpl::true_());
@ -580,13 +574,13 @@ namespace boost {
// Assign to a function object allocated on the heap. // Assign to a function object allocated on the heap.
template<typename FunctionObj> template<typename FunctionObj>
void void
assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) const assign_functor(FunctionObj f, function_buffer& functor, mpl::false_) const
{ {
functor.members.obj_ptr = new FunctionObj(f); functor.obj_ptr = new FunctionObj(f);
} }
template<typename FunctionObj,typename Allocator> template<typename FunctionObj,typename Allocator>
void void
assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) const assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, mpl::false_) const
{ {
typedef functor_wrapper<FunctionObj,Allocator> functor_wrapper_type; typedef functor_wrapper<FunctionObj,Allocator> functor_wrapper_type;
@ -597,15 +591,15 @@ namespace boost {
wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1); wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
wrapper_allocator.construct(copy, functor_wrapper_type(f,a)); wrapper_allocator.construct(copy, functor_wrapper_type(f,a));
functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy); functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
functor.members.obj_ptr = new_f; functor.obj_ptr = new_f;
} }
template<typename FunctionObj> template<typename FunctionObj>
bool bool
assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) const assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) const
{ {
if (!boost::detail::function::has_empty_target(boost::addressof(f))) { if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
assign_functor(f, functor, assign_functor(f, functor,
mpl::bool_<(function_allows_small_object_optimization<FunctionObj>::value)>()); mpl::bool_<(function_allows_small_object_optimization<FunctionObj>::value)>());
return true; return true;
} else { } else {
@ -613,7 +607,7 @@ namespace boost {
} }
} }
template<typename FunctionObj,typename Allocator> template<typename FunctionObj,typename Allocator>
bool bool
assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) const assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) const
{ {
if (!boost::detail::function::has_empty_target(boost::addressof(f))) { if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
@ -627,18 +621,18 @@ namespace boost {
// Reference to a function object // Reference to a function object
template<typename FunctionObj> template<typename FunctionObj>
bool bool
assign_to(const reference_wrapper<FunctionObj>& f, assign_to(const reference_wrapper<FunctionObj>& f,
function_buffer& functor, function_obj_ref_tag) const function_buffer& functor, function_obj_ref_tag) const
{ {
functor.members.obj_ref.obj_ptr = (void *)(f.get_pointer()); functor.obj_ref.obj_ptr = (void *)(f.get_pointer());
functor.members.obj_ref.is_const_qualified = is_const<FunctionObj>::value; functor.obj_ref.is_const_qualified = is_const<FunctionObj>::value;
functor.members.obj_ref.is_volatile_qualified = is_volatile<FunctionObj>::value; functor.obj_ref.is_volatile_qualified = is_volatile<FunctionObj>::value;
return true; return true;
} }
template<typename FunctionObj,typename Allocator> template<typename FunctionObj,typename Allocator>
bool bool
assign_to_a(const reference_wrapper<FunctionObj>& f, assign_to_a(const reference_wrapper<FunctionObj>& f,
function_buffer& functor, Allocator, function_obj_ref_tag) const function_buffer& functor, Allocator, function_obj_ref_tag) const
{ {
return assign_to(f,functor,function_obj_ref_tag()); return assign_to(f,functor,function_obj_ref_tag());
@ -683,7 +677,7 @@ namespace boost {
vtable_type* get_vtable() const { vtable_type* get_vtable() const {
return reinterpret_cast<vtable_type*>( return reinterpret_cast<vtable_type*>(
reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01)); reinterpret_cast<std::size_t>(vtable) & ~static_cast<size_t>(0x01));
} }
struct clear_type {}; struct clear_type {};
@ -717,8 +711,9 @@ namespace boost {
template<typename Functor> template<typename Functor>
BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
,typename boost::enable_if_c< ,typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
int>::type = 0 int>::type = 0
#endif // BOOST_NO_SFINAE #endif // BOOST_NO_SFINAE
) : ) :
@ -729,8 +724,9 @@ namespace boost {
template<typename Functor,typename Allocator> template<typename Functor,typename Allocator>
BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
,typename boost::enable_if_c< ,typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
int>::type = 0 int>::type = 0
#endif // BOOST_NO_SFINAE #endif // BOOST_NO_SFINAE
) : ) :
@ -753,13 +749,6 @@ namespace boost {
this->assign_to_own(f); this->assign_to_own(f);
} }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
BOOST_FUNCTION_FUNCTION(BOOST_FUNCTION_FUNCTION&& f) : function_base()
{
this->move_assign(f);
}
#endif
~BOOST_FUNCTION_FUNCTION() { clear(); } ~BOOST_FUNCTION_FUNCTION() { clear(); }
result_type operator()(BOOST_FUNCTION_PARMS) const result_type operator()(BOOST_FUNCTION_PARMS) const
@ -778,8 +767,9 @@ namespace boost {
// construct. // construct.
template<typename Functor> template<typename Functor>
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
typename boost::enable_if_c< typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
BOOST_FUNCTION_FUNCTION&>::type BOOST_FUNCTION_FUNCTION&>::type
#else #else
BOOST_FUNCTION_FUNCTION& BOOST_FUNCTION_FUNCTION&
@ -841,25 +831,6 @@ namespace boost {
return *this; return *this;
} }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Move assignment from another BOOST_FUNCTION_FUNCTION
BOOST_FUNCTION_FUNCTION& operator=(BOOST_FUNCTION_FUNCTION&& f)
{
if (&f == this)
return *this;
this->clear();
BOOST_TRY {
this->move_assign(f);
} BOOST_CATCH (...) {
vtable = 0;
BOOST_RETHROW;
}
BOOST_CATCH_END
return *this;
}
#endif
void swap(BOOST_FUNCTION_FUNCTION& other) void swap(BOOST_FUNCTION_FUNCTION& other)
{ {
if (&other == this) if (&other == this)
@ -916,15 +887,15 @@ namespace boost {
template<typename Functor> template<typename Functor>
void assign_to(Functor f) void assign_to(Functor f)
{ {
using boost::detail::function::vtable_base; using detail::function::vtable_base;
typedef typename boost::detail::function::get_function_tag<Functor>::type tag; typedef typename detail::function::get_function_tag<Functor>::type tag;
typedef boost::detail::function::BOOST_FUNCTION_GET_INVOKER<tag> get_invoker; typedef detail::function::BOOST_FUNCTION_GET_INVOKER<tag> get_invoker;
typedef typename get_invoker:: typedef typename get_invoker::
template apply<Functor, R BOOST_FUNCTION_COMMA template apply<Functor, R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS> BOOST_FUNCTION_TEMPLATE_ARGS>
handler_type; handler_type;
typedef typename handler_type::invoker_type invoker_type; typedef typename handler_type::invoker_type invoker_type;
typedef typename handler_type::manager_type manager_type; typedef typename handler_type::manager_type manager_type;
@ -932,34 +903,33 @@ namespace boost {
// static initialization. Otherwise, we will have a race // static initialization. Otherwise, we will have a race
// condition here in multi-threaded code. See // condition here in multi-threaded code. See
// http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/. // http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/.
static const vtable_type stored_vtable = static const vtable_type stored_vtable =
{ { &manager_type::manage }, &invoker_type::invoke }; { { &manager_type::manage }, &invoker_type::invoke };
if (stored_vtable.assign_to(f, functor)) { if (stored_vtable.assign_to(f, functor)) {
std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base); std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
// coverity[pointless_expression]: suppress coverity warnings on apparant if(const).
if (boost::has_trivial_copy_constructor<Functor>::value && if (boost::has_trivial_copy_constructor<Functor>::value &&
boost::has_trivial_destructor<Functor>::value && boost::has_trivial_destructor<Functor>::value &&
boost::detail::function::function_allows_small_object_optimization<Functor>::value) detail::function::function_allows_small_object_optimization<Functor>::value)
value |= static_cast<std::size_t>(0x01); value |= static_cast<size_t>(0x01);
vtable = reinterpret_cast<boost::detail::function::vtable_base *>(value); vtable = reinterpret_cast<detail::function::vtable_base *>(value);
} else } else
vtable = 0; vtable = 0;
} }
template<typename Functor,typename Allocator> template<typename Functor,typename Allocator>
void assign_to_a(Functor f,Allocator a) void assign_to_a(Functor f,Allocator a)
{ {
using boost::detail::function::vtable_base; using detail::function::vtable_base;
typedef typename boost::detail::function::get_function_tag<Functor>::type tag; typedef typename detail::function::get_function_tag<Functor>::type tag;
typedef boost::detail::function::BOOST_FUNCTION_GET_INVOKER<tag> get_invoker; typedef detail::function::BOOST_FUNCTION_GET_INVOKER<tag> get_invoker;
typedef typename get_invoker:: typedef typename get_invoker::
template apply_a<Functor, R BOOST_FUNCTION_COMMA template apply_a<Functor, R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS, BOOST_FUNCTION_TEMPLATE_ARGS,
Allocator> Allocator>
handler_type; handler_type;
typedef typename handler_type::invoker_type invoker_type; typedef typename handler_type::invoker_type invoker_type;
typedef typename handler_type::manager_type manager_type; typedef typename handler_type::manager_type manager_type;
@ -970,23 +940,22 @@ namespace boost {
static const vtable_type stored_vtable = static const vtable_type stored_vtable =
{ { &manager_type::manage }, &invoker_type::invoke }; { { &manager_type::manage }, &invoker_type::invoke };
if (stored_vtable.assign_to_a(f, functor, a)) { if (stored_vtable.assign_to_a(f, functor, a)) {
std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base); std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
// coverity[pointless_expression]: suppress coverity warnings on apparant if(const).
if (boost::has_trivial_copy_constructor<Functor>::value && if (boost::has_trivial_copy_constructor<Functor>::value &&
boost::has_trivial_destructor<Functor>::value && boost::has_trivial_destructor<Functor>::value &&
boost::detail::function::function_allows_small_object_optimization<Functor>::value) detail::function::function_allows_small_object_optimization<Functor>::value)
value |= static_cast<std::size_t>(0x01); value |= static_cast<std::size_t>(0x01);
vtable = reinterpret_cast<boost::detail::function::vtable_base *>(value); vtable = reinterpret_cast<detail::function::vtable_base *>(value);
} else } else
vtable = 0; vtable = 0;
} }
// Moves the value from the specified argument to *this. If the argument // Moves the value from the specified argument to *this. If the argument
// has its function object allocated on the heap, move_assign will pass // has its function object allocated on the heap, move_assign will pass
// its buffer to *this, and set the argument's buffer pointer to NULL. // its buffer to *this, and set the argument's buffer pointer to NULL.
void move_assign(BOOST_FUNCTION_FUNCTION& f) void move_assign(BOOST_FUNCTION_FUNCTION& f)
{ {
if (&f == this) if (&f == this)
return; return;
@ -1064,8 +1033,9 @@ public:
template<typename Functor> template<typename Functor>
function(Functor f function(Functor f
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
,typename boost::enable_if_c< ,typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
int>::type = 0 int>::type = 0
#endif #endif
) : ) :
@ -1075,8 +1045,9 @@ public:
template<typename Functor,typename Allocator> template<typename Functor,typename Allocator>
function(Functor f, Allocator a function(Functor f, Allocator a
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
,typename boost::enable_if_c< ,typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
int>::type = 0 int>::type = 0
#endif #endif
) : ) :
@ -1092,30 +1063,17 @@ public:
function(const base_type& f) : base_type(static_cast<const base_type&>(f)){} function(const base_type& f) : base_type(static_cast<const base_type&>(f)){}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Move constructors
function(self_type&& f): base_type(static_cast<base_type&&>(f)){}
function(base_type&& f): base_type(static_cast<base_type&&>(f)){}
#endif
self_type& operator=(const self_type& f) self_type& operator=(const self_type& f)
{ {
self_type(f).swap(*this); self_type(f).swap(*this);
return *this; return *this;
} }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
self_type& operator=(self_type&& f)
{
self_type(static_cast<self_type&&>(f)).swap(*this);
return *this;
}
#endif
template<typename Functor> template<typename Functor>
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
typename boost::enable_if_c< typename enable_if_c<
!(is_integral<Functor>::value), (boost::type_traits::ice_not<
(is_integral<Functor>::value)>::value),
self_type&>::type self_type&>::type
#else #else
self_type& self_type&
@ -1139,14 +1097,6 @@ public:
self_type(f).swap(*this); self_type(f).swap(*this);
return *this; return *this;
} }
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
self_type& operator=(base_type&& f)
{
self_type(static_cast<base_type&&>(f)).swap(*this);
return *this;
}
#endif
}; };
#undef BOOST_FUNCTION_PARTIAL_SPEC #undef BOOST_FUNCTION_PARTIAL_SPEC
@ -1175,9 +1125,6 @@ public:
#undef BOOST_FUNCTION_TEMPLATE_ARGS #undef BOOST_FUNCTION_TEMPLATE_ARGS
#undef BOOST_FUNCTION_PARMS #undef BOOST_FUNCTION_PARMS
#undef BOOST_FUNCTION_PARM #undef BOOST_FUNCTION_PARM
#ifdef BOOST_FUNCTION_ARG
# undef BOOST_FUNCTION_ARG
#endif
#undef BOOST_FUNCTION_ARGS #undef BOOST_FUNCTION_ARGS
#undef BOOST_FUNCTION_ARG_TYPE #undef BOOST_FUNCTION_ARG_TYPE
#undef BOOST_FUNCTION_ARG_TYPES #undef BOOST_FUNCTION_ARG_TYPES
@ -1186,4 +1133,4 @@ public:
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
# pragma warning( pop ) # pragma warning( pop )
#endif #endif

View File

@ -1,18 +0,0 @@
{
"key": "function",
"name": "Function",
"authors": [
"Doug Gregor"
],
"description": "Function object wrappers for deferred calls or callbacks.",
"std": [
"tr1"
],
"category": [
"Function-objects",
"Programming"
],
"maintainers": [
"Douglas Gregor <dgregor -at- cs.indiana.edu>"
]
}

View File

@ -21,8 +21,6 @@ import testing ;
: :
[ run libs/function/test/function_test.cpp : : : : lib_function_test ] [ run libs/function/test/function_test.cpp : : : : lib_function_test ]
[ run libs/function/test/function_test.cpp : : : <rtti>off : lib_function_test_no_rtti ]
[ run libs/function/test/function_n_test.cpp : : : : ] [ run libs/function/test/function_n_test.cpp : : : : ]
[ run libs/function/test/allocator_test.cpp ../../../libs/test/build//boost_test_exec_monitor : : : : ] [ run libs/function/test/allocator_test.cpp ../../../libs/test/build//boost_test_exec_monitor : : : : ]
@ -63,8 +61,6 @@ import testing ;
[ run libs/function/test/nothrow_swap.cpp : : : : ] [ run libs/function/test/nothrow_swap.cpp : : : : ]
[ run libs/function/test/rvalues_test.cpp : : : : ]
[ compile libs/function/test/function_typeof_test.cpp ] [ compile libs/function/test/function_typeof_test.cpp ]
; ;
} }

View File

@ -690,95 +690,6 @@ static void test_call()
test_call_cref(std::plus<int>()); test_call_cref(std::plus<int>());
} }
struct big_aggregating_structure {
int disable_small_objects_optimizations[32];
big_aggregating_structure()
{
++ global_int;
}
big_aggregating_structure(const big_aggregating_structure&)
{
++ global_int;
}
~big_aggregating_structure()
{
-- global_int;
}
void operator()()
{
++ global_int;
}
void operator()(int)
{
++ global_int;
}
};
template <class FunctionT>
static void test_move_semantics()
{
typedef FunctionT f1_type;
big_aggregating_structure obj;
f1_type f1 = obj;
global_int = 0;
f1();
BOOST_CHECK(!f1.empty());
BOOST_CHECK(global_int == 1);
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
// Testing rvalue constructors
f1_type f2(static_cast<f1_type&&>(f1));
BOOST_CHECK(f1.empty());
BOOST_CHECK(!f2.empty());
BOOST_CHECK(global_int == 1);
f2();
BOOST_CHECK(global_int == 2);
f1_type f3(static_cast<f1_type&&>(f2));
BOOST_CHECK(f1.empty());
BOOST_CHECK(f2.empty());
BOOST_CHECK(!f3.empty());
BOOST_CHECK(global_int == 2);
f3();
BOOST_CHECK(global_int == 3);
// Testing move assignment
f1_type f4;
BOOST_CHECK(f4.empty());
f4 = static_cast<f1_type&&>(f3);
BOOST_CHECK(f1.empty());
BOOST_CHECK(f2.empty());
BOOST_CHECK(f3.empty());
BOOST_CHECK(!f4.empty());
BOOST_CHECK(global_int == 3);
f4();
BOOST_CHECK(global_int == 4);
// Testing self move assignment
f4 = static_cast<f1_type&&>(f4);
BOOST_CHECK(!f4.empty());
BOOST_CHECK(global_int == 4);
// Testing, that no memory leaked when assigning to nonempty function
f4 = obj;
BOOST_CHECK(!f4.empty());
BOOST_CHECK(global_int == 4);
f1_type f5 = obj;
BOOST_CHECK(global_int == 5);
f4 = static_cast<f1_type&&>(f5);
BOOST_CHECK(global_int == 4);
#endif
}
int test_main(int, char* []) int test_main(int, char* [])
{ {
test_zero_args(); test_zero_args();
@ -791,8 +702,6 @@ int test_main(int, char* [])
test_exception(); test_exception();
test_implicit(); test_implicit();
test_call(); test_call();
test_move_semantics<function<void()> >();
test_move_semantics<boost::function0<void> >();
return 0; return 0;
} }

View File

@ -14,32 +14,24 @@
#include <iostream> #include <iostream>
#include <functional> #include <functional>
struct Y {
Y(int y = 0) : y_(y) {}
bool operator==(const Y& rhs) { return y_ == rhs.y_; }
private:
int y_;
};
struct X { struct X {
int foo(int); int foo(int);
Y& foo2(Y&) const; std::ostream& foo2(std::ostream&) const;
}; };
int X::foo(int x) { return -x; } int X::foo(int x) { return -x; }
Y& X::foo2(Y& x) const { return x; } std::ostream& X::foo2(std::ostream& x) const { return x; }
int main() int main()
{ {
boost::function<int (X*, int)> f; boost::function<int (X*, int)> f;
boost::function<Y& (X*, Y&)> f2; boost::function<std::ostream& (X*, std::ostream&)> f2;
Y y1;
f = &X::foo; f = &X::foo;
f2 = &X::foo2; f2 = &X::foo2;
X x; X x;
BOOST_TEST(f(&x, 5) == -5); BOOST_TEST(f(&x, 5) == -5);
BOOST_TEST(f2(&x, boost::ref(y1)) == y1); BOOST_TEST(f2(&x, boost::ref(std::cout)) == std::cout);
return ::boost::report_errors(); return ::boost::report_errors();
} }

View File

@ -14,32 +14,24 @@
#include <iostream> #include <iostream>
#include <functional> #include <functional>
struct Y {
Y(int y = 0) : y_(y) {}
bool operator==(const Y& rhs) { return y_ == rhs.y_; }
private:
int y_;
};
struct X { struct X {
int foo(int); int foo(int);
Y& foo2(Y&) const; std::ostream& foo2(std::ostream&) const;
}; };
int X::foo(int x) { return -x; } int X::foo(int x) { return -x; }
Y& X::foo2(Y& x) const { return x; } std::ostream& X::foo2(std::ostream& x) const { return x; }
int main() int main()
{ {
boost::function2<int, X*, int> f; boost::function2<int, X*, int> f;
boost::function2<Y&, X*, Y&> f2; boost::function2<std::ostream&, X*, std::ostream&> f2;
Y y1;
f = &X::foo; f = &X::foo;
f2 = &X::foo2; f2 = &X::foo2;
X x; X x;
BOOST_TEST(f(&x, 5) == -5); BOOST_TEST(f(&x, 5) == -5);
BOOST_TEST(f2(&x, boost::ref(y1)) == y1); BOOST_TEST(f2(&x, boost::ref(std::cout)) == std::cout);
return ::boost::report_errors(); return ::boost::report_errors();
} }

View File

@ -1,106 +0,0 @@
// Copyright 2014 Antony Polukhin.
//
// Distributed under 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 <iostream>
#include <cstdlib>
#include <boost/test/minimal.hpp>
#include <boost/function.hpp>
#include <boost/move/move.hpp>
class only_movable {
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable)
int value_;
bool moved_;
public:
only_movable(BOOST_RV_REF(only_movable) x)
: value_(x.value_)
, moved_(false)
{
x.moved_ = true;
}
only_movable& operator=(BOOST_RV_REF(only_movable) x) {
value_ = x.value_;
x.moved_ = true;
moved_ = false;
return *this;
}
explicit only_movable(int value = 0) : value_(value), moved_(false) {}
int get_value() const { return value_; }
bool is_moved() const { return moved_; }
};
int one(BOOST_RV_REF(only_movable) v) { return v.get_value(); }
only_movable two(BOOST_RV_REF(only_movable) t) {
only_movable t1 = boost::move(t);
return BOOST_MOVE_RET(only_movable, t1);
}
only_movable two_sum(BOOST_RV_REF(only_movable) t1, BOOST_RV_REF(only_movable) t2) {
only_movable ret(t1.get_value() + t2.get_value());
return BOOST_MOVE_RET(only_movable, ret);
}
struct sum_struct {
only_movable operator()(BOOST_RV_REF(only_movable) t1, BOOST_RV_REF(only_movable) t2) const {
only_movable ret(t1.get_value() + t2.get_value());
return BOOST_MOVE_RET(only_movable, ret);
}
};
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
int three(std::string&&) { return 1; }
std::string&& four(std::string&& s) { return boost::move(s); }
#endif
int test_main(int, char*[])
{
using boost::function;
function <int(BOOST_RV_REF(only_movable))> f1 = one;
only_movable om1(1);
BOOST_CHECK(f1(boost::move(om1)) == 1);
function <only_movable(BOOST_RV_REF(only_movable))> f2 = two;
only_movable om2(2);
only_movable om2_2 = f2(boost::move(om2));
BOOST_CHECK(om2_2.get_value() == 2);
BOOST_CHECK(om2.is_moved());
{
function <only_movable(BOOST_RV_REF(only_movable), BOOST_RV_REF(only_movable))> f2_sum = two_sum;
only_movable om1_sum(1), om2_sum(2);
only_movable om2_sum_2 = f2_sum(boost::move(om1_sum), boost::move(om2_sum));
BOOST_CHECK(om2_sum_2.get_value() == 3);
}
{
sum_struct s;
function <only_movable(BOOST_RV_REF(only_movable), BOOST_RV_REF(only_movable))> f2_sum = s;
only_movable om1_sum(1), om2_sum(2);
only_movable om2_sum_2 = f2_sum(boost::move(om1_sum), boost::move(om2_sum));
BOOST_CHECK(om2_sum_2.get_value() == 3);
}
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
function <int(std::string&&)> f3 = three;
function <std::string&& (std::string&& s)> f4 = four;
f3(std::string("Hello"));
BOOST_CHECK(f4(std::string("world")) == "world");
#endif
return 0;
}