From fa97494cc8e9a510b39e58c5dbfad0eb6bd930be Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2011 18:53:03 +0000 Subject: [PATCH] Unordered: Move some of the unordered implementation. [SVN r73755] --- include/boost/unordered/detail/buckets.hpp | 103 ++++++++++++++- include/boost/unordered/detail/table.hpp | 140 ++++----------------- 2 files changed, 121 insertions(+), 122 deletions(-) diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 21974b9f..927ae534 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -64,6 +64,7 @@ namespace boost { namespace unordered { namespace detail { bucket_ptr buckets_; std::size_t bucket_count_; + std::size_t size_; ::boost::compressed_pair allocators_; // Data access @@ -100,6 +101,7 @@ namespace boost { namespace unordered { namespace detail { buckets(node_allocator const& a, std::size_t bucket_count) : buckets_(), bucket_count_(bucket_count), + size_(), allocators_(a,a) { } @@ -109,6 +111,7 @@ namespace boost { namespace unordered { namespace detail { buckets(buckets& b, move_tag) : buckets_(), bucket_count_(b.bucket_count_), + size_(), allocators_(b.allocators_) { } @@ -138,6 +141,7 @@ namespace boost { namespace unordered { namespace detail { BOOST_ASSERT(node_alloc() == other.node_alloc()); std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); + std::swap(size_, other.size_); } void swap(buckets& other, true_type) @@ -145,6 +149,7 @@ namespace boost { namespace unordered { namespace detail { allocators_.swap(other.allocators_); std::swap(buckets_, other.buckets_); std::swap(bucket_count_, other.bucket_count_); + std::swap(size_, other.size_); } void move(buckets& other) @@ -153,13 +158,15 @@ namespace boost { namespace unordered { namespace detail { if(this->buckets_) { this->delete_buckets(); } this->buckets_ = other.buckets_; this->bucket_count_ = other.bucket_count_; + this->size_ = other.size_; other.buckets_ = bucket_ptr(); other.bucket_count_ = 0; + other.size_ = 0; } 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_; if (!ptr) return 0; ptr = ptr->next_; @@ -177,7 +184,7 @@ namespace boost { namespace unordered { namespace detail { 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]; if (!b.next_) return node_ptr(); return b.next_->next_; @@ -190,6 +197,13 @@ namespace boost { namespace unordered { namespace detail { return buckets_ + static_cast(bucket_index); } + float load_factor() const + { + BOOST_ASSERT(this->bucket_count_ != 0); + return static_cast(this->size_) + / static_cast(this->bucket_count_); + } + //////////////////////////////////////////////////////////////////////// // Delete @@ -201,12 +215,13 @@ namespace boost { namespace unordered { namespace detail { ::boost::unordered::detail::destroy(raw_ptr->value_ptr()); allocator_traits::destroy(node_alloc(), raw_ptr); allocator_traits::deallocate(node_alloc(), real_ptr, 1); + + --this->size_; } void delete_buckets() { bucket_ptr end = this->get_bucket(this->bucket_count_); - node_ptr n = (end)->next_; while(BOOST_UNORDERED_BORLAND_BOOL(n)) { @@ -224,6 +239,7 @@ namespace boost { namespace unordered { namespace detail { allocator_traits::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1); this->buckets_ = bucket_ptr(); + BOOST_ASSERT(this->size_ == 0); } std::size_t delete_nodes(node_ptr begin, node_ptr end) @@ -238,6 +254,57 @@ namespace boost { namespace unordered { namespace detail { 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 // the bucket pointers. 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 move_buckets_to(buckets&) const; + void rehash_impl(std::size_t); }; // 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::set_hash(first_node, hash); node_ptr end = prev->next_ = first_node; + ++dst.size_; for(n = n->next_; n != group_end; n = n->next_) { a.construct(node::get_value(n)); end = a.release(); node::set_hash(end, hash); node::add_after_node(end, first_node); + ++dst.size_; } prev = dst.place_in_bucket(prev, end); @@ -690,12 +760,39 @@ namespace boost { namespace unordered { namespace detail { end = a.release(); node::set_hash(end, hash); node::add_after_node(end, first_node); + ++dst.size_; } prev = dst.place_in_bucket(prev, end); } } } + + // strong otherwise exception safety + template + void buckets::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 diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 17b73592..ecbf4dfe 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -42,7 +42,6 @@ namespace boost { namespace unordered { namespace detail { // Members - std::size_t size_; float mlf_; std::size_t max_load_; @@ -92,7 +91,7 @@ namespace boost { namespace unordered { namespace detail { { if (!this->size_) return node_ptr(); 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( @@ -101,14 +100,14 @@ namespace boost { namespace unordered { namespace detail { key_type const& k) const { 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 { if (!this->size_) return node_ptr(); 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()); } @@ -167,13 +166,6 @@ namespace boost { namespace unordered { namespace detail { 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(this->size_) - / static_cast(this->bucket_count_); - } - //////////////////////////////////////////////////////////////////////// // Constructors @@ -183,7 +175,6 @@ namespace boost { namespace unordered { namespace detail { node_allocator const& a) : buckets(a, next_prime(num_buckets)), functions(hf, eq), - size_(), mlf_(1.0f), max_load_(0) { @@ -192,7 +183,6 @@ namespace boost { namespace unordered { namespace detail { table(table const& x, node_allocator const& a) : buckets(a, x.min_buckets_for_size(x.size_)), functions(x), - size_(x.size_), mlf_(x.mlf_), max_load_(0) { @@ -205,7 +195,6 @@ namespace boost { namespace unordered { namespace detail { table(table& x, move_tag m) : buckets(x, m), functions(x), - size_(0), mlf_(1.0f), max_load_(0) { @@ -215,7 +204,6 @@ namespace boost { namespace unordered { namespace detail { table(table& x, node_allocator const& a, move_tag m) : buckets(a, x.bucket_count_), functions(x), - size_(0), mlf_(x.mlf_), max_load_(0) { @@ -225,9 +213,8 @@ namespace boost { namespace unordered { namespace detail { else if(x.size_) { // Use a temporary table because move_buckets_to leaves the // source container in a complete mess. - table tmp(x, m); + buckets tmp(x, m); tmp.move_buckets_to(*this); - this->size_ = tmp.size_; this->max_load_ = calculate_max_load(); } } @@ -257,30 +244,30 @@ namespace boost { namespace unordered { namespace detail { if(this->node_alloc() == x.node_alloc()) { this->buckets::move(x); // no throw - this->size_ = x.size_; + this->mlf_ = x.mlf_; this->max_load_ = x.max_load_; - x.size_ = 0; } else { // Create new buckets in separate buckets // which will clean up if anything throws an exception. buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); + if (x.size_) { // Use a temporary table because move_buckets_to leaves the // source container in a complete mess. - table tmp(x, move_tag()); + buckets tmp(x, move_tag()); 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(); } @@ -304,7 +291,6 @@ namespace boost { namespace unordered { namespace detail { op2.commit(); } - std::swap(this->size_, x.size_); std::swap(this->mlf_, x.mlf_); std::swap(this->max_load_, x.max_load_); } @@ -326,7 +312,6 @@ namespace boost { namespace unordered { namespace detail { void partial_swap(table& x) { this->buckets::swap(x, false_type()); - std::swap(this->size_, x.size_); std::swap(this->mlf_, x.mlf_); std::swap(this->max_load_, x.max_load_); } @@ -365,28 +350,6 @@ namespace boost { namespace unordered { namespace detail { // // 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) { if(!this->size_) return 0; @@ -413,50 +376,14 @@ namespace boost { namespace unordered { namespace detail { node_ptr pos = prev->next_; node_ptr end = node::next_group(pos); prev->next_ = end; - this->fix_buckets(bucket, prev, 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; + return this->delete_nodes(pos, end); } // Reserve and rehash bool reserve_for_insert(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->size_ + (this->size_ >> 1))); if (num_buckets != this->bucket_count_) { - rehash_impl(num_buckets); + this->rehash_impl(num_buckets); + this->max_load_ = calculate_max_load(); return true; } } @@ -506,39 +434,13 @@ namespace boost { namespace unordered { namespace detail { // no throw: min_buckets = next_prime((std::max)(min_buckets, 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 - void table::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