Unordered: Avoid unnecessary swapping in rehash and move.

[SVN r80378]
This commit is contained in:
Daniel James
2012-09-03 20:01:50 +00:00
parent c0faf59a86
commit 7a4930f1a1
4 changed files with 44 additions and 52 deletions

View File

@ -684,38 +684,59 @@ namespace boost { namespace unordered { namespace detail {
} }
buckets(buckets& b, boost::unordered::detail::move_tag m) : buckets(buckets& b, boost::unordered::detail::move_tag m) :
buckets_(), buckets_(b.buckets_),
bucket_count_(b.bucket_count_), bucket_count_(b.bucket_count_),
size_(), size_(b.size_),
allocators_(b.allocators_, m) allocators_(b.allocators_, m)
{ {
swap(b); b.buckets_ = bucket_pointer();
b.size_ = 0;
} }
template <typename Types> template <typename Types>
buckets(boost::unordered::detail::table<Types>& x, buckets(boost::unordered::detail::table<Types>& x,
boost::unordered::detail::move_tag m) : boost::unordered::detail::move_tag m) :
buckets_(), buckets_(x.buckets_),
bucket_count_(x.bucket_count_), bucket_count_(x.bucket_count_),
size_(), size_(x.size_),
allocators_(x.allocators_, m) allocators_(x.allocators_, m)
{ {
swap(x); x.buckets_ = bucket_pointer();
x.size_ = 0;
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Create buckets // Create buckets
// (never called in constructor to avoid exception issues) // (never called in constructor to avoid exception issues)
void create_buckets() void create_buckets(std::size_t new_count)
{ {
boost::unordered::detail::array_constructor<bucket_allocator> boost::unordered::detail::array_constructor<bucket_allocator>
constructor(bucket_alloc()); constructor(bucket_alloc());
// Creates an extra bucket to act as the start node. // Creates an extra bucket to act as the start node.
constructor.construct(bucket(), this->bucket_count_ + 1); constructor.construct(bucket(), new_count + 1);
if (bucket::extra_node) if (buckets_)
{
// Copy the nodes to the new buckets, including the dummy
// node if there is one.
(constructor.get() +
static_cast<std::ptrdiff_t>(new_count))->next_ =
(buckets_ + static_cast<std::ptrdiff_t>(
bucket_count_))->next_;
bucket_pointer end = this->get_bucket(this->bucket_count_ + 1);
for(bucket_pointer it = this->buckets_; it != end; ++it)
{
bucket_allocator_traits::destroy(bucket_alloc(),
boost::addressof(*it));
}
bucket_allocator_traits::deallocate(bucket_alloc(),
this->buckets_, this->bucket_count_ + 1);
}
else if (bucket::extra_node)
{ {
node_constructor a(this->node_alloc()); node_constructor a(this->node_alloc());
a.construct_node(); a.construct_node();
@ -725,6 +746,7 @@ namespace boost { namespace unordered { namespace detail {
a.release(); a.release();
} }
this->bucket_count_ = new_count;
this->buckets_ = constructor.release(); this->buckets_ = constructor.release();
} }
@ -755,7 +777,6 @@ namespace boost { namespace unordered { namespace detail {
this->bucket_count_ = other.bucket_count_; this->bucket_count_ = other.bucket_count_;
this->size_ = other.size_; this->size_ = other.size_;
other.buckets_ = bucket_pointer(); other.buckets_ = bucket_pointer();
other.bucket_count_ = 0;
other.size_ = 0; other.size_ = 0;
} }

View File

@ -719,7 +719,7 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(!dst.buckets_); BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(); dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc()); node_constructor a(dst.node_alloc());
@ -766,7 +766,7 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(!dst.buckets_); BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(); dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc()); node_constructor a(dst.node_alloc());
@ -808,26 +808,12 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(this->size_); BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets); this->create_buckets(num_buckets);
dst.create_buckets(); previous_pointer prev = this->get_previous_start();
previous_pointer src_start = this->get_previous_start();
previous_pointer dst_start = dst.get_previous_start();
dst_start->next_ = src_start->next_;
src_start->next_ = link_pointer();
dst.size_ = this->size_;
this->size_ = 0;
previous_pointer prev = dst_start;
while (prev->next_) while (prev->next_)
prev = place_in_bucket(dst, prev, prev = place_in_bucket(*this, prev,
static_cast<node_pointer>( static_cast<node_pointer>(
static_cast<node_pointer>(prev->next_)->group_prev_)); static_cast<node_pointer>(prev->next_)->group_prev_));
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
} }
// Iterate through the nodes placing them in the correct buckets. // Iterate through the nodes placing them in the correct buckets.

View File

@ -196,7 +196,7 @@ namespace boost { namespace unordered { namespace detail {
max_load_(x.max_load_) max_load_(x.max_load_)
{ {
if(a == x.node_alloc()) { if(a == x.node_alloc()) {
this->buckets::swap(x, false_type()); this->move_buckets_from(x);
} }
else if(x.size_) { else if(x.size_) {
// Use a temporary table because move_buckets_to leaves the // Use a temporary table because move_buckets_to leaves the
@ -403,9 +403,8 @@ namespace boost { namespace unordered { namespace detail {
inline void table<Types>::reserve_for_insert(std::size_t size) inline void table<Types>::reserve_for_insert(std::size_t size)
{ {
if (!this->buckets_) { if (!this->buckets_) {
this->bucket_count_ = (std::max)(this->bucket_count_, this->create_buckets((std::max)(this->bucket_count_,
this->min_buckets_for_size(size)); this->min_buckets_for_size(size)));
this->create_buckets();
this->max_load_ = this->calculate_max_load(); this->max_load_ = this->calculate_max_load();
} }
// According to the standard this should be 'size >= max_load_', // According to the standard this should be 'size >= max_load_',

View File

@ -626,7 +626,7 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(!dst.buckets_); BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(); dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc()); node_constructor a(dst.node_alloc());
@ -657,7 +657,7 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(!dst.buckets_); BOOST_ASSERT(!dst.buckets_);
dst.create_buckets(); dst.create_buckets(dst.bucket_count_);
node_constructor a(dst.node_alloc()); node_constructor a(dst.node_alloc());
@ -683,24 +683,10 @@ namespace boost { namespace unordered { namespace detail {
{ {
BOOST_ASSERT(this->size_); BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets); this->create_buckets(num_buckets);
dst.create_buckets(); previous_pointer prev = this->get_previous_start();
previous_pointer src_start = this->get_previous_start();
previous_pointer dst_start = dst.get_previous_start();
dst_start->next_ = src_start->next_;
src_start->next_ = link_pointer();
dst.size_ = this->size_;
this->size_ = 0;
previous_pointer prev = dst.get_previous_start();
while (prev->next_) while (prev->next_)
prev = place_in_bucket(dst, prev); prev = place_in_bucket(*this, prev);
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
} }
// Iterate through the nodes placing them in the correct buckets. // Iterate through the nodes placing them in the correct buckets.