diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index cb6b14bc..9deb00e8 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -115,6 +115,8 @@ template struct table_impl; template struct grouped_node; template struct grouped_ptr_node; template struct grouped_table_impl; +template struct node_algo; +template struct grouped_node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; @@ -2533,6 +2535,7 @@ struct table : boost::unordered::detail::functions @@ -2566,14 +2569,6 @@ struct table : boost::unordered::detail::functions(n->next_); - } - //////////////////////////////////////////////////////////////////////// // Data access @@ -2610,7 +2605,8 @@ struct table : boost::unordered::detail::functionshash_) == index) { ++count; - n = next_node(n); + n = node_algo::next_node(n); } return count; @@ -3103,20 +3099,88 @@ struct table : boost::unordered::detail::functions(this)->find_node_impl( - policy::apply_hash(hf, k), k, eq); + return this->find_node_impl(policy::apply_hash(hf, k), k, eq); } node_pointer find_node(std::size_t key_hash, const_key_type& k) const { - return static_cast(this)->find_node_impl( - key_hash, k, this->key_eq()); + return this->find_node_impl(key_hash, k, this->key_eq()); } node_pointer find_node(const_key_type& k) const { - return static_cast(this)->find_node_impl( - hash(k), k, this->key_eq()); + return this->find_node_impl(hash(k), k, this->key_eq()); + } + + template + node_pointer find_node_impl( + std::size_t key_hash, Key const& k, Pred const& eq) const + { + std::size_t bucket_index = this->hash_to_bucket(key_hash); + node_pointer n = this->begin(bucket_index); + + for (;;) { + if (!n) + return n; + + std::size_t node_hash = n->hash_; + if (key_hash == node_hash) { + if (eq(k, this->get_key(n->value()))) + return n; + } else { + if (this->hash_to_bucket(node_hash) != bucket_index) + return node_pointer(); + } + + n = node_algo::next_for_find(n); + } + } + + // Find the node before the key, so that it can be erased. + link_pointer find_previous_node( + const_key_type& k, std::size_t key_hash, std::size_t bucket_index) + { + link_pointer prev = this->get_previous_start(bucket_index); + if (!prev) { + return prev; + } + + for (;;) { + if (!prev->next_) { + return link_pointer(); + } + std::size_t node_hash = node_algo::next_node(prev)->hash_; + if (this->hash_to_bucket(node_hash) != bucket_index) { + return link_pointer(); + } + if (node_hash == key_hash && + this->key_eq()( + k, this->get_key(node_algo::next_node(prev)->value()))) { + return prev; + } + prev = node_algo::next_for_erase(prev); + } + } + + // Extract and erase + + inline node_pointer extract_by_key(const_key_type& k) + { + if (!this->size_) { + return node_pointer(); + } + std::size_t key_hash = this->hash(k); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + if (!prev) { + return node_pointer(); + } + node_pointer n = node_algo::extract_first_node(prev); + --this->size_; + this->fix_bucket(bucket_index, prev); + n->next_ = link_pointer(); + + return n; } // Reserve and rehash @@ -3124,6 +3188,7 @@ struct table : boost::unordered::detail::functions::reserve_for_insert(std::size_t size) min_buckets_for_size((std::max)(size, size_ + (size_ >> 1))); if (num_buckets != bucket_count_) - static_cast(this)->rehash_impl(num_buckets); + this->rehash_impl(num_buckets); } } @@ -3162,7 +3227,7 @@ inline void table::rehash(std::size_t min_buckets) 1)); if (min_buckets != bucket_count_) - static_cast(this)->rehash_impl(min_buckets); + this->rehash_impl(min_buckets); } } @@ -3173,6 +3238,17 @@ inline void table::reserve(std::size_t num_elements) std::ceil(static_cast(num_elements) / mlf_))); } +template +inline void table::rehash_impl(std::size_t num_buckets) +{ + BOOST_ASSERT(this->buckets_); + + this->create_buckets(num_buckets); + link_pointer prev = this->get_previous_start(); + while (prev->next_) + prev = node_algo::place_in_bucket(*this, prev); +} + #if defined(BOOST_MSVC) #pragma warning(pop) #endif @@ -3333,6 +3409,10 @@ struct unique_node : boost::unordered::detail::value_base typedef typename ::boost::unordered::detail::allocator_traits< allocator>::pointer node_pointer; typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; link_pointer next_; std::size_t hash_; @@ -3351,6 +3431,7 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket typedef boost::unordered::detail::ptr_bucket bucket_base; typedef ptr_node* node_pointer; typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; std::size_t hash_; boost::unordered::detail::value_base value_base_; @@ -3367,6 +3448,64 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket ptr_node& operator=(ptr_node const&); }; +template struct node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast(n->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + // Add node 'n' after 'pos'. + // This results in a different order to the grouped implementation. + static inline void add_to_node_group(node_pointer n, node_pointer pos) + { + n->next_ = pos->next_; + pos->next_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + prev->next_ = n->next_; + return n; + } + + // Extract a node and place it in the correct bucket. + // TODO: For tables with equivalent keys, this doesn't preserve + // the order. + // pre: prev->next_ is not null. + template + static link_pointer place_in_bucket(Table& dst, link_pointer prev) + { + node_pointer n = next_node(prev); + bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_)); + + if (!b->next_) { + b->next_ = prev; + return n; + } else { + prev->next_ = n->next_; + n->next_ = b->next_->next_; + b->next_->next_ = n; + return prev; + } + } +}; + // If the allocator uses raw pointers use ptr_node // Otherwise use node. @@ -3413,6 +3552,7 @@ template struct pick_node typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::node_algo node_algo; }; template @@ -3435,6 +3575,7 @@ struct table_impl : boost::unordered::detail::table typedef typename table::extractor extractor; typedef typename table::iterator iterator; typedef typename table::c_iterator c_iterator; + typedef typename table::node_algo node_algo; typedef std::pair emplace_return; @@ -3470,39 +3611,8 @@ struct table_impl : boost::unordered::detail::table this->move_init(x); } - // Node functions. - - static inline node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - // Accessors - template - node_pointer find_node_impl( - std::size_t key_hash, Key const& k, Pred const& eq) const - { - std::size_t bucket_index = this->hash_to_bucket(key_hash); - node_pointer n = this->begin(bucket_index); - - for (;;) { - if (!n) - return n; - - std::size_t node_hash = n->hash_; - if (key_hash == node_hash) { - if (eq(k, this->get_key(n->value()))) - return n; - } else { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); - } - - n = next_node(n); - } - } - std::size_t count(const_key_type& k) const { return this->find_node(k) ? 1 : 0; @@ -3523,7 +3633,8 @@ struct table_impl : boost::unordered::detail::table std::pair equal_range(const_key_type& k) const { node_pointer n = this->find_node(k); - return std::make_pair(iterator(n), iterator(n ? next_node(n) : n)); + return std::make_pair( + iterator(n), iterator(n ? node_algo::next_node(n) : n)); } // equals @@ -3533,7 +3644,8 @@ struct table_impl : boost::unordered::detail::table if (this->size_ != other.size_) return false; - for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) { + for (node_pointer n1 = this->begin(); n1; + n1 = node_algo::next_node(n1)) { node_pointer n2 = other.find_node(other.get_key(n1->value())); if (!n2 || n1->value() != n2->value()) @@ -3555,8 +3667,8 @@ struct table_impl : boost::unordered::detail::table link_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket( - this->hash_to_bucket(next_node(start_node)->hash_)) + this->get_bucket(this->hash_to_bucket( + node_algo::next_node(start_node)->hash_)) ->next_ = n; } @@ -3846,7 +3958,7 @@ struct table_impl : boost::unordered::detail::table link_pointer prev = other.get_previous_start(); while (prev->next_) { - node_pointer n = other.next_node(prev); + node_pointer n = Types2::node_algo::next_node(prev); const_key_type& k = this->get_key(n->value()); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3943,25 +4055,6 @@ struct table_impl : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // Extract - inline node_pointer extract_by_key(const_key_type& k) - { - if (!this->size_) { - return node_pointer(); - } - std::size_t key_hash = this->hash(k); - std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = find_previous_node(k, key_hash, bucket_index); - if (!prev) { - return node_pointer(); - } - node_pointer n = next_node(prev); - prev->next_ = n->next_; - --this->size_; - this->fix_bucket(bucket_index, prev); - n->next_ = link_pointer(); - return n; - } - inline node_pointer extract_by_iterator(c_iterator i) { node_pointer n = i.node_; @@ -3984,40 +4077,16 @@ struct table_impl : boost::unordered::detail::table // // no throw - link_pointer find_previous_node( - const_key_type& k, std::size_t key_hash, std::size_t bucket_index) - { - link_pointer prev = this->get_previous_start(bucket_index); - if (!prev) { - return prev; - } - - for (;;) { - if (!prev->next_) { - return link_pointer(); - } - std::size_t node_hash = next_node(prev)->hash_; - if (this->hash_to_bucket(node_hash) != bucket_index) { - return link_pointer(); - } - if (node_hash == key_hash && - this->key_eq()(k, this->get_key(next_node(prev)->value()))) { - return prev; - } - prev = prev->next_; - } - } - std::size_t erase_key(const_key_type& k) { if (!this->size_) return 0; std::size_t key_hash = this->hash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); if (!prev) return 0; - link_pointer end = next_node(prev)->next_; + link_pointer end = node_algo::next_node(prev)->next_; this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); return 1; @@ -4026,7 +4095,7 @@ struct table_impl : boost::unordered::detail::table iterator erase(c_iterator r) { BOOST_ASSERT(r.node_); - node_pointer next = next_node(r.node_); + node_pointer next = node_algo::next_node(r.node_); erase_nodes(r.node_, next); return iterator(next); } @@ -4062,7 +4131,7 @@ struct table_impl : boost::unordered::detail::table { this->create_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = next_node(n)) { + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), n->hash_); @@ -4073,7 +4142,7 @@ struct table_impl : boost::unordered::detail::table { this->create_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = next_node(n)) { + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), n->hash_); @@ -4083,7 +4152,7 @@ struct table_impl : boost::unordered::detail::table void assign_buckets(table const& src) { node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = next_node(n)) { + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { this->add_node(holder.copy_of(n->value()), n->hash_); } } @@ -4091,39 +4160,10 @@ struct table_impl : boost::unordered::detail::table void move_assign_buckets(table& src) { node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = next_node(n)) { + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { this->add_node(holder.move_copy_of(n->value()), n->hash_); } } - - // strong otherwise exception safety - void rehash_impl(std::size_t num_buckets) - { - BOOST_ASSERT(this->buckets_); - - this->create_buckets(num_buckets); - link_pointer prev = this->get_previous_start(); - while (prev->next_) - prev = place_in_bucket(*this, prev); - } - - // Iterate through the nodes placing them in the correct buckets. - // pre: prev->next_ is not null. - static link_pointer place_in_bucket(table& dst, link_pointer prev) - { - node_pointer n = next_node(prev); - bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_)); - - if (!b->next_) { - b->next_ = prev; - return n; - } else { - prev->next_ = n->next_; - n->next_ = b->next_->next_; - b->next_->next_ = n; - return prev; - } - } }; //////////////////////////////////////////////////////////////////////// @@ -4137,6 +4177,10 @@ struct grouped_node : boost::unordered::detail::value_base typedef typename ::boost::unordered::detail::allocator_traits< allocator>::pointer node_pointer; typedef node_pointer link_pointer; + typedef typename ::boost::unordered::detail::rebind_wrap >::type bucket_allocator; + typedef typename ::boost::unordered::detail::allocator_traits< + bucket_allocator>::pointer bucket_pointer; link_pointer next_; node_pointer group_prev_; @@ -4157,6 +4201,7 @@ struct grouped_ptr_node : boost::unordered::detail::ptr_bucket typedef boost::unordered::detail::ptr_bucket bucket_base; typedef grouped_ptr_node* node_pointer; typedef ptr_bucket* link_pointer; + typedef ptr_bucket* bucket_pointer; node_pointer group_prev_; std::size_t hash_; @@ -4174,6 +4219,123 @@ struct grouped_ptr_node : boost::unordered::detail::ptr_bucket grouped_ptr_node& operator=(grouped_ptr_node const&); }; +template struct grouped_node_algo +{ + typedef typename N::node_pointer node_pointer; + typedef typename N::link_pointer link_pointer; + typedef typename N::bucket_pointer bucket_pointer; + + static node_pointer next_node(link_pointer n) + { + return static_cast(n->next_); + } + + static node_pointer next_for_find(node_pointer n) + { + return static_cast(n->group_prev_->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return static_cast(prev->next_)->group_prev_; + } + + // The 'void*' arguments are pointers to the table, which we + // will ignore, but without groups they could be used to + // access the various functions for dealing with values and keys. + static node_pointer next_group(node_pointer(n), void const*) + { + return static_cast(n->group_prev_->next_); + } + + static std::size_t count(node_pointer n, void const*) + { + std::size_t x = 0; + node_pointer it = n; + do { + it = it->group_prev_; + ++x; + } while (it != n); + + return x; + } + + // Adds node 'n' to the group containing 'pos'. + // If 'pos' is the first node in group, add to the end of the group, + // otherwise add before 'pos'. Other versions will probably behave + // differently. + static inline void add_to_node_group(node_pointer n, node_pointer pos) + { + n->next_ = pos->group_prev_->next_; + n->group_prev_ = pos->group_prev_; + pos->group_prev_->next_ = n; + pos->group_prev_ = n; + } + + static inline node_pointer extract_first_node(link_pointer prev) + { + node_pointer n = next_node(prev); + if (n->group_prev_ != n) { + node_pointer next = next_node(n); + next->group_prev_ = n->group_prev_; + n->group_prev_ = n; + } + prev->next_ = n->next_; + return n; + } + + // Split the groups containing 'i' and 'j' so that they can + // be safely erased/extracted. + static link_pointer split_groups(node_pointer i, node_pointer j) + { + node_pointer prev = i->group_prev_; + if (prev->next_ != i) + prev = node_pointer(); + + if (j) { + node_pointer first = j; + while (first != i && first->group_prev_->next_ == first) { + first = first->group_prev_; + } + + boost::swap(first->group_prev_, j->group_prev_); + if (first == i) + return prev; + } + + if (prev) { + node_pointer first = prev; + while (first->group_prev_->next_ == first) { + first = first->group_prev_; + } + boost::swap(first->group_prev_, i->group_prev_); + } + + return prev; + } + + // Extract a group of nodes and place them in the correct bucket. + // pre: prev->next_ is not null. + template + static link_pointer place_in_bucket(Table& dst, link_pointer prev) + { + node_pointer end = static_cast(prev->next_)->group_prev_; + + bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_)); + + if (!b->next_) { + b->next_ = prev; + return end; + } else { + link_pointer next = end->next_; + end->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + return prev; + } + } +}; + // If the allocator uses raw pointers use grouped_ptr_node // Otherwise use grouped_node. @@ -4221,6 +4383,7 @@ template struct pick_grouped_node typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef boost::unordered::detail::grouped_node_algo node_algo; }; template @@ -4243,6 +4406,7 @@ struct grouped_table_impl : boost::unordered::detail::table typedef typename table::extractor extractor; typedef typename table::iterator iterator; typedef typename table::c_iterator c_iterator; + typedef typename table::node_algo node_algo; // Constructors @@ -4278,64 +4442,19 @@ struct grouped_table_impl : boost::unordered::detail::table this->move_init(x); } - // Node functions. - - static inline node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static inline node_pointer next_group(node_pointer n) - { - return static_cast(n->group_prev_->next_); - } - // Accessors - template - node_pointer find_node_impl( - std::size_t key_hash, Key const& k, Pred const& eq) const - { - std::size_t bucket_index = this->hash_to_bucket(key_hash); - node_pointer n = this->begin(bucket_index); - - for (;;) { - if (!n) - return n; - - std::size_t node_hash = n->hash_; - if (key_hash == node_hash) { - if (eq(k, this->get_key(n->value()))) - return n; - } else { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); - } - - n = next_group(n); - } - } - std::size_t count(const_key_type& k) const { node_pointer n = this->find_node(k); - if (!n) - return 0; - - std::size_t x = 0; - node_pointer it = n; - do { - it = it->group_prev_; - ++x; - } while (it != n); - - return x; + return n ? node_algo::count(n, this) : 0; } std::pair equal_range(const_key_type& k) const { node_pointer n = this->find_node(k); - return std::make_pair(iterator(n), iterator(n ? next_group(n) : n)); + return std::make_pair( + iterator(n), iterator(n ? node_algo::next_group(n, this) : n)); } // Equality @@ -4349,8 +4468,8 @@ struct grouped_table_impl : boost::unordered::detail::table node_pointer n2 = other.find_node(other.get_key(n1->value())); if (!n2) return false; - node_pointer end1 = next_group(n1); - node_pointer end2 = next_group(n2); + node_pointer end1 = node_algo::next_group(n1, this); + node_pointer end2 = node_algo::next_group(n2, this); if (!group_equals(n1, end1, n2, end2)) return false; n1 = end1; @@ -4366,8 +4485,8 @@ struct grouped_table_impl : boost::unordered::detail::table if (n1->value() != n2->value()) break; - n1 = next_node(n1); - n2 = next_node(n2); + n1 = node_algo::next_node(n1); + n2 = node_algo::next_node(n2); if (n1 == end1) return n2 == end2; @@ -4376,8 +4495,8 @@ struct grouped_table_impl : boost::unordered::detail::table } for (node_pointer n1a = n1, n2a = n2;;) { - n1a = next_node(n1a); - n2a = next_node(n2a); + n1a = node_algo::next_node(n1a); + n2a = node_algo::next_node(n2a); if (n1a == end1) { if (n2a == end2) @@ -4391,13 +4510,14 @@ struct grouped_table_impl : boost::unordered::detail::table } node_pointer start = n1; - for (; n1 != end1; n1 = next_node(n1)) { + for (; n1 != end1; n1 = node_algo::next_node(n1)) { value_type const& v = n1->value(); if (!find(start, n1, v)) { std::size_t matches = count_equal(n2, end2, v); if (!matches) return false; - if (matches != 1 + count_equal(next_node(n1), end1, v)) + if (matches != + 1 + count_equal(node_algo::next_node(n1), end1, v)) return false; } } @@ -4407,7 +4527,7 @@ struct grouped_table_impl : boost::unordered::detail::table static bool find(node_pointer n, node_pointer end, value_type const& v) { - for (; n != end; n = next_node(n)) + for (; n != end; n = node_algo::next_node(n)) if (n->value() == v) return true; return false; @@ -4417,7 +4537,7 @@ struct grouped_table_impl : boost::unordered::detail::table node_pointer n, node_pointer end, value_type const& v) { std::size_t count = 0; - for (; n != end; n = next_node(n)) + for (; n != end; n = node_algo::next_node(n)) if (n->value() == v) ++count; return count; @@ -4425,26 +4545,15 @@ struct grouped_table_impl : boost::unordered::detail::table // Emplace/Insert - // Add node 'n' to the group containing 'pos'. - // If 'pos' is the first node in group, add to the end of the group, - // otherwise add before 'pos'. - static inline void add_to_node_group(node_pointer n, node_pointer pos) - { - n->next_ = pos->group_prev_->next_; - n->group_prev_ = pos->group_prev_; - pos->group_prev_->next_ = n; - pos->group_prev_ = n; - } - inline node_pointer add_node( node_pointer n, std::size_t key_hash, node_pointer pos) { n->hash_ = key_hash; if (pos) { - this->add_to_node_group(n, pos); + node_algo::add_to_node_group(n, pos); if (n->next_) { std::size_t next_bucket = - this->hash_to_bucket(next_node(n)->hash_); + this->hash_to_bucket(node_algo::next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } @@ -4457,7 +4566,8 @@ struct grouped_table_impl : boost::unordered::detail::table if (start_node->next_) { this->get_bucket( - this->hash_to_bucket(next_node(start_node)->hash_)) + this->hash_to_bucket( + node_algo::next_node(start_node)->hash_)) ->next_ = n; } @@ -4476,9 +4586,10 @@ struct grouped_table_impl : boost::unordered::detail::table inline node_pointer add_using_hint(node_pointer n, node_pointer hint) { n->hash_ = hint->hash_; - this->add_to_node_group(n, hint); + node_algo::add_to_node_group(n, hint); if (n->next_ != hint && n->next_) { - std::size_t next_bucket = this->hash_to_bucket(next_node(n)->hash_); + std::size_t next_bucket = + this->hash_to_bucket(node_algo::next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(n->hash_)) { this->get_bucket(next_bucket)->next_ = n; } @@ -4653,43 +4764,16 @@ struct grouped_table_impl : boost::unordered::detail::table //////////////////////////////////////////////////////////////////////// // Extract - inline node_pointer extract_by_key(const_key_type& k) - { - if (!this->size_) { - return node_pointer(); - } - std::size_t key_hash = this->hash(k); - std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = find_previous_node(k, key_hash, bucket_index); - if (!prev) { - return node_pointer(); - } - node_pointer n = next_node(prev); - - if (n->group_prev_ != n) { - node_pointer next = next_node(n); - next->group_prev_ = n->group_prev_; - n->group_prev_ = n; - } - - prev->next_ = n->next_; - --this->size_; - this->fix_bucket(bucket_index, prev); - n->next_ = link_pointer(); - - return n; - } - inline node_pointer extract_by_iterator(c_iterator n) { node_pointer i = n.node_; BOOST_ASSERT(i); - node_pointer j(next_node(i)); + node_pointer j(node_algo::next_node(i)); std::size_t bucket_index = this->hash_to_bucket(i->hash_); // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while // we're at it. - link_pointer prev = split_groups(i, j); + link_pointer prev = node_algo::split_groups(i, j); // If we don't have a 'prev' it means that i is at the // beginning of a block, so search through the blocks in the @@ -4697,7 +4781,7 @@ struct grouped_table_impl : boost::unordered::detail::table if (!prev) { prev = this->get_previous_start(bucket_index); while (prev->next_ != i) { - prev = next_node(prev)->group_prev_; + prev = node_algo::next_for_erase(prev); } } @@ -4714,31 +4798,6 @@ struct grouped_table_impl : boost::unordered::detail::table // // no throw - link_pointer find_previous_node( - const_key_type& k, std::size_t key_hash, std::size_t bucket_index) - { - link_pointer prev = this->get_previous_start(bucket_index); - if (!prev) { - return prev; - } - - for (;;) { - if (!prev->next_) { - return link_pointer(); - } - node_pointer first_node = next_node(prev); - std::size_t node_hash = first_node->hash_; - if (this->hash_to_bucket(node_hash) != bucket_index) { - return link_pointer(); - } - if (node_hash == key_hash && - this->key_eq()(k, this->get_key(first_node->value()))) { - return prev; - } - prev = first_node->group_prev_; - } - } - std::size_t erase_key(const_key_type& k) { if (!this->size_) @@ -4746,12 +4805,12 @@ struct grouped_table_impl : boost::unordered::detail::table std::size_t key_hash = this->hash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); if (!prev) return 0; - node_pointer first_node = next_node(prev); - link_pointer end = first_node->group_prev_->next_; + node_pointer first_node = node_algo::next_node(prev); + link_pointer end = node_algo::next_group(first_node, this); std::size_t deleted_count = this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -4761,7 +4820,7 @@ struct grouped_table_impl : boost::unordered::detail::table iterator erase(c_iterator r) { BOOST_ASSERT(r.node_); - node_pointer next = next_node(r.node_); + node_pointer next = node_algo::next_node(r.node_); erase_nodes(r.node_, next); return iterator(next); } @@ -4781,20 +4840,22 @@ struct grouped_table_impl : boost::unordered::detail::table // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while // we're at it. - link_pointer prev = split_groups(i, j); + link_pointer prev = node_algo::split_groups(i, j); // If we don't have a 'prev' it means that i is at the // beginning of a block, so search through the blocks in the // same bucket. if (!prev) { prev = this->get_previous_start(bucket_index); - while (prev->next_ != i) - prev = next_node(prev)->group_prev_; + while (prev->next_ != i) { + prev = node_algo::next_for_erase(prev); + } } // Delete the nodes. do { - link_pointer group_end = next_group(next_node(prev)); + link_pointer group_end = + node_algo::next_group(node_algo::next_node(prev), this); this->delete_nodes(prev, group_end); bucket_index = this->fix_bucket(bucket_index, prev); } while (prev->next_ != j); @@ -4802,34 +4863,6 @@ struct grouped_table_impl : boost::unordered::detail::table return prev; } - static link_pointer split_groups(node_pointer i, node_pointer j) - { - node_pointer prev = i->group_prev_; - if (prev->next_ != i) - prev = node_pointer(); - - if (j) { - node_pointer first = j; - while (first != i && first->group_prev_->next_ == first) { - first = first->group_prev_; - } - - boost::swap(first->group_prev_, j->group_prev_); - if (first == i) - return prev; - } - - if (prev) { - node_pointer first = prev; - while (first->group_prev_->next_ == first) { - first = first->group_prev_; - } - boost::swap(first->group_prev_, i->group_prev_); - } - - return prev; - } - //////////////////////////////////////////////////////////////////////// // fill_buckets @@ -4839,12 +4872,13 @@ struct grouped_table_impl : boost::unordered::detail::table for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); + node_pointer group_end(node_algo::next_group(n, this)); node_pointer pos = this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) { + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, pos); @@ -4858,12 +4892,13 @@ struct grouped_table_impl : boost::unordered::detail::table for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); + node_pointer group_end(node_algo::next_group(n, this)); node_pointer pos = this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) { + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { this->add_node(boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, pos); @@ -4876,10 +4911,11 @@ struct grouped_table_impl : boost::unordered::detail::table node_holder holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); + node_pointer group_end(node_algo::next_group(n, this)); node_pointer pos = this->add_node( holder.copy_of(n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) { + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { this->add_node(holder.copy_of(n->value()), key_hash, pos); } } @@ -4890,44 +4926,15 @@ struct grouped_table_impl : boost::unordered::detail::table node_holder holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(next_group(n)); + node_pointer group_end(node_algo::next_group(n, this)); node_pointer pos = this->add_node( holder.move_copy_of(n->value()), key_hash, node_pointer()); - for (n = next_node(n); n != group_end; n = next_node(n)) { + for (n = node_algo::next_node(n); n != group_end; + n = node_algo::next_node(n)) { this->add_node(holder.move_copy_of(n->value()), key_hash, pos); } } } - - // strong otherwise exception safety - void rehash_impl(std::size_t num_buckets) - { - BOOST_ASSERT(this->buckets_); - - this->create_buckets(num_buckets); - link_pointer prev = this->get_previous_start(); - while (prev->next_) - prev = place_in_bucket(*this, prev, next_node(prev)->group_prev_); - } - - // Iterate through the nodes placing them in the correct buckets. - // pre: prev->next_ is not null. - static link_pointer place_in_bucket( - table& dst, link_pointer prev, node_pointer end) - { - bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_)); - - if (!b->next_) { - b->next_ = prev; - return end; - } else { - link_pointer next = end->next_; - end->next_ = b->next_->next_; - b->next_->next_ = prev->next_; - prev->next_ = next; - return prev; - } - } }; } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 9ea19a9e..70a283f6 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -27,6 +27,7 @@ template struct map typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table_impl table; typedef boost::unordered::detail::map_extractor extractor; @@ -64,6 +65,7 @@ struct multimap typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::grouped_table_impl table; typedef boost::unordered::detail::map_extractor extractor; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 8f1d34ca..e4e08cc7 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -27,6 +27,7 @@ template struct set typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table_impl table; typedef boost::unordered::detail::set_extractor extractor; @@ -63,6 +64,7 @@ template struct multiset typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; + typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::grouped_table_impl table; typedef boost::unordered::detail::set_extractor extractor;