|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r48615 - in trunk: boost/function libs/function/doc libs/function/test
From: dgregor_at_[hidden]
Date: 2008-09-05 11:43:23
Author: dgregor
Date: 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
New Revision: 48615
URL: http://svn.boost.org/trac/boost/changeset/48615
Log:
Improve the performance of Boost.Function's swap. Thanks to Niels Dekker for the original patch. Fixes #1910
Added:
trunk/libs/function/test/nothrow_swap.cpp (contents, props changed)
Text files modified:
trunk/boost/function/function_base.hpp | 25 ++++++++++++++++++++++---
trunk/boost/function/function_fwd.hpp | 2 ++
trunk/boost/function/function_template.hpp | 33 ++++++++++++++++++++++++++++++---
trunk/libs/function/doc/history.xml | 8 ++++++++
trunk/libs/function/test/Jamfile.v2 | 1 +
5 files changed, 63 insertions(+), 6 deletions(-)
Modified: trunk/boost/function/function_base.hpp
==============================================================================
--- trunk/boost/function/function_base.hpp (original)
+++ trunk/boost/function/function_base.hpp 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -92,7 +92,7 @@
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).
@@ -138,6 +138,7 @@
// 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
@@ -182,6 +183,11 @@
out_buffer.obj_ptr = in_buffer.obj_ptr;
return;
+ case move_functor_tag:
+ out_buffer.obj_ptr = in_buffer.obj_ptr;
+ in_buffer.obj_ptr = 0;
+ return;
+
case destroy_functor_tag:
out_buffer.obj_ptr = 0;
return;
@@ -247,7 +253,10 @@
{
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 =
@@ -264,10 +273,14 @@
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();
@@ -317,6 +330,9 @@
(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 =
@@ -409,6 +425,9 @@
// 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 =
Modified: trunk/boost/function/function_fwd.hpp
==============================================================================
--- trunk/boost/function/function_fwd.hpp (original)
+++ trunk/boost/function/function_fwd.hpp 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -26,6 +26,8 @@
#endif
namespace boost {
+ class bad_function_call;
+
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
// Preferred syntax
template<typename Signature> class function;
Modified: trunk/boost/function/function_template.hpp
==============================================================================
--- trunk/boost/function/function_template.hpp (original)
+++ trunk/boost/function/function_template.hpp 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -729,9 +729,10 @@
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 +787,32 @@
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);
+#if !defined(BOOST_NO_EXCEPTIONS)
+ } else {
+ clear();
+ }
+ } catch (...) {
+ vtable = 0;
+ throw;
+ }
+#endif
+ }
};
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS>
Modified: trunk/libs/function/doc/history.xml
==============================================================================
--- trunk/libs/function/doc/history.xml (original)
+++ trunk/libs/function/doc/history.xml 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -13,6 +13,14 @@
<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>
+ </itemizedlist>
+ </listitem>
+
<listitem><para><bold>Version 1.36.0</bold>: </para>
<itemizedlist spacing="compact">
<listitem><para>Boost.Function now implements allocator support
Modified: trunk/libs/function/test/Jamfile.v2
==============================================================================
--- trunk/libs/function/test/Jamfile.v2 (original)
+++ trunk/libs/function/test/Jamfile.v2 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -58,6 +58,7 @@
[ run libs/function/test/contains2_test.cpp : : : : ]
+ [ run libs/function/test/nothrow_swap.cpp : : : : ]
;
}
Added: trunk/libs/function/test/nothrow_swap.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/function/test/nothrow_swap.cpp 2008-09-05 11:43:22 EDT (Fri, 05 Sep 2008)
@@ -0,0 +1,51 @@
+#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;
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk