Unordered: Move some of the unordered implementation.

[SVN r73755]
This commit is contained in:
Daniel James
2011-08-14 18:53:03 +00:00
parent f4d4975077
commit fa97494cc8
2 changed files with 121 additions and 122 deletions

View File

@@ -64,6 +64,7 @@ namespace boost { namespace unordered { namespace detail {
bucket_ptr buckets_; bucket_ptr buckets_;
std::size_t bucket_count_; std::size_t bucket_count_;
std::size_t size_;
::boost::compressed_pair<bucket_allocator, node_allocator> allocators_; ::boost::compressed_pair<bucket_allocator, node_allocator> allocators_;
// Data access // Data access
@@ -100,6 +101,7 @@ namespace boost { namespace unordered { namespace detail {
buckets(node_allocator const& a, std::size_t bucket_count) buckets(node_allocator const& a, std::size_t bucket_count)
: buckets_(), : buckets_(),
bucket_count_(bucket_count), bucket_count_(bucket_count),
size_(),
allocators_(a,a) allocators_(a,a)
{ {
} }
@@ -109,6 +111,7 @@ namespace boost { namespace unordered { namespace detail {
buckets(buckets& b, move_tag) buckets(buckets& b, move_tag)
: buckets_(), : buckets_(),
bucket_count_(b.bucket_count_), bucket_count_(b.bucket_count_),
size_(),
allocators_(b.allocators_) allocators_(b.allocators_)
{ {
} }
@@ -138,6 +141,7 @@ namespace boost { namespace unordered { namespace detail {
BOOST_ASSERT(node_alloc() == other.node_alloc()); BOOST_ASSERT(node_alloc() == other.node_alloc());
std::swap(buckets_, other.buckets_); std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_); std::swap(bucket_count_, other.bucket_count_);
std::swap(size_, other.size_);
} }
void swap(buckets& other, true_type) void swap(buckets& other, true_type)
@@ -145,6 +149,7 @@ namespace boost { namespace unordered { namespace detail {
allocators_.swap(other.allocators_); allocators_.swap(other.allocators_);
std::swap(buckets_, other.buckets_); std::swap(buckets_, other.buckets_);
std::swap(bucket_count_, other.bucket_count_); std::swap(bucket_count_, other.bucket_count_);
std::swap(size_, other.size_);
} }
void move(buckets& other) void move(buckets& other)
@@ -153,13 +158,15 @@ namespace boost { namespace unordered { namespace detail {
if(this->buckets_) { this->delete_buckets(); } if(this->buckets_) { this->delete_buckets(); }
this->buckets_ = other.buckets_; this->buckets_ = other.buckets_;
this->bucket_count_ = other.bucket_count_; this->bucket_count_ = other.bucket_count_;
this->size_ = other.size_;
other.buckets_ = bucket_ptr(); other.buckets_ = bucket_ptr();
other.bucket_count_ = 0; other.bucket_count_ = 0;
other.size_ = 0;
} }
std::size_t bucket_size(std::size_t index) const std::size_t bucket_size(std::size_t index) const
{ {
if (!this->buckets_) return 0; if (!this->size_) return 0;
node_ptr ptr = this->buckets_[index].next_; node_ptr ptr = this->buckets_[index].next_;
if (!ptr) return 0; if (!ptr) return 0;
ptr = ptr->next_; ptr = ptr->next_;
@@ -177,7 +184,7 @@ namespace boost { namespace unordered { namespace detail {
node_ptr bucket_begin(std::size_t bucket_index) const node_ptr bucket_begin(std::size_t bucket_index) const
{ {
if (!this->buckets_) return node_ptr(); if (!this->size_) return node_ptr();
bucket& b = this->buckets_[bucket_index]; bucket& b = this->buckets_[bucket_index];
if (!b.next_) return node_ptr(); if (!b.next_) return node_ptr();
return b.next_->next_; return b.next_->next_;
@@ -190,6 +197,13 @@ namespace boost { namespace unordered { namespace detail {
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
} }
float load_factor() const
{
BOOST_ASSERT(this->bucket_count_ != 0);
return static_cast<float>(this->size_)
/ static_cast<float>(this->bucket_count_);
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Delete // Delete
@@ -201,12 +215,13 @@ namespace boost { namespace unordered { namespace detail {
::boost::unordered::detail::destroy(raw_ptr->value_ptr()); ::boost::unordered::detail::destroy(raw_ptr->value_ptr());
allocator_traits<node_allocator>::destroy(node_alloc(), raw_ptr); allocator_traits<node_allocator>::destroy(node_alloc(), raw_ptr);
allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1); allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1);
--this->size_;
} }
void delete_buckets() void delete_buckets()
{ {
bucket_ptr end = this->get_bucket(this->bucket_count_); bucket_ptr end = this->get_bucket(this->bucket_count_);
node_ptr n = (end)->next_; node_ptr n = (end)->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(n)) while(BOOST_UNORDERED_BORLAND_BOOL(n))
{ {
@@ -224,6 +239,7 @@ namespace boost { namespace unordered { namespace detail {
allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1); allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1);
this->buckets_ = bucket_ptr(); this->buckets_ = bucket_ptr();
BOOST_ASSERT(this->size_ == 0);
} }
std::size_t delete_nodes(node_ptr begin, node_ptr end) std::size_t delete_nodes(node_ptr begin, node_ptr end)
@@ -238,6 +254,57 @@ namespace boost { namespace unordered { namespace detail {
return count; return count;
} }
void clear()
{
if(!this->size_) return;
bucket_ptr end = this->get_bucket(this->bucket_count_);
node_ptr n = (end)->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(n))
{
node_ptr node_to_delete = n;
n = n->next_;
this->delete_node(node_to_delete);
}
++end;
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
begin->next_ = bucket_ptr();
}
this->size_ = 0;
}
node_ptr erase(node_ptr r)
{
BOOST_ASSERT(r);
node_ptr next = r->next_;
bucket_ptr bucket = this->get_bucket(
node::get_hash(r) % this->bucket_count_);
node_ptr prev = node::unlink_node(*bucket, r);
this->fix_buckets(bucket, prev, next);
this->delete_node(r);
return next;
}
node_ptr erase_range(node_ptr r1, node_ptr r2)
{
if (r1 == r2) return r2;
std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_;
node_ptr prev = node::unlink_nodes(
this->buckets_[bucket_index], r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
this->delete_nodes(r1, r2);
return r2;
}
// This is called after erasing a node or group of nodes to fix up // This is called after erasing a node or group of nodes to fix up
// the bucket pointers. // the bucket pointers.
void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next) void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next)
@@ -324,6 +391,7 @@ namespace boost { namespace unordered { namespace detail {
void copy_buckets_to(buckets&) const; void copy_buckets_to(buckets&) const;
void move_buckets_to(buckets&) const; void move_buckets_to(buckets&) const;
void rehash_impl(std::size_t);
}; };
// Assigning and swapping the equality and hash function objects // Assigning and swapping the equality and hash function objects
@@ -643,12 +711,14 @@ namespace boost { namespace unordered { namespace detail {
node_ptr first_node = a.release(); node_ptr first_node = a.release();
node::set_hash(first_node, hash); node::set_hash(first_node, hash);
node_ptr end = prev->next_ = first_node; node_ptr end = prev->next_ = first_node;
++dst.size_;
for(n = n->next_; n != group_end; n = n->next_) { for(n = n->next_; n != group_end; n = n->next_) {
a.construct(node::get_value(n)); a.construct(node::get_value(n));
end = a.release(); end = a.release();
node::set_hash(end, hash); node::set_hash(end, hash);
node::add_after_node(end, first_node); node::add_after_node(end, first_node);
++dst.size_;
} }
prev = dst.place_in_bucket(prev, end); prev = dst.place_in_bucket(prev, end);
@@ -690,12 +760,39 @@ namespace boost { namespace unordered { namespace detail {
end = a.release(); end = a.release();
node::set_hash(end, hash); node::set_hash(end, hash);
node::add_after_node(end, first_node); node::add_after_node(end, first_node);
++dst.size_;
} }
prev = dst.place_in_bucket(prev, end); prev = dst.place_in_bucket(prev, end);
} }
} }
} }
// strong otherwise exception safety
template <class A, bool Unique>
void buckets<A, Unique>::rehash_impl(std::size_t num_buckets)
{
BOOST_ASSERT(this->size_);
buckets dst(this->node_alloc(), num_buckets);
dst.create_buckets();
bucket_ptr src_start = this->get_bucket(this->bucket_count_);
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
dst_start->next_ = src_start->next_;
src_start->next_ = bucket_ptr();
dst.size_ = this->size_;
this->size_ = 0;
node_ptr prev = dst_start;
while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_))
prev = dst.place_in_bucket(prev, node::next_group2(prev));
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
}
}}} }}}
#endif #endif

View File

@@ -42,7 +42,6 @@ namespace boost { namespace unordered { namespace detail {
// Members // Members
std::size_t size_;
float mlf_; float mlf_;
std::size_t max_load_; std::size_t max_load_;
@@ -92,7 +91,7 @@ namespace boost { namespace unordered { namespace detail {
{ {
if (!this->size_) return node_ptr(); if (!this->size_) return node_ptr();
std::size_t hash = hash_function(k); std::size_t hash = hash_function(k);
return find_node_impl(hash % this->bucket_count_, hash, k, eq); return this->find_node_impl(hash % this->bucket_count_, hash, k, eq);
} }
node_ptr find_node( node_ptr find_node(
@@ -101,14 +100,14 @@ namespace boost { namespace unordered { namespace detail {
key_type const& k) const key_type const& k) const
{ {
if (!this->size_) return node_ptr(); if (!this->size_) return node_ptr();
return find_node_impl(bucket_index, hash, k, this->key_eq()); return this->find_node_impl(bucket_index, hash, k, this->key_eq());
} }
node_ptr find_node(key_type const& k) const node_ptr find_node(key_type const& k) const
{ {
if (!this->size_) return node_ptr(); if (!this->size_) return node_ptr();
std::size_t hash = this->hash_function()(k); std::size_t hash = this->hash_function()(k);
return find_node_impl(hash % this->bucket_count_, hash, k, return this->find_node_impl(hash % this->bucket_count_, hash, k,
this->key_eq()); this->key_eq());
} }
@@ -167,13 +166,6 @@ namespace boost { namespace unordered { namespace detail {
return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1);
} }
float load_factor() const
{
BOOST_ASSERT(this->bucket_count_ != 0);
return static_cast<float>(this->size_)
/ static_cast<float>(this->bucket_count_);
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Constructors // Constructors
@@ -183,7 +175,6 @@ namespace boost { namespace unordered { namespace detail {
node_allocator const& a) node_allocator const& a)
: buckets(a, next_prime(num_buckets)), : buckets(a, next_prime(num_buckets)),
functions(hf, eq), functions(hf, eq),
size_(),
mlf_(1.0f), mlf_(1.0f),
max_load_(0) max_load_(0)
{ {
@@ -192,7 +183,6 @@ namespace boost { namespace unordered { namespace detail {
table(table const& x, node_allocator const& a) table(table const& x, node_allocator const& a)
: buckets(a, x.min_buckets_for_size(x.size_)), : buckets(a, x.min_buckets_for_size(x.size_)),
functions(x), functions(x),
size_(x.size_),
mlf_(x.mlf_), mlf_(x.mlf_),
max_load_(0) max_load_(0)
{ {
@@ -205,7 +195,6 @@ namespace boost { namespace unordered { namespace detail {
table(table& x, move_tag m) table(table& x, move_tag m)
: buckets(x, m), : buckets(x, m),
functions(x), functions(x),
size_(0),
mlf_(1.0f), mlf_(1.0f),
max_load_(0) max_load_(0)
{ {
@@ -215,7 +204,6 @@ namespace boost { namespace unordered { namespace detail {
table(table& x, node_allocator const& a, move_tag m) table(table& x, node_allocator const& a, move_tag m)
: buckets(a, x.bucket_count_), : buckets(a, x.bucket_count_),
functions(x), functions(x),
size_(0),
mlf_(x.mlf_), mlf_(x.mlf_),
max_load_(0) max_load_(0)
{ {
@@ -225,9 +213,8 @@ namespace boost { namespace unordered { namespace detail {
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
// source container in a complete mess. // source container in a complete mess.
table tmp(x, m); buckets tmp(x, m);
tmp.move_buckets_to(*this); tmp.move_buckets_to(*this);
this->size_ = tmp.size_;
this->max_load_ = calculate_max_load(); this->max_load_ = calculate_max_load();
} }
} }
@@ -257,30 +244,30 @@ namespace boost { namespace unordered { namespace detail {
if(this->node_alloc() == x.node_alloc()) { if(this->node_alloc() == x.node_alloc()) {
this->buckets::move(x); // no throw this->buckets::move(x); // no throw
this->size_ = x.size_; this->mlf_ = x.mlf_;
this->max_load_ = x.max_load_; this->max_load_ = x.max_load_;
x.size_ = 0;
} }
else { else {
// Create new buckets in separate buckets // Create new buckets in separate buckets
// which will clean up if anything throws an exception. // which will clean up if anything throws an exception.
buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_));
if (x.size_) { if (x.size_) {
// Use a temporary table because move_buckets_to leaves the // Use a temporary table because move_buckets_to leaves the
// source container in a complete mess. // source container in a complete mess.
table tmp(x, move_tag()); buckets tmp(x, move_tag());
tmp.move_buckets_to(b); tmp.move_buckets_to(b);
b.swap(*this);
this->mlf_ = x.mlf_;
this->max_load_ = calculate_max_load();
}
else {
b.swap(*this);
this->mlf_ = x.mlf_;
} }
// Start updating the data here, no throw from now on.
this->size_ = x.size_;
b.swap(*this);
this->max_load_ = x.size_ ? calculate_max_load() : 0;
} }
// We've made it, the rest is no throw.
this->mlf_ = x.mlf_;
new_func_this.commit(); new_func_this.commit();
} }
@@ -304,7 +291,6 @@ namespace boost { namespace unordered { namespace detail {
op2.commit(); op2.commit();
} }
std::swap(this->size_, x.size_);
std::swap(this->mlf_, x.mlf_); std::swap(this->mlf_, x.mlf_);
std::swap(this->max_load_, x.max_load_); std::swap(this->max_load_, x.max_load_);
} }
@@ -326,7 +312,6 @@ namespace boost { namespace unordered { namespace detail {
void partial_swap(table& x) void partial_swap(table& x)
{ {
this->buckets::swap(x, false_type()); this->buckets::swap(x, false_type());
std::swap(this->size_, x.size_);
std::swap(this->mlf_, x.mlf_); std::swap(this->mlf_, x.mlf_);
std::swap(this->max_load_, x.max_load_); std::swap(this->max_load_, x.max_load_);
} }
@@ -365,28 +350,6 @@ namespace boost { namespace unordered { namespace detail {
// //
// no throw // no throw
void clear()
{
if(!this->size_) return;
bucket_ptr end = this->get_bucket(this->bucket_count_);
node_ptr n = (end)->next_;
while(BOOST_UNORDERED_BORLAND_BOOL(n))
{
node_ptr node_to_delete = n;
n = n->next_;
this->delete_node(node_to_delete);
}
++end;
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
begin->next_ = bucket_ptr();
}
this->size_ = 0;
}
std::size_t erase_key(key_type const& k) std::size_t erase_key(key_type const& k)
{ {
if(!this->size_) return 0; if(!this->size_) return 0;
@@ -413,50 +376,14 @@ namespace boost { namespace unordered { namespace detail {
node_ptr pos = prev->next_; node_ptr pos = prev->next_;
node_ptr end = node::next_group(pos); node_ptr end = node::next_group(pos);
prev->next_ = end; prev->next_ = end;
this->fix_buckets(bucket, prev, end); this->fix_buckets(bucket, prev, end);
return this->delete_nodes(pos, end);
std::size_t count = this->delete_nodes(pos, end);
this->size_ -= count;
return count;
}
node_ptr erase(node_ptr r)
{
BOOST_ASSERT(r);
node_ptr next = r->next_;
bucket_ptr bucket = this->get_bucket(
node::get_hash(r) % this->bucket_count_);
node_ptr prev = node::unlink_node(*bucket, r);
this->fix_buckets(bucket, prev, next);
this->delete_node(r);
--this->size_;
return next;
}
node_ptr erase_range(node_ptr r1, node_ptr r2)
{
if (r1 == r2) return r2;
std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_;
node_ptr prev = node::unlink_nodes(
this->buckets_[bucket_index], r1, r2);
this->fix_buckets_range(bucket_index, prev, r1, r2);
this->size_ -= this->delete_nodes(r1, r2);
return r2;
} }
// Reserve and rehash // Reserve and rehash
bool reserve_for_insert(std::size_t); bool reserve_for_insert(std::size_t);
void rehash(std::size_t); void rehash(std::size_t);
void rehash_impl(std::size_t);
}; };
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -480,7 +407,8 @@ namespace boost { namespace unordered { namespace detail {
= this->min_buckets_for_size((std::max)(size, = this->min_buckets_for_size((std::max)(size,
this->size_ + (this->size_ >> 1))); this->size_ + (this->size_ >> 1)));
if (num_buckets != this->bucket_count_) { if (num_buckets != this->bucket_count_) {
rehash_impl(num_buckets); this->rehash_impl(num_buckets);
this->max_load_ = calculate_max_load();
return true; return true;
} }
} }
@@ -506,39 +434,13 @@ namespace boost { namespace unordered { namespace detail {
// no throw: // no throw:
min_buckets = next_prime((std::max)(min_buckets, min_buckets = next_prime((std::max)(min_buckets,
double_to_size_t(floor(this->size_ / (double) mlf_)) + 1)); double_to_size_t(floor(this->size_ / (double) mlf_)) + 1));
if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); if(min_buckets != this->bucket_count_) {
this->rehash_impl(min_buckets);
this->max_load_ = calculate_max_load();
}
} }
} }
// strong otherwise exception safety
template <class T>
void table<T>::rehash_impl(std::size_t num_buckets)
{
std::size_t size = this->size_;
BOOST_ASSERT(size);
buckets dst(this->node_alloc(), num_buckets);
dst.create_buckets();
bucket_ptr src_start = this->get_bucket(this->bucket_count_);
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
dst_start->next_ = src_start->next_;
src_start->next_ = bucket_ptr();
// No need to do this, since the following is 'no throw'.
//this->size_ = 0;
node_ptr prev = dst_start;
while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_))
prev = dst.place_in_bucket(prev, node::next_group2(prev));
// Swap the new nodes back into the container and setup the
// variables.
dst.swap(*this); // no throw
this->size_ = size;
this->max_load_ = calculate_max_load();
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// types // types