Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r54824 - in branches/release: . boost/function libs/function/doc libs/function/test
From: daniel_james_at_[hidden]
Date: 2009-07-08 19:23:53


Author: danieljames
Date: 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
New Revision: 54824
URL: http://svn.boost.org/trac/boost/changeset/54824

Log:
Merge various function changes from trunk.

Merged revisions 49571,50064,51743,51745,53722,54616-54619 via svnmerge from
https://svn.boost.org/svn/boost/trunk

........
  r49571 | noel_belcourt | 2008-11-03 18:37:49 +0000 (Mon, 03 Nov 2008) | 9 lines
  
  Both Sun and Pgi on Linux correctly put typeinfo into the std
  namespace, but function_base keys off the
  BOOST_NO_EXCEPTION_STD_NAMESPACE macro instead of the
  BOOST_NO_STD_TYPEINFO macro. The attached patch changes
  function_base to use the typeinfo macro. Because eVC 4.2 doesn't
  put typeinfo into the std namespace, I need to define
  BOOST_NO_STD_TYPEINFO only for this eVC version.
........
  r50064 | johnmaddock | 2008-12-02 10:10:46 +0000 (Tue, 02 Dec 2008) | 1 line
  
  Fix -Wundef warning and suspect usage of BOOST_STRICT_CONFIG.
........
  r51743 | dgregor | 2009-03-13 05:23:53 +0000 (Fri, 13 Mar 2009) | 11 lines
  
  Implement an optimization that David Abrahams and myself came up with,
  where Boost.Function uses a bit in the vtable pointer to indicate when
  the target function object has a trivial copy constructor, trivial
  destructor, and fits within the small object buffer. In this case, we
  just copy the bits of the function object rather than performing an
  indirect call to the manager.
  
  This results in a 60% speedup on a micro-benchmark that copies and
  calls such function objects repeatedly.
........
  r51745 | dgregor | 2009-03-13 05:49:02 +0000 (Fri, 13 Mar 2009) | 7 lines
  
  Make Boost.Function compile under BOOST_NO_EXCEPTIONS.
  
  Fixes #2499
  Fixes #2494
  Fixes #2469
  Fixes #2466
........
  r53722 | vladimir_prus | 2009-06-07 16:44:50 +0100 (Sun, 07 Jun 2009) | 4 lines
  
  Make Boost.Function compile with disabled exceptions.
  
  Closes #2900. Patch from Gabi Davar.
........
  r54616 | danieljames | 2009-07-03 23:20:26 +0100 (Fri, 03 Jul 2009) | 3 lines
  
  When copying boost::ref, copy even when the referenced function is empty. Fixes #2642
  
  Patch by Steven Watanabe
........
  r54617 | danieljames | 2009-07-03 23:20:52 +0100 (Fri, 03 Jul 2009) | 6 lines
  
  Add 'and later versions' to support info for GCC and Visual C++. Fixes #2847.
  
  I didn't explicitly specify the versions since no one's updating this
  list and it's highly unlikely that a future version will break this. The
  same could probably be done for the other compilers but I don't know
  them very well so I'm leaving them alone.
........
  r54618 | danieljames | 2009-07-03 23:21:40 +0100 (Fri, 03 Jul 2009) | 4 lines
  
  Fix Boost.Function unit tests for C++0x. Fixes #3012
  
  Based on a patch from Richard Webb. Changed a bit so that it also
  works for the Visual C++ 10 beta.
........
  r54619 | danieljames | 2009-07-03 23:22:03 +0100 (Fri, 03 Jul 2009) | 3 lines
  
  Work around Visual C++ copy constructor bug. Fixes #2929.
  
  Based on the patch by Steven Watanabe.
........

Properties modified:
   branches/release/ (props changed)
Text files modified:
   branches/release/boost/function/function_base.hpp | 26 +++++++++-
   branches/release/boost/function/function_fwd.hpp | 2
   branches/release/boost/function/function_template.hpp | 96 +++++++++++++++++++++++++---------------
   branches/release/libs/function/doc/tutorial.xml | 4
   branches/release/libs/function/test/allocator_test.cpp | 4 +
   branches/release/libs/function/test/function_test.cpp | 39 +++++++++++++--
   branches/release/libs/function/test/lambda_test.cpp | 12 ++--
   7 files changed, 127 insertions(+), 56 deletions(-)

Modified: branches/release/boost/function/function_base.hpp
==============================================================================
--- branches/release/boost/function/function_base.hpp (original)
+++ branches/release/boost/function/function_base.hpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -18,6 +18,9 @@
 #include <typeinfo>
 #include <boost/config.hpp>
 #include <boost/assert.hpp>
