diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index f3602339..30d70fb7 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -670,12 +672,16 @@ namespace boost { namespace unordered { namespace detail { // atomically assigns the new function objects in a strongly // exception safe manner. - template class set_hash_functions; + template + class set_hash_functions; template class functions { - friend class boost::unordered::detail::set_hash_functions; + friend class boost::unordered::detail::set_hash_functions::value && + boost::is_nothrow_move_assignable

::value + >; functions& operator=(functions const&); typedef compressed function_pair; @@ -692,6 +698,11 @@ namespace boost { namespace unordered { namespace detail { static_cast(&funcs_[current_])); } + function_pair& current() { + return *static_cast( + static_cast(&funcs_[current_])); + } + void construct(bool which, H const& hf, P const& eq) { new((void*) &funcs_[which]) function_pair(hf, eq); @@ -709,6 +720,11 @@ namespace boost { namespace unordered { namespace detail { public: + typedef boost::unordered::detail::set_hash_functions::value && + boost::is_nothrow_move_assignable

::value + > set_hash_functions; + functions(H const& hf, P const& eq) : current_(false) { @@ -733,26 +749,28 @@ namespace boost { namespace unordered { namespace detail { return current().second(); } }; - + template - class set_hash_functions + class set_hash_functions { set_hash_functions(set_hash_functions const&); set_hash_functions& operator=(set_hash_functions const&); + + typedef functions functions_type; - functions& functions_; + functions_type& functions_; bool tmp_functions_; public: - set_hash_functions(functions& 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& f, functions const& other) + set_hash_functions(functions_type& f, functions_type const& other) : functions_(f), tmp_functions_(!f.current_) { @@ -771,6 +789,37 @@ namespace boost { namespace unordered { namespace detail { } }; + template + class set_hash_functions + { + set_hash_functions(set_hash_functions const&); + set_hash_functions& operator=(set_hash_functions const&); + + typedef functions 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 diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index a0b14c0c..06be1be1 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -159,6 +159,7 @@ namespace boost { namespace unordered { namespace detail { 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 @@ namespace boost { namespace unordered { namespace detail { // Only swaps the allocators if propagate_on_container_swap void swap(table& x) { - boost::unordered::detail::set_hash_functions - op1(*this, x); - boost::unordered::detail::set_hash_functions - 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 @@ namespace boost { namespace unordered { namespace detail { void assign(table const& x, false_type) { // Strong exception safety. - boost::unordered::detail::set_hash_functions - 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 @@ namespace boost { namespace unordered { namespace detail { assign(x, false_type()); } else { - boost::unordered::detail::set_hash_functions - 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 @@ namespace boost { namespace unordered { namespace detail { move_assign_no_alloc(x); } else { - boost::unordered::detail::set_hash_functions - 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 @@ namespace boost { namespace unordered { namespace detail { void move_assign_no_alloc(table& x) { - boost::unordered::detail::set_hash_functions - 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_;