diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 8e3252a3..6ac10fdb 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -710,20 +710,12 @@ namespace boost { namespace unordered { namespace detail { } //////////////////////////////////////////////////////////////////////// - // copy_buckets_to - // - // Basic exception safety. If an exception is thrown this will - // leave dst partially filled and the buckets unset. + // fill_buckets - static void copy_buckets_to(buckets const& src, buckets& dst) + template + static void fill_buckets(iterator n, buckets& dst, + NodeCreator& creator) { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(dst.bucket_count_); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); while (n.node_) { @@ -733,10 +725,7 @@ namespace boost { namespace unordered { namespace detail { static_cast(n.node_->group_prev_)->next_ )); - a.construct_node(); - a.construct_value2(*n); - - node_pointer first_node = a.release(); + node_pointer first_node = creator.create(*n); node_pointer end = first_node; first_node->hash_ = key_hash; prev->next_ = static_cast(first_node); @@ -744,56 +733,7 @@ namespace boost { namespace unordered { namespace detail { for (++n; n != group_end; ++n) { - a.construct_node(); - a.construct_value2(*n); - end = a.release(); - end->hash_ = key_hash; - add_after_node(end, first_node); - ++dst.size_; - } - - prev = place_in_bucket(dst, prev, end); - } - } - - //////////////////////////////////////////////////////////////////////// - // move_buckets_to - // - // Basic exception safety. The source nodes are left in an unusable - // state if an exception throws. - - static void move_buckets_to(buckets& src, buckets& dst) - { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(dst.bucket_count_); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); - - while (n.node_) { - std::size_t key_hash = n.node_->hash_; - iterator group_end( - static_cast( - static_cast(n.node_->group_prev_)->next_ - )); - - a.construct_node(); - a.construct_value2(boost::move(*n)); - - node_pointer first_node = a.release(); - node_pointer end = first_node; - first_node->hash_ = key_hash; - prev->next_ = static_cast(first_node); - ++dst.size_; - - for(++n; n != group_end; ++n) - { - a.construct_node(); - a.construct_value2(boost::move(*n)); - end = a.release(); + end = creator.create(*n); end->hash_ = key_hash; add_after_node(end, first_node); ++dst.size_; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 5951e729..e6c1459f 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -54,6 +54,45 @@ namespace boost { namespace unordered { namespace detail { value_base& operator=(value_base const&); }; + template + struct copy_nodes + { + typedef boost::unordered::detail::allocator_traits + node_allocator_traits; + + node_constructor constructor; + + explicit copy_nodes(NodeAlloc& a) : constructor(a) {} + + typename node_allocator_traits::pointer create( + typename node_allocator_traits::value_type::value_type const& v) + { + constructor.construct_node(); + constructor.construct_value2(v); + return constructor.release(); + } + }; + + template + struct move_nodes + { + typedef boost::unordered::detail::allocator_traits + node_allocator_traits; + + node_constructor constructor; + + explicit move_nodes(NodeAlloc& a) : constructor(a) {} + + typename node_allocator_traits::pointer create( + typename node_allocator_traits::value_type::value_type& v) + { + constructor.construct_node(); + constructor.construct_value2(boost::move(v)); + return constructor.release(); + } + }; + + template struct table : boost::unordered::detail::buckets< @@ -173,7 +212,9 @@ namespace boost { namespace unordered { namespace detail { max_load_(0) { if(x.size_) { - table_impl::copy_buckets_to(x, *this); + this->create_buckets(this->bucket_count_); + copy_nodes copy(this->node_alloc()); + table_impl::fill_buckets(x.get_start(), *this, copy); this->max_load_ = calculate_max_load(); } } @@ -199,11 +240,15 @@ namespace boost { namespace unordered { namespace detail { this->move_buckets_from(x); } else if(x.size_) { - // Use a temporary table because move_buckets_to leaves the + // Use a temporary table because moving the nodes leaves the // source container in a complete mess. buckets tmp(x, m); - table_impl::move_buckets_to(tmp, *this); + + this->create_buckets(this->bucket_count_); + move_nodes move(this->node_alloc()); + table_impl::fill_buckets(tmp.get_start(), *this, move); + this->max_load_ = calculate_max_load(); } } @@ -271,7 +316,11 @@ namespace boost { namespace unordered { namespace detail { buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); buckets tmp(x, move_tag()); - table_impl::move_buckets_to(tmp, b); + + b.create_buckets(b.bucket_count_); + move_nodes move(b.node_alloc()); + table_impl::fill_buckets(tmp.get_start(), b, move); + b.swap(*this); } else { diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 0e5c20b2..20311435 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -617,58 +617,16 @@ namespace boost { namespace unordered { namespace detail { } //////////////////////////////////////////////////////////////////////// - // copy_buckets_to - // - // Basic exception safety. If an exception is thrown this will - // leave dst partially filled and the buckets unset. + // fill_buckets - static void copy_buckets_to(buckets const& src, buckets& dst) + template + static void fill_buckets(iterator n, buckets& dst, + NodeCreator& creator) { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(dst.bucket_count_); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); - previous_pointer prev = dst.get_previous_start(); - - while(n.node_) { - a.construct_node(); - a.construct_value2(*n); - - node_pointer node = a.release(); - node->hash_ = n.node_->hash_; - prev->next_ = static_cast(node); - ++dst.size_; - ++n; - - prev = place_in_bucket(dst, prev); - } - } - - //////////////////////////////////////////////////////////////////////// - // move_buckets_to - // - // Basic exception safety. The source nodes are left in an unusable - // state if an exception throws. - - static void move_buckets_to(buckets& src, buckets& dst) - { - BOOST_ASSERT(!dst.buckets_); - - dst.create_buckets(dst.bucket_count_); - - node_constructor a(dst.node_alloc()); - - iterator n = src.get_start(); previous_pointer prev = dst.get_previous_start(); while (n.node_) { - a.construct_node(); - a.construct_value2(boost::move(*n)); - - node_pointer node = a.release(); + node_pointer node = creator.create(*n); node->hash_ = n.node_->hash_; prev->next_ = static_cast(node); ++dst.size_;