+#include <boost/integer.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
 #include <boost/type_traits/is_const.hpp>
 #include <boost/type_traits/is_integral.hpp>
 #include <boost/type_traits/is_volatile.hpp>
@@ -42,7 +45,7 @@
 #endif
 
 // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
-#ifdef BOOST_NO_EXCEPTION_STD_NAMESPACE
+#ifdef BOOST_NO_STD_TYPEINFO
 // Embedded VC++ does not have type_info in namespace std
 # define BOOST_FUNCTION_STD_NS
 #else
@@ -259,6 +262,12 @@
           A(a)
         {
         }
+
+ functor_wrapper(const functor_wrapper& f) :
+ F(static_cast<const F&>(f)),
+ A(static_cast<const A&>(f))
+ {
+ }
       };
 
       /**
@@ -625,7 +634,7 @@
     if (!vtable) return typeid(void);
 
     detail::function::function_buffer type;
- vtable->manager(functor, type, detail::function::get_functor_type_tag);
+ get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
     return *type.type.type;
   }
 
@@ -638,7 +647,7 @@
       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,
+ get_vtable()->manager(functor, type_result,
                       detail::function::check_functor_type_tag);
       return static_cast<Functor*>(type_result.obj_ptr);
     }
@@ -656,7 +665,7 @@
       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,
+ get_vtable()->manager(functor, type_result,
                       detail::function::check_functor_type_tag);
       // GCC 2.95.3 gets the CV qualifiers wrong here, so we
       // can't do the static_cast that we should do.
@@ -702,6 +711,15 @@
 #endif
 
 public: // should be protected, but GCC 2.95.3 will fail to allow access
+ detail::function::vtable_base* get_vtable() const {
+ return reinterpret_cast<detail::function::vtable_base*>(
+ reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
+ }
+
+ bool has_trivial_copy_and_destroy() const {
+ return reinterpret_cast<std::size_t>(vtable) & 0x01;
+ }
+
   detail::function::vtable_base* vtable;
   mutable detail::function::function_buffer functor;
 };

Modified: branches/release/boost/function/function_fwd.hpp
==============================================================================
--- branches/release/boost/function/function_fwd.hpp (original)
+++ branches/release/boost/function/function_fwd.hpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -21,7 +21,7 @@
 
 #if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
  || defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
- || !(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
 #endif
 

Modified: branches/release/boost/function/function_template.hpp
==============================================================================
--- branches/release/boost/function/function_template.hpp (original)
+++ branches/release/boost/function/function_template.hpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -11,6 +11,7 @@
 // Note: this header is a header template and must NOT have multiple-inclusion
 // protection.
 #include <boost/function/detail/prologue.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
 
 #if defined(BOOST_MSVC)
 # pragma warning( push )
@@ -624,14 +625,10 @@
         assign_to(const reference_wrapper<FunctionObj>& f,
                   function_buffer& functor, function_obj_ref_tag)
         {
- if (!boost::detail::function::has_empty_target(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;
- }
+ 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;
         }
         template<typename FunctionObj,typename Allocator>
         bool
@@ -678,6 +675,11 @@
               R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
       vtable_type;
 
+ vtable_type* get_vtable() const {
+ return reinterpret_cast<vtable_type*>(
+ reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
+ }
+
     struct clear_type {};
 
   public:
@@ -757,7 +759,7 @@
       if (this->empty())
         boost::throw_exception(bad_function_call());
 
- return static_cast<vtable_type*>(vtable)->invoker
+ return get_vtable()->invoker
                (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
     }
 #else
@@ -781,24 +783,26 @@
     operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
     {
       this->clear();
- try {
+ BOOST_TRY {
         this->assign_to(f);
- } catch (...) {
+ } BOOST_CATCH (...) {
         vtable = 0;
- throw;
+ BOOST_RETHROW;
       }
+ BOOST_CATCH_END
       return *this;
     }
     template<typename Functor,typename Allocator>
     void assign(Functor BOOST_FUNCTION_TARGET_FIX(const &) f, Allocator a)
     {
       this->clear();
- try {
+ BOOST_TRY{
         this->assign_to_a(f,a);
- } catch (...) {
+ } BOOST_CATCH (...) {
         vtable = 0;
- throw;
+ BOOST_RETHROW;
       }
+ BOOST_CATCH_END
     }
 
 #ifndef BOOST_NO_SFINAE
@@ -823,12 +827,13 @@
         return *this;
 
       this->clear();
- try {
+ BOOST_TRY {
         this->assign_to_own(f);
- } catch (...) {
+ } BOOST_CATCH (...) {
         vtable = 0;
- throw;
+ BOOST_RETHROW;
       }
+ BOOST_CATCH_END
       return *this;
     }
 
@@ -847,7 +852,8 @@
     void clear()
     {
       if (vtable) {
- reinterpret_cast<vtable_type*>(vtable)->clear(this->functor);
+ if (!this->has_trivial_copy_and_destroy())
+ get_vtable()->clear(this->functor);
         vtable = 0;
       }
     }
@@ -876,8 +882,11 @@
     {
       if (!f.empty()) {
         this->vtable = f.vtable;
- f.vtable->manager(f.functor, this->functor,
- boost::detail::function::clone_functor_tag);
+ if (this->has_trivial_copy_and_destroy())
+ this->functor = f.functor;
+ else
+ get_vtable()->base.manager(f.functor, this->functor,
+ boost::detail::function::clone_functor_tag);
       }
     }
 
@@ -903,8 +912,15 @@
       static vtable_type stored_vtable =
         { { &manager_type::manage }, &invoker_type::invoke };
 
- if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base;
- else vtable = 0;
+ if (stored_vtable.assign_to(f, functor)) {
+ std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
+ if (boost::has_trivial_copy_constructor<Functor>::value &&
+ boost::has_trivial_destructor<Functor>::value &&
+ detail::function::function_allows_small_object_optimization<Functor>::value)
+ value |= (std::size_t)0x01;
+ vtable = reinterpret_cast<detail::function::vtable_base *>(value);
+ } else
+ vtable = 0;
     }
 
     template<typename Functor,typename Allocator>
@@ -930,8 +946,15 @@
       static vtable_type stored_vtable =
         { { &manager_type::manage }, &invoker_type::invoke };
 
- if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base;
- else vtable = 0;
+ if (stored_vtable.assign_to_a(f, functor, a)) {
+ std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
+ if (boost::has_trivial_copy_constructor<Functor>::value &&
+ boost::has_trivial_destructor<Functor>::value &&
+ detail::function::function_allows_small_object_optimization<Functor>::value)
+ value |= (std::size_t)0x01;
+ vtable = reinterpret_cast<detail::function::vtable_base *>(value);
+ } else
+ vtable = 0;
     }
 
     // Moves the value from the specified argument to *this. If the argument
@@ -942,23 +965,23 @@
       if (&f == this)
         return;
 
-#if !defined(BOOST_NO_EXCEPTIONS)
- try {
-#endif
+ BOOST_TRY {
         if (!f.empty()) {
           this->vtable = f.vtable;
- f.vtable->manager(f.functor, this->functor,
- boost::detail::function::move_functor_tag);
+ if (this->has_trivial_copy_and_destroy())
+ this->functor = f.functor;
+ else
+ get_vtable()->base.manager(f.functor, this->functor,
+ boost::detail::function::move_functor_tag);
           f.vtable = 0;
-#if !defined(BOOST_NO_EXCEPTIONS)
         } else {
           clear();
         }
- } catch (...) {
+ } BOOST_CATCH (...) {
         vtable = 0;
- throw;
+ BOOST_RETHROW;
       }
-#endif
+ BOOST_CATCH_END
     }
   };
 
@@ -979,13 +1002,14 @@
   template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS>
   typename BOOST_FUNCTION_FUNCTION<
       R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type
- BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
+ inline
+ BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
   ::operator()(BOOST_FUNCTION_PARMS) const
   {
     if (this->empty())
       boost::throw_exception(bad_function_call());
 
- return reinterpret_cast<const vtable_type*>(vtable)->invoker
+ return get_vtable()->invoker
              (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
   }
 #endif

Modified: branches/release/libs/function/doc/tutorial.xml
==============================================================================
--- branches/release/libs/function/doc/tutorial.xml (original)
+++ branches/release/libs/function/doc/tutorial.xml 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -35,12 +35,12 @@
         <row>
           <entry>
             <itemizedlist spacing="compact">
- <listitem><simpara>GNU C++ 2.95.x, 3.0.x, 3.1.x</simpara></listitem>
+ <listitem><simpara>GNU C++ 2.95.x, 3.0.x and later verseions</simpara></listitem>
               <listitem><simpara>Comeau C++ 4.2.45.2</simpara></listitem>
               <listitem><simpara>SGI MIPSpro 7.3.0</simpara></listitem>
               <listitem><simpara>Intel C++ 5.0, 6.0</simpara></listitem>
               <listitem><simpara>Compaq's cxx 6.2</simpara></listitem>
- <listitem><simpara>Microsoft Visual C++ 7.1</simpara></listitem>
+ <listitem><simpara>Microsoft Visual C++ 7.1 and later versions</simpara></listitem>
             </itemizedlist>
           </entry>
           <entry>

Modified: branches/release/libs/function/test/allocator_test.cpp
==============================================================================
--- branches/release/libs/function/test/allocator_test.cpp (original)
+++ branches/release/libs/function/test/allocator_test.cpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -128,6 +128,10 @@
   BOOST_CHECK(dealloc_count == 0);
   fv.assign( &do_nothing, std::allocator<int>() );
   fv.clear();
+
+ function0<void> fv2;
+ fv.assign(&do_nothing, std::allocator<int>() );
+ fv2.assign(fv, std::allocator<int>() );
 
   return 0;
 }

Modified: branches/release/libs/function/test/function_test.cpp
==============================================================================
--- branches/release/libs/function/test/function_test.cpp (original)
+++ branches/release/libs/function/test/function_test.cpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -13,8 +13,8 @@
 #include <string>
 #include <utility>
 
-using namespace boost;
-using namespace std;
+using boost::function;
+using std::string;
 
 int global_int;
 
@@ -525,7 +525,7 @@
 static void
 test_one_arg()
 {
- negate<int> neg;
+ std::negate<int> neg;
 
   function<int (int)> f1(neg);
   BOOST_CHECK(f1(5) == -5);
@@ -607,12 +607,12 @@
 
   add_with_throw_on_copy(const add_with_throw_on_copy&)
   {
- throw runtime_error("But this CAN'T throw");
+ throw std::runtime_error("But this CAN'T throw");
   }
 
   add_with_throw_on_copy& operator=(const add_with_throw_on_copy&)
   {
- throw runtime_error("But this CAN'T throw");
+ throw std::runtime_error("But this CAN'T throw");
   }
 };
 
@@ -621,14 +621,38 @@
 {
   add_with_throw_on_copy atc;
   try {
- boost::function<int (int, int)> f(ref(atc));
+ boost::function<int (int, int)> f(boost::ref(atc));
     BOOST_CHECK(f(1, 3) == 4);
   }
- catch(runtime_error e) {
+ catch(std::runtime_error e) {
     BOOST_ERROR("Nonthrowing constructor threw an exception");
   }
 }
 
+static void dummy() {}
+
+static void test_empty_ref()
+{
+ boost::function<void()> f1;
+ boost::function<void()> f2(boost::ref(f1));
+
+ try {
+ f2();
+ BOOST_ERROR("Exception didn't throw for reference to empty function.");
+ }
+ catch(std::runtime_error e) {}
+
+ f1 = dummy;
+
+ try {
+ f2();
+ }
+ catch(std::runtime_error e) {
+ BOOST_ERROR("Error calling referenced function.");
+ }
+}
+
+
 static void test_exception()
 {
   boost::function<int (int, int)> f;
@@ -674,6 +698,7 @@
   test_emptiness();
   test_member_functions();
   test_ref();
+ test_empty_ref();
   test_exception();
   test_implicit();
   test_call();

Modified: branches/release/libs/function/test/lambda_test.cpp
==============================================================================
--- branches/release/libs/function/test/lambda_test.cpp (original)
+++ branches/release/libs/function/test/lambda_test.cpp 2009-07-08 19:23:52 EDT (Wed, 08 Jul 2009)
@@ -15,21 +15,21 @@
 #include <boost/lambda/bind.hpp>
 #include <boost/function.hpp>
 
-using namespace std;
-using namespace boost;
-using namespace boost::lambda;
-
 static unsigned
 func_impl(int arg1, bool arg2, double arg3)
 {
+ using namespace std;
   return abs (static_cast<int>((arg2 ? arg1 : 2 * arg1) * arg3));
 }
 
 int test_main(int, char*[])
 {
+ using boost::function;
+ using namespace boost::lambda;
+
   function <unsigned(bool, double)> f1 = bind(func_impl, 15, _1, _2);
- function <unsigned(double)> f2 = bind(f1, false, _1);
- function <unsigned()> f3 = bind(f2, 4.0);
+ function <unsigned(double)> f2 = boost::lambda::bind(f1, false, _1);
+ function <unsigned()> f3 = boost::lambda::bind(f2, 4.0);
 
   f3();
 


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