Boost logo

Boost-Commit :

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_;


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