forked from boostorg/function
Compare commits
10 Commits
svn-branch
...
svn-branch
Author | SHA1 | Date | |
---|---|---|---|
98a207958d | |||
75890fea53 | |||
da259e8dce | |||
2fe4cc253f | |||
f379ef8532 | |||
ea18f5777b | |||
d5a86a2d52 | |||
e3dfa7268a | |||
bacb5d6752 | |||
04040ae566 |
@ -13,6 +13,26 @@
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
|
||||
<listitem><para><bold>Version 1.37.0</bold>: </para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem><para>Improved the performance of Boost.Function's
|
||||
swap() operation for large function objects. Original patch
|
||||
contributed by Niels Dekker.</para></listitem>
|
||||
|
||||
<listitem><para>Added a new header <boost/function/function_typeof.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects.</para></listitem>
|
||||
|
||||
<listitem><para>Added a new header <boost/function/function_fwd.hpp> that provides support for using the Boost.Typeof library on Boost.Function objects.</para></listitem>
|
||||
|
||||
<listitem><para>The <methodname alt="boost::function::target">target</methodname>()
|
||||
function now respects the cv-qualifiers of function objects
|
||||
stored by reference
|
||||
(using <classname>boost::reference_wrapper</classname>), such
|
||||
that a reference to a <code>const</code> function object cannot
|
||||
be accessed as a reference to a non-<code>const</code> function
|
||||
object.</para></listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem><para><bold>Version 1.36.0</bold>: </para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem><para>Boost.Function now implements allocator support
|
||||
|
@ -24,7 +24,7 @@
|
||||
<para> And, of course, function pointers have several advantages over Boost.Function:
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem><para> Function pointers are smaller (the size of one pointer instead of three) </para></listitem>
|
||||
<listitem><para> Function pointers are smaller (the size of one pointer instead of four or more) </para></listitem>
|
||||
<listitem><para> Function pointers are faster (Boost.Function may require two calls through function pointers) </para></listitem>
|
||||
<listitem><para> Function pointers are backward-compatible with C libraries.</para></listitem>
|
||||
<listitem><para> More readable error messages. </para></listitem>
|
||||
@ -37,12 +37,12 @@
|
||||
|
||||
<section>
|
||||
<title>Function object wrapper size</title>
|
||||
<para> Function object wrappers will be the size of two function pointers plus one function pointer or data pointer (whichever is larger). On common 32-bit platforms, this amounts to 12 bytes per wrapper. Additionally, the function object target will be allocated on the heap.</para>
|
||||
<para> Function object wrappers will be the size of a struct containing a member function pointer and two data pointers. The actual size can vary significantly depending on the underlying platform; on 32-bit Mac OS X with GCC, this amounts to 16 bytes, while it is 32 bytes Windows with Visual C++. Additionally, the function object target may be allocated on the heap, if it cannot be placed into the small-object buffer in the <code>boost::function</code> object.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Copying efficiency</title>
|
||||
<para> Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using <computeroutput>ref</computeroutput>) if the cost of this cloning becomes prohibitive.</para>
|
||||
<para> Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using <computeroutput>ref</computeroutput>) if the cost of this cloning becomes prohibitive. Small function objects can be stored within the <code>boost::function</code> object itself, improving copying efficiency.</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
@ -18,8 +18,11 @@
|
||||
#include <typeinfo>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_volatile.hpp>
|
||||
#include <boost/type_traits/composite_traits.hpp>
|
||||
#include <boost/type_traits/ice.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
@ -30,6 +33,7 @@
|
||||
# include "boost/mpl/bool.hpp"
|
||||
#endif
|
||||
#include <boost/function_equal.hpp>
|
||||
#include <boost/function/function_fwd.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning( push )
|
||||
@ -63,22 +67,7 @@
|
||||
# define BOOST_FUNCTION_TARGET_FIX(x)
|
||||
#endif // not MSVC
|
||||
|
||||
#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
|
||||
// Work around a compiler bug.
|
||||
// boost::python::objects::function has to be seen by the compiler before the
|
||||
// boost::function class template.
|
||||
namespace boost { namespace python { namespace objects {
|
||||
class function;
|
||||
}}}
|
||||
#endif
|
||||
|
||||
#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
|
||||
|| defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
|
||||
|| !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
|
||||
# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
|
||||
#endif
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
|
||||
# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
|
||||
typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
|
||||
(::boost::is_integral<Functor>::value)>::value), \
|
||||
@ -92,22 +81,6 @@ namespace boost { namespace python { namespace objects {
|
||||
Type>::type
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
||||
namespace boost {
|
||||
|
||||
template<typename Signature>
|
||||
class function;
|
||||
|
||||
template<typename Signature>
|
||||
inline void swap(function<Signature>& f1,
|
||||
function<Signature>& f2)
|
||||
{
|
||||
f1.swap(f2);
|
||||
}
|
||||
|
||||
} // end namespace boost
|
||||
#endif // have partial specialization
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace function {
|
||||
@ -122,11 +95,18 @@ namespace boost {
|
||||
union function_buffer
|
||||
{
|
||||
// For pointers to function objects
|
||||
void* obj_ptr;
|
||||
mutable void* obj_ptr;
|
||||
|
||||
// For pointers to std::type_info objects
|
||||
// (get_functor_type_tag, check_functor_type_tag).
|
||||
const void* const_obj_ptr;
|
||||
struct type_t {
|
||||
// (get_functor_type_tag, check_functor_type_tag).
|
||||
const BOOST_FUNCTION_STD_NS::type_info* type;
|
||||
|
||||
// Whether the type is const-qualified.
|
||||
bool const_qualified;
|
||||
// Whether the type is volatile-qualified.
|
||||
bool volatile_qualified;
|
||||
} type;
|
||||
|
||||
// For function pointers of all kinds
|
||||
mutable void (*func_ptr)();
|
||||
@ -137,6 +117,14 @@ namespace boost {
|
||||
void* obj_ptr;
|
||||
} bound_memfunc_ptr;
|
||||
|
||||
// For references to function objects. We explicitly keep
|
||||
// track of the cv-qualifiers on the object referenced.
|
||||
struct obj_ref_t {
|
||||
mutable void* obj_ptr;
|
||||
bool is_const_qualified;
|
||||
bool is_volatile_qualified;
|
||||
} obj_ref;
|
||||
|
||||
// To relax aliasing constraints
|
||||
mutable char data;
|
||||
};
|
||||
@ -168,6 +156,7 @@ namespace boost {
|
||||
// The operation type to perform on the given functor/function pointer
|
||||
enum functor_manager_operation_type {
|
||||
clone_functor_tag,
|
||||
move_functor_tag,
|
||||
destroy_functor_tag,
|
||||
check_functor_type_tag,
|
||||
get_functor_type_tag
|
||||
@ -209,29 +198,40 @@ namespace boost {
|
||||
{
|
||||
switch (op) {
|
||||
case clone_functor_tag:
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
|
||||
return;
|
||||
|
||||
case move_functor_tag:
|
||||
out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
|
||||
in_buffer.obj_ref.obj_ptr = 0;
|
||||
return;
|
||||
|
||||
case destroy_functor_tag:
|
||||
out_buffer.obj_ptr = 0;
|
||||
out_buffer.obj_ref.obj_ptr = 0;
|
||||
return;
|
||||
|
||||
case check_functor_type_tag:
|
||||
{
|
||||
// DPG TBD: Since we're only storing a pointer, it's
|
||||
// possible that the user could ask for a base class or
|
||||
// derived class. Is that okay?
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
||||
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type
|
||||
= *out_buffer.type.type;
|
||||
|
||||
// Check whether we have the same type. We can add
|
||||
// cv-qualifiers, but we can't take them away.
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
|
||||
&& (!in_buffer.obj_ref.is_const_qualified
|
||||
|| out_buffer.type.const_qualified)
|
||||
&& (!in_buffer.obj_ref.is_volatile_qualified
|
||||
|| out_buffer.type.volatile_qualified))
|
||||
out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
|
||||
else
|
||||
out_buffer.obj_ptr = 0;
|
||||
}
|
||||
return;
|
||||
|
||||
case get_functor_type_tag:
|
||||
out_buffer.const_obj_ptr = &typeid(F);
|
||||
out_buffer.type.type = &typeid(F);
|
||||
out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
|
||||
out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -277,15 +277,22 @@ namespace boost {
|
||||
{
|
||||
if (op == clone_functor_tag)
|
||||
out_buffer.func_ptr = in_buffer.func_ptr;
|
||||
else if (op == destroy_functor_tag)
|
||||
else if (op == move_functor_tag) {
|
||||
out_buffer.func_ptr = in_buffer.func_ptr;
|
||||
in_buffer.func_ptr = 0;
|
||||
} else if (op == destroy_functor_tag)
|
||||
out_buffer.func_ptr = 0;
|
||||
else /* op == check_functor_type_tag */ {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
||||
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
||||
else if (op == check_functor_type_tag) {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type
|
||||
= *out_buffer.type.type;
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
||||
out_buffer.obj_ptr = &in_buffer.func_ptr;
|
||||
else
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == get_functor_type_tag */ {
|
||||
out_buffer.type.type = &typeid(Functor);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,20 +301,28 @@ namespace boost {
|
||||
manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
|
||||
functor_manager_operation_type op)
|
||||
{
|
||||
if (op == clone_functor_tag) {
|
||||
if (op == clone_functor_tag || op == move_functor_tag) {
|
||||
const functor_type* in_functor =
|
||||
reinterpret_cast<const functor_type*>(&in_buffer.data);
|
||||
new ((void*)&out_buffer.data) functor_type(*in_functor);
|
||||
|
||||
if (op == move_functor_tag) {
|
||||
reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
|
||||
}
|
||||
} else if (op == destroy_functor_tag) {
|
||||
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
|
||||
reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
|
||||
} else /* op == check_functor_type_tag */ {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
||||
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
||||
} else if (op == check_functor_type_tag) {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type
|
||||
= *out_buffer.type.type;
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
||||
out_buffer.obj_ptr = &in_buffer.data;
|
||||
else
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == get_functor_type_tag */ {
|
||||
out_buffer.type.type = &typeid(Functor);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -347,19 +362,26 @@ namespace boost {
|
||||
(const functor_type*)(in_buffer.obj_ptr);
|
||||
functor_type* new_f = new functor_type(*f);
|
||||
out_buffer.obj_ptr = new_f;
|
||||
} else if (op == move_functor_tag) {
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
in_buffer.obj_ptr = 0;
|
||||
} else if (op == destroy_functor_tag) {
|
||||
/* Cast from the void pointer to the functor pointer type */
|
||||
functor_type* f =
|
||||
static_cast<functor_type*>(out_buffer.obj_ptr);
|
||||
delete f;
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == check_functor_type_tag */ {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
||||
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
||||
} else if (op == check_functor_type_tag) {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type
|
||||
= *out_buffer.type.type;
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
else
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == get_functor_type_tag */ {
|
||||
out_buffer.type.type = &typeid(Functor);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,7 +406,9 @@ namespace boost {
|
||||
typedef typename get_function_tag<functor_type>::type tag_type;
|
||||
switch (op) {
|
||||
case get_functor_type_tag:
|
||||
out_buffer.const_obj_ptr = &typeid(functor_type);
|
||||
out_buffer.type.type = &typeid(functor_type);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
return;
|
||||
|
||||
default:
|
||||
@ -432,28 +456,35 @@ namespace boost {
|
||||
// can't do the static_cast that we should do.
|
||||
const functor_wrapper_type* f =
|
||||
(const functor_wrapper_type*)(in_buffer.obj_ptr);
|
||||
wrapper_allocator_type wrapper_allocator(static_cast<wrapper_allocator_type const &>(*f));
|
||||
wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
|
||||
wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
|
||||
wrapper_allocator.construct(copy, *f);
|
||||
|
||||
// Get back to the original pointer type
|
||||
functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
|
||||
out_buffer.obj_ptr = new_f;
|
||||
} else if (op == move_functor_tag) {
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
in_buffer.obj_ptr = 0;
|
||||
} else if (op == destroy_functor_tag) {
|
||||
/* Cast from the void pointer to the functor_wrapper_type */
|
||||
functor_wrapper_type* victim =
|
||||
static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
|
||||
wrapper_allocator_type wrapper_allocator(static_cast<wrapper_allocator_type const &>(*victim));
|
||||
wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
|
||||
wrapper_allocator.destroy(victim);
|
||||
wrapper_allocator.deallocate(victim,1);
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == check_functor_type_tag */ {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type =
|
||||
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
|
||||
} else if (op == check_functor_type_tag) {
|
||||
const BOOST_FUNCTION_STD_NS::type_info& check_type
|
||||
= *out_buffer.type.type;
|
||||
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
|
||||
out_buffer.obj_ptr = in_buffer.obj_ptr;
|
||||
else
|
||||
out_buffer.obj_ptr = 0;
|
||||
} else /* op == get_functor_type_tag */ {
|
||||
out_buffer.type.type = &typeid(Functor);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,7 +509,9 @@ namespace boost {
|
||||
typedef typename get_function_tag<functor_type>::type tag_type;
|
||||
switch (op) {
|
||||
case get_functor_type_tag:
|
||||
out_buffer.const_obj_ptr = &typeid(functor_type);
|
||||
out_buffer.type.type = &typeid(functor_type);
|
||||
out_buffer.type.const_qualified = false;
|
||||
out_buffer.type.volatile_qualified = false;
|
||||
return;
|
||||
|
||||
default:
|
||||
@ -586,7 +619,7 @@ public:
|
||||
|
||||
detail::function::function_buffer type;
|
||||
vtable->manager(functor, type, detail::function::get_functor_type_tag);
|
||||
return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
|
||||
return *type.type.type;
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
@ -595,7 +628,9 @@ public:
|
||||
if (!vtable) return 0;
|
||||
|
||||
detail::function::function_buffer type_result;
|
||||
type_result.const_obj_ptr = &typeid(Functor);
|
||||
type_result.type.type = &typeid(Functor);
|
||||
type_result.type.const_qualified = is_const<Functor>::value;
|
||||
type_result.type.volatile_qualified = is_volatile<Functor>::value;
|
||||
vtable->manager(functor, type_result,
|
||||
detail::function::check_functor_type_tag);
|
||||
return static_cast<Functor*>(type_result.obj_ptr);
|
||||
@ -611,7 +646,9 @@ public:
|
||||
if (!vtable) return 0;
|
||||
|
||||
detail::function::function_buffer type_result;
|
||||
type_result.const_obj_ptr = &typeid(Functor);
|
||||
type_result.type.type = &typeid(Functor);
|
||||
type_result.type.const_qualified = true;
|
||||
type_result.type.volatile_qualified = is_volatile<Functor>::value;
|
||||
vtable->manager(functor, type_result,
|
||||
detail::function::check_functor_type_tag);
|
||||
// GCC 2.95.3 gets the CV qualifiers wrong here, so we
|
||||
|
70
include/boost/function/function_fwd.hpp
Normal file
70
include/boost/function/function_fwd.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
// Boost.Function library
|
||||
// Copyright (C) Douglas Gregor 2008
|
||||
//
|
||||
// Use, modification and distribution is subject to the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// For more information, see http://www.boost.org
|
||||
#ifndef BOOST_FUNCTION_FWD_HPP
|
||||
#define BOOST_FUNCTION_FWD_HPP
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
|
||||
// Work around a compiler bug.
|
||||
// boost::python::objects::function has to be seen by the compiler before the
|
||||
// boost::function class template.
|
||||
namespace boost { namespace python { namespace objects {
|
||||
class function;
|
||||
}}}
|
||||
#endif
|
||||
|
||||
#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
|
||||
|| defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
|
||||
|| !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
|
||||
# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
class bad_function_call;
|
||||
|
||||
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
||||
// Preferred syntax
|
||||
template<typename Signature> class function;
|
||||
|
||||
template<typename Signature>
|
||||
inline void swap(function<Signature>& f1, function<Signature>& f2)
|
||||
{
|
||||
f1.swap(f2);
|
||||
}
|
||||
#endif // have partial specialization
|
||||
|
||||
// Portable syntax
|
||||
template<typename R> class function0;
|
||||
template<typename R, typename T1> class function1;
|
||||
template<typename R, typename T1, typename T2> class function2;
|
||||
template<typename R, typename T1, typename T2, typename T3> class function3;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
class function4;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5>
|
||||
class function5;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6>
|
||||
class function6;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7>
|
||||
class function7;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8>
|
||||
class function8;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8, typename T9>
|
||||
class function9;
|
||||
template<typename R, typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8, typename T9,
|
||||
typename T10>
|
||||
class function10;
|
||||
}
|
||||
|
||||
#endif
|
@ -516,11 +516,9 @@ namespace boost {
|
||||
function_buffer& functor, function_obj_ref_tag)
|
||||
{
|
||||
if (!boost::detail::function::has_empty_target(f.get_pointer())) {
|
||||
// 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();
|
||||
functor.obj_ref.obj_ptr = (void *)f.get_pointer();
|
||||
functor.obj_ref.is_const_qualified = is_const<FunctionObj>::value;
|
||||
functor.obj_ref.is_volatile_qualified = is_volatile<FunctionObj>::value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -729,9 +727,10 @@ namespace boost {
|
||||
if (&other == this)
|
||||
return;
|
||||
|
||||
BOOST_FUNCTION_FUNCTION tmp = *this;
|
||||
*this = other;
|
||||
other = tmp;
|
||||
BOOST_FUNCTION_FUNCTION tmp;
|
||||
tmp.move_assign(*this);
|
||||
this->move_assign(other);
|
||||
other.move_assign(tmp);
|
||||
}
|
||||
|
||||
// Clear out a target, if there is one
|
||||
@ -786,6 +785,33 @@ namespace boost {
|
||||
if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable;
|
||||
else vtable = 0;
|
||||
}
|
||||
|
||||
// Moves the value from the specified argument to *this. If the argument
|
||||
// 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.
|
||||
void move_assign(BOOST_FUNCTION_FUNCTION& f)
|
||||
{
|
||||
if (&f == this)
|
||||
return;
|
||||
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
try {
|
||||
#endif
|
||||
if (!f.empty()) {
|
||||
this->vtable = f.vtable;
|
||||
f.vtable->manager(f.functor, this->functor,
|
||||
boost::detail::function::move_functor_tag);
|
||||
f.vtable = 0;
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
} catch (...) {
|
||||
vtable = 0;
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS>
|
||||
|
45
include/boost/function/function_typeof.hpp
Normal file
45
include/boost/function/function_typeof.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Boost.Function library - Typeof support
|
||||
// Copyright (C) Douglas Gregor 2008
|
||||
//
|
||||
// Use, modification and distribution is subject to the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// For more information, see http://www.boost.org
|
||||
#ifndef BOOST_FUNCTION_TYPEOF_HPP
|
||||
#define BOOST_FUNCTION_TYPEOF_HPP
|
||||
#include <boost/function/function_fwd.hpp>
|
||||
#include <boost/typeof/typeof.hpp>
|
||||
|
||||
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
|
||||
|
||||
BOOST_TYPEOF_REGISTER_TYPE(boost::bad_function_call)
|
||||
|
||||
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function, (typename))
|
||||
#endif
|
||||
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function0, (typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function1, (typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function2, (typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function3,
|
||||
(typename)(typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function4,
|
||||
(typename)(typename)(typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function5,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function6,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function7,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename)(typename)
|
||||
(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function8,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename)(typename)
|
||||
(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function9,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename)(typename)
|
||||
(typename)(typename)(typename))
|
||||
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function10,
|
||||
(typename)(typename)(typename)(typename)(typename)(typename)(typename)
|
||||
(typename)(typename)(typename)(typename))
|
||||
#endif
|
@ -58,6 +58,9 @@ import testing ;
|
||||
|
||||
[ run libs/function/test/contains2_test.cpp : : : : ]
|
||||
|
||||
[ run libs/function/test/nothrow_swap.cpp : : : : ]
|
||||
|
||||
[ compile libs/function/test/function_typeof_test.cpp ]
|
||||
;
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,15 @@ static void target_test()
|
||||
BOOST_CHECK(!f.target<int (*)()>());
|
||||
BOOST_CHECK(f.target<Seventeen>());
|
||||
BOOST_CHECK(f.target<Seventeen>() == &this_seventeen);
|
||||
|
||||
const Seventeen const_seventeen = this_seventeen;
|
||||
f = boost::ref(const_seventeen);
|
||||
BOOST_CHECK(!f.target<int (*)()>());
|
||||
BOOST_CHECK(f.target<const Seventeen>());
|
||||
BOOST_CHECK(f.target<const Seventeen>() == &const_seventeen);
|
||||
BOOST_CHECK(f.target<const volatile Seventeen>());
|
||||
BOOST_CHECK(!f.target<Seventeen>());
|
||||
BOOST_CHECK(!f.target<volatile Seventeen>());
|
||||
}
|
||||
|
||||
static void equal_test()
|
||||
|
@ -636,6 +636,54 @@ test_ref()
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned construction_count = 0;
|
||||
static unsigned destruction_count = 0;
|
||||
|
||||
struct MySmallFunctor {
|
||||
MySmallFunctor() { ++construction_count; }
|
||||
MySmallFunctor(const MySmallFunctor &) { ++construction_count; }
|
||||
~MySmallFunctor() { ++destruction_count; }
|
||||
int operator()() { return 0; }
|
||||
};
|
||||
|
||||
struct MyLargeFunctor {
|
||||
MyLargeFunctor() { ++construction_count; }
|
||||
MyLargeFunctor(const MyLargeFunctor &) { ++construction_count; }
|
||||
~MyLargeFunctor() { ++destruction_count; }
|
||||
int operator()() { return 0; }
|
||||
|
||||
float data[128];
|
||||
};
|
||||
|
||||
void test_construct_destroy_count()
|
||||
{
|
||||
{
|
||||
boost::function0<int> f;
|
||||
boost::function0<int> g;
|
||||
f = MySmallFunctor();
|
||||
g = MySmallFunctor();
|
||||
f.swap(g);
|
||||
}
|
||||
|
||||
// MySmallFunctor objects should be constructed as many times as
|
||||
// they are destroyed.
|
||||
BOOST_CHECK(construction_count == destruction_count);
|
||||
|
||||
construction_count = 0;
|
||||
destruction_count = 0;
|
||||
{
|
||||
boost::function0<int> f;
|
||||
boost::function0<int> g;
|
||||
f = MyLargeFunctor();
|
||||
g = MyLargeFunctor();
|
||||
f.swap(g);
|
||||
}
|
||||
|
||||
// MyLargeFunctor objects should be constructed as many times as
|
||||
// they are destroyed.
|
||||
BOOST_CHECK(construction_count == destruction_count);
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
{
|
||||
test_zero_args();
|
||||
@ -644,5 +692,6 @@ int test_main(int, char* [])
|
||||
test_emptiness();
|
||||
test_member_functions();
|
||||
test_ref();
|
||||
test_construct_destroy_count();
|
||||
return 0;
|
||||
}
|
||||
|
18
test/function_typeof_test.cpp
Normal file
18
test/function_typeof_test.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Boost.Function library
|
||||
|
||||
// Copyright Douglas Gregor 2008. Use, modification and
|
||||
// distribution is subject to the Boost Software License, Version
|
||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// For more information, see http://www.boost.org
|
||||
#include <boost/function/function_typeof.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/typeof/typeof.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
void f(boost::function0<void> f, boost::function0<void> g)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<boost::function0<void>, BOOST_TYPEOF(f = g)>::value));
|
||||
}
|
60
test/nothrow_swap.cpp
Normal file
60
test/nothrow_swap.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
// Boost.Function library
|
||||
|
||||
// Copyright Douglas Gregor 2008. Use, modification and
|
||||
// distribution is subject to the Boost Software License, Version
|
||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// For more information, see http://www.boost.org
|
||||
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
struct tried_to_copy { };
|
||||
|
||||
struct MaybeThrowOnCopy {
|
||||
MaybeThrowOnCopy(int value = 0) : value(value) { }
|
||||
|
||||
MaybeThrowOnCopy(const MaybeThrowOnCopy& other) : value(other.value) {
|
||||
if (throwOnCopy)
|
||||
throw tried_to_copy();
|
||||
}
|
||||
|
||||
MaybeThrowOnCopy& operator=(const MaybeThrowOnCopy& other) {
|
||||
if (throwOnCopy)
|
||||
throw tried_to_copy();
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int operator()() { return value; }
|
||||
|
||||
int value;
|
||||
|
||||
// Make sure that this function object doesn't trigger the
|
||||
// small-object optimization in Function.
|
||||
float padding[100];
|
||||
|
||||
static bool throwOnCopy;
|
||||
};
|
||||
|
||||
bool MaybeThrowOnCopy::throwOnCopy = false;
|
||||
|
||||
int test_main(int, char* [])
|
||||
{
|
||||
boost::function0<int> f;
|
||||
boost::function0<int> g;
|
||||
|
||||
MaybeThrowOnCopy::throwOnCopy = false;
|
||||
f = MaybeThrowOnCopy(1);
|
||||
g = MaybeThrowOnCopy(2);
|
||||
BOOST_CHECK(f() == 1);
|
||||
BOOST_CHECK(g() == 2);
|
||||
|
||||
MaybeThrowOnCopy::throwOnCopy = true;
|
||||
f.swap(g);
|
||||
BOOST_CHECK(f() == 2);
|
||||
BOOST_CHECK(g() == 1);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user