$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r80738 - in branches/release: boost/function libs/function/test
From: antoshkka_at_[hidden]
Date: 2012-09-28 14:14:00
Author: apolukhin
Date: 2012-09-28 14:14:00 EDT (Fri, 28 Sep 2012)
New Revision: 80738
URL: http://svn.boost.org/trac/boost/changeset/80738
Log:
Merge from trunk: added move assignment and move constructors to Boost.Function (fixes #7330)
Text files modified: 
   branches/release/boost/function/function_template.hpp |    51 +++++++++++++++++++++                   
   branches/release/libs/function/test/function_test.cpp |    91 ++++++++++++++++++++++++++++++++++++++++
   2 files changed, 141 insertions(+), 1 deletions(-)
Modified: branches/release/boost/function/function_template.hpp
==============================================================================
--- branches/release/boost/function/function_template.hpp	(original)
+++ branches/release/boost/function/function_template.hpp	2012-09-28 14:14:00 EDT (Fri, 28 Sep 2012)
@@ -748,7 +748,14 @@
     {
       this->assign_to_own(f);
     }
-
+    
+#ifndef BOOST_NO_RVALUE_REFERENCES
+    BOOST_FUNCTION_FUNCTION(BOOST_FUNCTION_FUNCTION&& f) : function_base()
+    {
+      this->move_assign(f);
+    }
+#endif
+    
     ~BOOST_FUNCTION_FUNCTION() { clear(); }
 
     result_type operator()(BOOST_FUNCTION_PARMS) const
@@ -830,6 +837,26 @@
       BOOST_CATCH_END
       return *this;
     }
+    
+#ifndef BOOST_NO_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)
     {
@@ -1063,12 +1090,26 @@
 
   function(const base_type& f) : base_type(static_cast<const base_type&>(f)){}
 
+#ifndef BOOST_NO_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(f).swap(*this);
     return *this;
   }
 
+#ifndef BOOST_NO_RVALUE_REFERENCES
+  self_type& operator=(self_type&& f)
+  {
+    self_type(static_cast<self_type&&>(f)).swap(*this);
+    return *this;
+  }
+#endif  
+
   template<typename Functor>
 #ifndef BOOST_NO_SFINAE
   typename enable_if_c<
@@ -1097,6 +1138,14 @@
     self_type(f).swap(*this);
     return *this;
   }
+  
+#ifndef BOOST_NO_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
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	2012-09-28 14:14:00 EDT (Fri, 28 Sep 2012)
@@ -690,6 +690,95 @@
   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_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* [])
 {
   test_zero_args();
@@ -702,6 +791,8 @@
   test_exception();
   test_implicit();
   test_call();
+  test_move_semantics<function<void()> >();
+  test_move_semantics<boost::function0<void> >();
 
   return 0;
 }