$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r84276 - trunk/boost/unordered/detail
From: dnljms_at_[hidden]
Date: 2013-05-13 19:12:47
Author: danieljames
Date: 2013-05-13 19:12:46 EDT (Mon, 13 May 2013)
New Revision: 84276
URL: http://svn.boost.org/trac/boost/changeset/84276
Log:
Use nothrow move assignment for function objects, when available.
Originally I was going to use two different versions of `hash_functions`, but
the recent discussion on binary compatibility persuaded me not to.
Text files modified: 
   trunk/boost/unordered/detail/buckets.hpp |    63 +++++++++++++++++++++++++++++++++++---- 
   trunk/boost/unordered/detail/table.hpp   |    19 ++++-------                             
   2 files changed, 63 insertions(+), 19 deletions(-)
Modified: trunk/boost/unordered/detail/buckets.hpp
==============================================================================
--- trunk/boost/unordered/detail/buckets.hpp	(original)
+++ trunk/boost/unordered/detail/buckets.hpp	2013-05-13 19:12:46 EDT (Mon, 13 May 2013)
@@ -15,6 +15,8 @@
 #include <boost/unordered/detail/allocate.hpp>
 #include <boost/type_traits/aligned_storage.hpp>
 #include <boost/type_traits/alignment_of.hpp>
+#include <boost/type_traits/is_nothrow_move_constructible.hpp>
+#include <boost/type_traits/is_nothrow_move_assignable.hpp>
 #include <boost/swap.hpp>
 #include <boost/assert.hpp>
 #include <boost/limits.hpp>
@@ -670,12 +672,16 @@
     // atomically assigns the new function objects in a strongly
     // exception safe manner.
 
-    template <class H, class P> class set_hash_functions;
+    template <class H, class P, bool NoThrowMoveAssign>
+    class set_hash_functions;
 
     template <class H, class P>
     class functions
     {
-        friend class boost::unordered::detail::set_hash_functions<H, P>;
+        friend class boost::unordered::detail::set_hash_functions<H, P,
+               boost::is_nothrow_move_assignable<H>::value &&
+               boost::is_nothrow_move_assignable<P>::value
+           >;
         functions& operator=(functions const&);
 
         typedef compressed<H, P> function_pair;
@@ -692,6 +698,11 @@
                 static_cast<void const*>(&funcs_[current_]));
         }
 
+        function_pair& current() {
+            return *static_cast<function_pair*>(
+                static_cast<void*>(&funcs_[current_]));
+        }
+
         void construct(bool which, H const& hf, P const& eq)
         {
             new((void*) &funcs_[which]) function_pair(hf, eq);
@@ -709,6 +720,11 @@
         
     public:
 
+        typedef boost::unordered::detail::set_hash_functions<H, P,
+                boost::is_nothrow_move_assignable<H>::value &&
+                boost::is_nothrow_move_assignable<P>::value
+            > set_hash_functions;
+
         functions(H const& hf, P const& eq)
             : current_(false)
         {
@@ -733,26 +749,28 @@
             return current().second();
         }
     };
-    
+
     template <class H, class P>
-    class set_hash_functions
+    class set_hash_functions<H, P, false>
     {
         set_hash_functions(set_hash_functions const&);
         set_hash_functions& operator=(set_hash_functions const&);
+
+        typedef functions<H, P> functions_type;
     
-        functions<H,P>& functions_;
+        functions_type& functions_;
         bool tmp_functions_;
 
     public:
 
-        set_hash_functions(functions<H,P>& f, H const& h, P const& p)
+        set_hash_functions(functions_type& f, H const& h, P const& p)
           : functions_(f),
             tmp_functions_(!f.current_)
         {
             f.construct(tmp_functions_, h, p);
         }
 
-        set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
+        set_hash_functions(functions_type& f, functions_type const& other)
           : functions_(f),
             tmp_functions_(!f.current_)
         {
@@ -771,6 +789,37 @@
         }
     };
 
+    template <class H, class P>
+    class set_hash_functions<H, P, true>
+    {
+        set_hash_functions(set_hash_functions const&);
+        set_hash_functions& operator=(set_hash_functions const&);
+
+        typedef functions<H, P> functions_type;
+
+        functions_type& functions_;
+        H hash_;
+        P pred_;
+    
+    public:
+
+        set_hash_functions(functions_type& f, H const& h, P const& p) :
+            functions_(f),
+            hash_(h),
+            pred_(p) {}
+
+        set_hash_functions(functions_type& f, functions_type const& other) :
+            functions_(f),
+            hash_(other.hash_function()),
+            pred_(other.key_eq()) {}
+
+        void commit()
+        {
+            functions_.current().first() = boost::move(hash_);
+            functions_.current().second() = boost::move(pred_);
+        }
+    };
+    
     ////////////////////////////////////////////////////////////////////////////
     // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
     // e.g. for int
Modified: trunk/boost/unordered/detail/table.hpp
==============================================================================
--- trunk/boost/unordered/detail/table.hpp	(original)
+++ trunk/boost/unordered/detail/table.hpp	2013-05-13 19:12:46 EDT (Mon, 13 May 2013)
@@ -159,6 +159,7 @@
         typedef boost::unordered::detail::functions<
             typename Types::hasher,
             typename Types::key_equal> functions;
+        typedef typename functions::set_hash_functions set_hash_functions;
 
         typedef typename Types::allocator allocator;
         typedef typename boost::unordered::detail::
@@ -469,10 +470,8 @@
         // Only swaps the allocators if propagate_on_container_swap
         void swap(table& x)
         {
-            boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                op1(*this, x);
-            boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                op2(x, *this);
+            set_hash_functions op1(*this, x);
+            set_hash_functions op2(x, *this);
 
             // I think swap can throw if Propagate::value,
             // since the allocators' swap can throw. Not sure though.
@@ -637,8 +636,7 @@
         void assign(table const& x, false_type)
         {
             // Strong exception safety.
-            boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                new_func_this(*this, x);
+            set_hash_functions new_func_this(*this, x);
             new_func_this.commit();
             mlf_ = x.mlf_;
             recalculate_max_load();
@@ -666,8 +664,7 @@
                 assign(x, false_type());
             }
             else {
-                boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                    new_func_this(*this, x);
+                set_hash_functions new_func_this(*this, x);
 
                 // Delete everything with current allocators before assigning
                 // the new ones.
@@ -714,8 +711,7 @@
                 move_assign_no_alloc(x);
             }
             else {
-                boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                    new_func_this(*this, x);
+                set_hash_functions new_func_this(*this, x);
                 new_func_this.commit();
                 mlf_ = x.mlf_;
                 recalculate_max_load();
@@ -740,8 +736,7 @@
         
         void move_assign_no_alloc(table& x)
         {
-            boost::unordered::detail::set_hash_functions<hasher, key_equal>
-                new_func_this(*this, x);
+            set_hash_functions new_func_this(*this, x);
             // No throw from here.
             mlf_ = x.mlf_;
             max_load_ = x.max_load_;