diff --git a/.travis.yml b/.travis.yml index 03f49936..db516156 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,14 +38,6 @@ matrix: env: | label="clang 32 bit"; user_config="using clang : : clang++ -m32 -Werror --std=c++03 ;" - - compiler: gcc - env: | - label="gcc C++03 interopable1"; - user_config="using gcc : : g++-4.8 -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=1 ;" - - compiler: clang - env: | - label="gcc C++11 interopable2"; - user_config="using clang : : clang++ -fsanitize=address -Werror --std=c++03 -DBOOST_UNORDERED_INTEROPERABLE_NODES=2 ;" before_script: - cd ${TRAVIS_BUILD_DIR} diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 50baa8ff..ae4ba6ca 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -66,19 +66,6 @@ #define BOOST_UNORDERED_EMPLACE_LIMIT 10 #endif -// BOOST_UNORDERED_INTEROPERABLE_NODES - Use the same node type for -// containers with unique and equivalent keys. -// -// 0 = Use different nodes -// 1 = Use ungrouped nodes everywhere -// 2 = Use grouped nodes everywhere -// -// Might add an extra value to use grouped nodes everywhere later. - -#if !defined(BOOST_UNORDERED_INTEROPERABLE_NODES) -#define BOOST_UNORDERED_INTEROPERABLE_NODES 0 -#endif - // BOOST_UNORDERED_USE_ALLOCATOR_TRAITS - Pick which version of // allocator_traits to use. // @@ -188,11 +175,6 @@ struct ptr_bucket; template struct node; template struct ptr_node; -template struct node_algo; - -template struct grouped_node; -template struct grouped_ptr_node; -template struct grouped_node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; @@ -1709,7 +1691,6 @@ template void node_constructor::create_node() BOOST_UNORDERED_CALL_CONSTRUCT0( node_allocator_traits, alloc_, boost::addressof(*node_)); - node_->init(node_); node_constructed_ = true; } @@ -1953,7 +1934,7 @@ struct l_iterator : public std::iterator(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + if (ptr_ && ptr_->get_bucket() != bucket_) ptr_ = node_pointer(); return *this; } @@ -2017,7 +1998,7 @@ struct cl_iterator cl_iterator& operator++() { ptr_ = static_cast(ptr_->next_); - if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_) != bucket_) + if (ptr_ && ptr_->get_bucket() != bucket_) ptr_ = node_pointer(); return *this; } @@ -2200,7 +2181,6 @@ template struct node_holder { node_pointer n = nodes_; nodes_ = static_cast(nodes_->next_); - n->init(n); n->next_ = link_pointer(); return n; } @@ -2677,7 +2657,6 @@ struct table : boost::unordered::detail::functions @@ -2718,6 +2697,48 @@ struct table : boost::unordered::detail::functions(n->next_); + } + + static node_pointer next_for_find(link_pointer n) + { + node_pointer n2 = static_cast(n); + do { + n2 = next_node(n2); + } while (n2 && !n2->is_first_in_group()); + return n2; + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + node_pointer next_group(node_pointer n) const + { + node_pointer n1 = n; + do { + n1 = next_node(n1); + } while (n1 && !n1->is_first_in_group()); + return n1; + } + + std::size_t group_count(node_pointer n) const + { + std::size_t x = 0; + node_pointer it = n; + do { + ++x; + it = next_node(it); + } while (it && !it->is_first_in_group()); + + return x; + } + + std::size_t node_bucket(node_pointer n) const { return n->get_bucket(); } + bucket_allocator const& bucket_alloc() const { return allocators_.first(); } node_allocator const& node_alloc() const { return allocators_.second(); } @@ -2751,8 +2772,7 @@ struct table : boost::unordered::detail::functionshash_) == index) { + while (n && node_bucket(n) == index) { ++count; - n = node_algo::next_node(n); + n = next_node(n); } return count; @@ -3074,8 +3094,7 @@ struct table : boost::unordered::detail::functions(end)->hash_); + bucket_index2 = node_bucket(static_cast(end)); // If begin and end are in the same bucket, then // there's nothing to do. @@ -3097,16 +3116,17 @@ struct table : boost::unordered::detail::functions:: - propagate_on_container_copy_assignment::value>()); + assign(x, is_unique, + boost::unordered::detail::integral_constant:: + propagate_on_container_copy_assignment::value>()); } } - void assign(table const& x, false_type) + void assign(table const& x, bool is_unique, false_type) { // Strong exception safety. set_hash_functions new_func_this(*this, x); @@ -3121,18 +3141,18 @@ struct table : boost::unordered::detail::functions:: - propagate_on_container_move_assignment::value>()); + x, is_unique, + boost::unordered::detail::integral_constant:: + propagate_on_container_move_assignment::value>()); } } - void move_assign(table& x, true_type) + void move_assign(table& x, bool /* is_unique */, true_type) { delete_buckets(); set_hash_functions new_func_this(*this, x); @@ -3178,7 +3199,7 @@ struct table : boost::unordered::detail::functionshash_; - if (key_hash == node_hash) { - if (eq(k, this->get_key(n))) - return n; - } else { - if (this->hash_to_bucket(node_hash) != bucket_index) - return node_pointer(); + if (eq(k, this->get_key(n))) { + return n; + } else if (this->node_bucket(n) != bucket_index) { + return node_pointer(); } - n = node_algo::next_for_find(n); + n = 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 find_previous_node(const_key_type& k, std::size_t bucket_index) { link_pointer prev = this->get_previous_start(bucket_index); if (!prev) { @@ -3266,18 +3283,17 @@ struct table : boost::unordered::detail::functionsnext_) { + node_pointer n = next_node(prev); + if (!n) { return link_pointer(); + } else if (n->is_first_in_group()) { + if (node_bucket(n) != bucket_index) { + return link_pointer(); + } else if (this->key_eq()(k, this->get_key(n))) { + return prev; + } } - 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)))) { - return prev; - } - prev = node_algo::next_for_erase(prev); + prev = n; } } @@ -3290,11 +3306,16 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) { return node_pointer(); } - node_pointer n = node_algo::extract_first_node(prev); + node_pointer n = next_node(prev); + node_pointer n2 = next_node(n); + if (n2) { + n2->set_first_in_group(); + } + prev->next_ = n2; --this->size_; this->fix_bucket(bucket_index, prev); n->next_ = link_pointer(); @@ -3319,8 +3340,7 @@ struct table : boost::unordered::detail::functionssize_ != other.size_) return false; - for (node_pointer n1 = this->begin(); n1; - n1 = node_algo::next_node(n1)) { + for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) { node_pointer n2 = other.find_node(other.get_key(n1)); if (!n2 || n1->value() != n2->value()) @@ -3334,17 +3354,18 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; + std::size_t bucket = this->hash_to_bucket(key_hash); + bucket_pointer b = this->get_bucket(bucket); - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + // TODO: Do this need to set_first_in_group ? + n->bucket_info_ = bucket; + n->set_first_in_group(); if (!b->next_) { link_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket(this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) - ->next_ = n; + this->get_bucket(node_bucket(next_node(start_node)))->next_ = n; } b->next_ = start_node; @@ -3564,25 +3585,45 @@ struct table : boost::unordered::detail::functions::value)); BOOST_ASSERT(this->node_alloc() == other.node_alloc()); - if (other.size_) { - link_pointer prev = other.get_previous_start(); + if (!other.size_) { + return; + } - while (prev->next_) { - node_pointer n = other_table::node_algo::next_node(prev); - const_key_type& k = this->get_key(n); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); + link_pointer prev = other.get_previous_start(); + node_pointer n = other_table::next_node(prev); + while (n) { + const_key_type& k = this->get_key(n); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); - if (pos) { + if (pos) { + prev = n; + n = other_table::next_node(prev); + } else { + this->reserve_for_insert(this->size_ + 1); + + prev->next_ = n->next_; + --other.size_; + other.fix_bucket(other.node_bucket(n), prev); + this->add_node_unique(n, key_hash); + n = other_table::next_node(prev); + + // If the next node was from the same group, it's now + // the first node in the group. + if (n && !n->is_first_in_group()) { + n->set_first_in_group(); prev = n; - } else { - this->reserve_for_insert(this->size_ + 1); - other_table::node_algo::split_groups( - n, other_table::node_algo::next_node(n)); - prev->next_ = n->next_; - --other.size_; - other.fix_bucket(other.hash_to_bucket(n->hash_), prev); - this->add_node_unique(n, key_hash); + n = other_table::next_node(prev); + } + } + + // Skip over rest of group of nodes with equivalent keys, + // as we know there's already one in the container. + while (n && !n->is_first_in_group()) { + prev = n; + n = other_table::next_node(prev); + if (!n) { + return; } } } @@ -3660,8 +3701,7 @@ struct table : boost::unordered::detail::functionshash_; - std::size_t bucket_index = this->hash_to_bucket(key_hash); + std::size_t bucket_index = this->node_bucket(n); link_pointer prev = this->get_previous_start(bucket_index); while (prev->next_ != n) { prev = prev->next_; @@ -3684,10 +3724,10 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) return 0; - link_pointer end = node_algo::next_node(prev)->next_; + link_pointer end = next_node(prev)->next_; this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); return 1; @@ -3695,7 +3735,7 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); + std::size_t bucket_index = this->node_bucket(i); // Find the node before i. link_pointer prev = this->get_previous_start(bucket_index); @@ -3716,11 +3756,12 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), - n->hash_); + key_hash); } } @@ -3729,27 +3770,30 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), - n->hash_); + key_hash); } } void assign_buckets_unique(table const& src) { node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node_unique(holder.copy_of(n->value()), n->hash_); + for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); + this->add_node_unique(holder.copy_of(n->value()), key_hash); } } void move_assign_buckets_unique(table& src) { node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); + for (node_pointer n = src.begin(); n; n = next_node(n)) { + std::size_t key_hash = this->hash(this->get_key(n)); + this->add_node_unique(holder.move_copy_of(n->value()), key_hash); } } @@ -3767,8 +3811,8 @@ struct table : boost::unordered::detail::functionsvalue() != n2->value()) break; - n1 = node_algo::next_node(n1); - n2 = node_algo::next_node(n2); + n1 = next_node(n1); + n2 = next_node(n2); if (n1 == end1) return n2 == end2; @@ -3794,8 +3838,8 @@ struct table : boost::unordered::detail::functionsvalue(); if (!find_equiv(start, n1, v)) { std::size_t matches = count_equal_equiv(n2, end2, v); if (!matches) return false; - if (matches != - 1 + count_equal_equiv(node_algo::next_node(n1), end1, v)) + if (matches != 1 + count_equal_equiv(next_node(n1), end1, v)) return false; } } @@ -3827,7 +3870,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) return true; return false; @@ -3837,7 +3880,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) ++count; return count; @@ -3848,26 +3891,27 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; + std::size_t bucket = this->hash_to_bucket(key_hash); + n->bucket_info_ = bucket; + if (pos) { - node_algo::add_to_node(n, pos); + n->next_ = pos->next_; + pos->next_ = n; if (n->next_) { - std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); - if (next_bucket != this->hash_to_bucket(key_hash)) { + std::size_t next_bucket = this->node_bucket(next_node(n)); + if (next_bucket != bucket) { this->get_bucket(next_bucket)->next_ = n; } } } else { - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + n->set_first_in_group(); + bucket_pointer b = this->get_bucket(bucket); if (!b->next_) { link_pointer start_node = this->get_previous_start(); if (start_node->next_) { - this->get_bucket( - this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) + this->get_bucket(this->node_bucket(next_node(start_node))) ->next_ = n; } @@ -3885,12 +3929,13 @@ struct table : boost::unordered::detail::functionshash_ = hint->hash_; - node_algo::add_to_node(n, hint); + n->bucket_info_ = hint->bucket_info_; + n->reset_first_in_group(); + n->next_ = hint->next_; + hint->next_ = n; if (n->next_ != hint && n->next_) { - std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); - if (next_bucket != this->hash_to_bucket(n->hash_)) { + std::size_t next_bucket = this->node_bucket(next_node(n)); + if (next_bucket != this->node_bucket(n)) { this->get_bucket(next_bucket)->next_ = n; } } @@ -4023,24 +4068,18 @@ struct table : boost::unordered::detail::functionshash_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 = node_algo::split_groups(i, j); + node_pointer j(next_node(i)); + std::size_t bucket_index = this->node_bucket(i); - // 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 = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } prev->next_ = i->next_; + if (j && i->is_first_in_group()) { + j->set_first_in_group(); + } --this->size_; this->fix_bucket(bucket_index, prev); i->next_ = link_pointer(); @@ -4060,12 +4099,12 @@ struct table : boost::unordered::detail::functionshash(k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, key_hash, bucket_index); + link_pointer prev = this->find_previous_node(k, bucket_index); if (!prev) return 0; - node_pointer first_node = node_algo::next_node(prev); - link_pointer end = node_algo::next_group(first_node, this); + node_pointer first_node = next_node(prev); + link_pointer end = next_group(first_node); std::size_t deleted_count = this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -4074,29 +4113,25 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); + std::size_t bucket_index = this->node_bucket(i); - // Split the groups containing 'i' and 'j'. - // And get the pointer to the node before i while - // we're at it. - 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 = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } // Delete the nodes. // Is it inefficient to call fix_bucket for every node? + bool includes_first = false; do { + includes_first = + includes_first || next_node(prev)->is_first_in_group(); this->delete_node(prev); bucket_index = this->fix_bucket(bucket_index, prev); } while (prev->next_ != j); + if (j && includes_first) { + j->set_first_in_group(); + } return prev; } @@ -4109,14 +4144,13 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + std::size_t key_hash = this->hash(this->get_key(n)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), @@ -4130,14 +4164,13 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + std::size_t key_hash = this->hash(this->get_key(n)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), @@ -4150,12 +4183,11 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + std::size_t key_hash = this->hash(this->get_key(n)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos); } } @@ -4165,12 +4197,11 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { - std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + std::size_t key_hash = this->hash(this->get_key(n)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, pos); } @@ -4225,20 +4256,43 @@ inline void table::rehash_impl(std::size_t num_buckets) this->create_buckets(num_buckets); link_pointer prev = this->get_previous_start(); - while (prev->next_) { - node_pointer group_last = node_algo::last_for_rehash(prev); - bucket_pointer b = - this->get_bucket(this->hash_to_bucket(group_last->hash_)); - if (!b->next_) { - b->next_ = prev; - prev = group_last; - } else { - link_pointer next = group_last->next_; - group_last->next_ = b->next_->next_; - b->next_->next_ = prev->next_; - prev->next_ = next; + BOOST_TRY + { + while (prev->next_) { + node_pointer n = next_node(prev); + std::size_t key_hash = this->hash(this->get_key(n)); + std::size_t bucket_index = this->hash_to_bucket(key_hash); + + n->bucket_info_ = bucket_index; + n->set_first_in_group(); + + // Iterator through the rest of the group of equal nodes, + // setting the bucket. + for (;;) { + node_pointer next = next_node(n); + if (!next || next->is_first_in_group()) { + break; + } + n = next; + n->bucket_info_ = bucket_index; + // n->reset_first_in_group(); + } + + // n is now the last node in the group + bucket_pointer b = this->get_bucket(bucket_index); + if (!b->next_) { + b->next_ = prev; + prev = n; + } else { + link_pointer next = n->next_; + n->next_ = b->next_->next_; + b->next_->next_ = prev->next_; + prev->next_ = next; + } } } + BOOST_CATCH(...) { delete_nodes(prev, link_pointer()); } + BOOST_CATCH_END } #if defined(BOOST_MSVC) @@ -4403,11 +4457,29 @@ struct node : boost::unordered::detail::value_base bucket_allocator>::pointer bucket_pointer; link_pointer next_; - std::size_t hash_; + std::size_t bucket_info_; - node() : next_(), hash_(0) {} + node() : next_(), bucket_info_(0) {} - void init(node_pointer) {} + std::size_t get_bucket() const + { + return bucket_info_ & ((std::size_t)-1 >> 1); + } + + std::size_t is_first_in_group() const + { + return bucket_info_ & ~((std::size_t)-1 >> 1); + } + + void set_first_in_group() + { + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + } + + void reset_first_in_group() + { + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + } private: node& operator=(node const&); @@ -4421,102 +4493,39 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket typedef ptr_bucket* link_pointer; typedef ptr_bucket* bucket_pointer; - std::size_t hash_; + std::size_t bucket_info_; boost::unordered::detail::value_base value_base_; - ptr_node() : bucket_base(), hash_(0) {} - - void init(node_pointer) {} + ptr_node() : bucket_base(), bucket_info_(0) {} void* address() { return value_base_.address(); } value_type& value() { return value_base_.value(); } value_type* value_ptr() { return value_base_.value_ptr(); } + std::size_t get_bucket() const + { + return bucket_info_ & ((std::size_t)-1 >> 1); + } + + std::size_t is_first_in_group() const + { + return bucket_info_ & ~((std::size_t)-1 >> 1); + } + + void set_first_in_group() + { + bucket_info_ = bucket_info_ | ~((std::size_t)-1 >> 1); + } + + void reset_first_in_group() + { + bucket_info_ = bucket_info_ & ((std::size_t)-1 >> 1); + } + private: 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_; - } - - // Group together all nodes with equal hash value, this may - // include nodes with different keys, but that's okay because - // they will end up in the same bucket. - static node_pointer last_for_rehash(link_pointer prev) - { - node_pointer n = next_node(prev); - std::size_t hash = n->hash_; - for (;;) { - node_pointer next = next_node(n); - if (!next || next->hash_ != hash) { - return n; - } - n = next; - } - } - - template - static node_pointer next_group(node_pointer n, Table const* t) - { - node_pointer n1 = n; - do { - n1 = next_node(n1); - } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); - return n1; - } - - template - static std::size_t count(node_pointer n, Table const* t) - { - std::size_t x = 0; - node_pointer it = n; - do { - ++x; - it = next_node(it); - } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); - - return x; - } - - // Add node 'n' after 'pos'. - // This results in a different order to the grouped implementation. - static inline void add_to_node(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; - } - - static link_pointer split_groups(node_pointer, node_pointer) - { - return link_pointer(); - } -}; - // If the allocator uses raw pointers use ptr_node // Otherwise use node. @@ -4563,211 +4572,6 @@ 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; -}; - -//////////////////////////////////////////////////////////////////////// -// Grouped nodes - -template -struct grouped_node : boost::unordered::detail::value_base -{ - typedef typename ::boost::unordered::detail::rebind_wrap >::type allocator; - 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_; - std::size_t hash_; - - grouped_node() : next_(), group_prev_(), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - private: - grouped_node& operator=(grouped_node const&); -}; - -template -struct grouped_ptr_node : boost::unordered::detail::ptr_bucket -{ - typedef T value_type; - 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_; - boost::unordered::detail::value_base value_base_; - - grouped_ptr_node() : bucket_base(), group_prev_(0), hash_(0) {} - - void init(node_pointer self) { group_prev_ = self; } - - void* address() { return value_base_.address(); } - value_type& value() { return value_base_.value(); } - value_type* value_ptr() { return value_base_.value_ptr(); } - - private: - 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_; - } - - static node_pointer last_for_rehash(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(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; - } -}; - -// If the allocator uses raw pointers use grouped_ptr_node -// Otherwise use grouped_node. - -template -struct pick_grouped_node2 -{ - typedef boost::unordered::detail::grouped_node node; - - typedef typename boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type>::pointer - node_pointer; - - typedef boost::unordered::detail::bucket bucket; - typedef node_pointer link_pointer; -}; - -template -struct pick_grouped_node2*, - boost::unordered::detail::ptr_bucket*> -{ - typedef boost::unordered::detail::grouped_ptr_node node; - typedef boost::unordered::detail::ptr_bucket bucket; - typedef bucket* link_pointer; -}; - -template struct pick_grouped_node -{ - typedef typename boost::remove_const::type nonconst; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap >::type> - tentative_node_traits; - - typedef boost::unordered::detail::allocator_traits< - typename boost::unordered::detail::rebind_wrap::type> - tentative_bucket_traits; - - typedef pick_grouped_node2 - pick; - - 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; }; } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 9b059d18..4568e75f 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -23,22 +23,13 @@ template struct map typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; -#else - typedef boost::unordered::detail::pick_grouped_node pick; -#endif 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 table; typedef boost::unordered::detail::map_extractor extractor; - enum - { - is_unique = true - }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -54,50 +45,6 @@ template struct map insert_return_type; }; -template -struct multimap -{ - typedef boost::unordered::detail::multimap types; - - typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef K const const_key_type; - - typedef typename ::boost::unordered::detail::rebind_wrap::type value_allocator; - typedef boost::unordered::detail::allocator_traits - value_allocator_traits; - -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 - typedef boost::unordered::detail::pick_grouped_node pick; -#else - typedef boost::unordered::detail::pick_node pick; -#endif - 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 table; - typedef boost::unordered::detail::map_extractor extractor; - enum - { - is_unique = false - }; - - typedef typename boost::unordered::detail::pick_policy::type policy; - - typedef boost::unordered::iterator_detail::iterator iterator; - typedef boost::unordered::iterator_detail::c_iterator c_iterator; - typedef boost::unordered::iterator_detail::l_iterator - l_iterator; - typedef boost::unordered::iterator_detail::cl_iterator - cl_iterator; - - typedef boost::unordered::node_handle_map node_type; -}; - template class instantiate_map { diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 6de4423c..fc13fa17 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -23,22 +23,13 @@ template struct set typedef boost::unordered::detail::allocator_traits value_allocator_traits; -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 2 typedef boost::unordered::detail::pick_node pick; -#else - typedef boost::unordered::detail::pick_grouped_node pick; -#endif 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 table; typedef boost::unordered::detail::set_extractor extractor; - enum - { - is_unique = true - }; typedef typename boost::unordered::detail::pick_policy::type policy; @@ -54,49 +45,6 @@ template struct set insert_return_type; }; -template struct multiset -{ - typedef boost::unordered::detail::multiset types; - - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T const const_key_type; - - typedef typename ::boost::unordered::detail::rebind_wrap::type value_allocator; - typedef boost::unordered::detail::allocator_traits - value_allocator_traits; - -#if BOOST_UNORDERED_INTEROPERABLE_NODES != 1 - typedef boost::unordered::detail::pick_grouped_node pick; -#else - typedef boost::unordered::detail::pick_node pick; -#endif - 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 table; - typedef boost::unordered::detail::set_extractor extractor; - enum - { - is_unique = false - }; - - typedef typename boost::unordered::detail::pick_policy::type policy; - - typedef boost::unordered::iterator_detail::c_iterator iterator; - typedef boost::unordered::iterator_detail::c_iterator c_iterator; - typedef boost::unordered::iterator_detail::cl_iterator - l_iterator; - typedef boost::unordered::iterator_detail::cl_iterator - cl_iterator; - - typedef boost::unordered::node_handle_set node_type; -}; - template class instantiate_set { typedef boost::unordered_set container; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5c941f75..6291c3dc 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -146,7 +146,7 @@ template class unordered_map #if defined(BOOST_UNORDERED_USE_MOVE) unordered_map& operator=(BOOST_COPY_ASSIGN_REF(unordered_map) x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -156,13 +156,13 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #else unordered_map& operator=(unordered_map const& x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -173,7 +173,7 @@ template class unordered_map // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #endif @@ -740,14 +740,12 @@ template class unordered_map void merge(boost::unordered_map&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_multimap& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_multimap&& source); -#endif #endif // observers @@ -858,7 +856,7 @@ template class unordered_multimap typedef A allocator_type; private: - typedef boost::unordered::detail::multimap types; + typedef boost::unordered::detail::map types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; typedef typename table::node_pointer node_pointer; @@ -952,7 +950,7 @@ template class unordered_multimap #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multimap& operator=(BOOST_COPY_ASSIGN_REF(unordered_multimap) x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -962,13 +960,13 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #else unordered_multimap& operator=(unordered_multimap const& x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -979,7 +977,7 @@ template class unordered_multimap // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #endif @@ -1277,14 +1275,12 @@ template class unordered_multimap void merge(boost::unordered_multimap&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_map& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_map&& source); -#endif #endif // observers @@ -1573,7 +1569,7 @@ unordered_map::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1584,7 +1580,7 @@ unordered_map::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1644,7 +1640,6 @@ void unordered_map::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_map::merge( @@ -1662,7 +1657,6 @@ void unordered_map::merge( table_.merge_unique(source.table_); } #endif -#endif // observers @@ -1729,8 +1723,7 @@ std::pair::iterator, unordered_map::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair( - iterator(n), iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair(iterator(n), iterator(n ? table::next_node(n) : n)); } template @@ -1739,8 +1732,8 @@ std::pair::const_iterator, unordered_map::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -2060,7 +2053,7 @@ unordered_multimap::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2071,7 +2064,7 @@ unordered_multimap::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2152,7 +2145,6 @@ void unordered_multimap::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_multimap::merge( @@ -2174,7 +2166,6 @@ void unordered_multimap::merge( } } #endif -#endif // lookup @@ -2217,7 +2208,7 @@ typename unordered_multimap::size_type unordered_multimap::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -2226,8 +2217,7 @@ std::pair::iterator, unordered_multimap::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair(iterator(n), - iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair(iterator(n), iterator(n ? table_.next_group(n) : n)); } template @@ -2236,8 +2226,8 @@ std::pair::const_iterator, unordered_multimap::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 36645b99..bbd07f60 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -144,7 +144,7 @@ template class unordered_set #if defined(BOOST_UNORDERED_USE_MOVE) unordered_set& operator=(BOOST_COPY_ASSIGN_REF(unordered_set) x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -154,13 +154,13 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #else unordered_set& operator=(unordered_set const& x) { - table_.assign(x.table_); + table_.assign(x.table_, true); return *this; } @@ -171,7 +171,7 @@ template class unordered_set // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, true); return *this; } #endif @@ -457,14 +457,12 @@ template class unordered_set void merge(boost::unordered_set&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_multiset& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_multiset&& source); -#endif #endif // observers @@ -562,7 +560,7 @@ template class unordered_multiset typedef A allocator_type; private: - typedef boost::unordered::detail::multiset types; + typedef boost::unordered::detail::set types; typedef typename types::value_allocator_traits value_allocator_traits; typedef typename types::table table; typedef typename table::node_pointer node_pointer; @@ -656,7 +654,7 @@ template class unordered_multiset #if defined(BOOST_UNORDERED_USE_MOVE) unordered_multiset& operator=(BOOST_COPY_ASSIGN_REF(unordered_multiset) x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -666,13 +664,13 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #else unordered_multiset& operator=(unordered_multiset const& x) { - table_.assign(x.table_); + table_.assign(x.table_, false); return *this; } @@ -683,7 +681,7 @@ template class unordered_multiset // is_nothrow_move_assignable_v && // is_nothrow_move_assignable_v

) { - table_.move_assign(x.table_); + table_.move_assign(x.table_, false); return *this; } #endif @@ -962,14 +960,12 @@ template class unordered_multiset void merge(boost::unordered_multiset&& source); #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template void merge(boost::unordered_set& source); #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template void merge(boost::unordered_set&& source); -#endif #endif // observers @@ -1246,7 +1242,7 @@ typename unordered_set::iterator unordered_set::erase( { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1322,7 +1318,6 @@ void unordered_set::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_set::merge( @@ -1340,7 +1335,6 @@ void unordered_set::merge( table_.merge_unique(source.table_); } #endif -#endif // lookup @@ -1374,8 +1368,8 @@ std::pair::const_iterator, unordered_set::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -1652,7 +1646,7 @@ unordered_multiset::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -1732,7 +1726,6 @@ void unordered_multiset::merge( } #endif -#if BOOST_UNORDERED_INTEROPERABLE_NODES template template void unordered_multiset::merge( @@ -1754,7 +1747,6 @@ void unordered_multiset::merge( } } #endif -#endif // lookup @@ -1780,7 +1772,7 @@ typename unordered_multiset::size_type unordered_multiset::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -1789,8 +1781,8 @@ std::pair::const_iterator, unordered_multiset::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template diff --git a/test/helpers/invariants.hpp b/test/helpers/invariants.hpp index ffc5de4e..06091b94 100644 --- a/test/helpers/invariants.hpp +++ b/test/helpers/invariants.hpp @@ -63,20 +63,28 @@ template void check_equivalent_keys(X const& x1) BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key); BOOST_DEDUCED_TYPENAME X::const_local_iterator lit = x1.begin(bucket), lend = x1.end(bucket); - for (; lit != lend && !eq(get_key(*lit), key); ++lit) - continue; - if (lit == lend) + + unsigned int count_checked = 0; + for (; lit != lend && !eq(get_key(*lit), key); ++lit) { + ++count_checked; + } + + if (lit == lend) { BOOST_ERROR("Unable to find element with a local_iterator"); - unsigned int count2 = 0; - for (; lit != lend && eq(get_key(*lit), key); ++lit) - ++count2; - if (count != count2) - BOOST_ERROR("Element count doesn't match local_iterator."); - for (; lit != lend; ++lit) { - if (eq(get_key(*lit), key)) { - BOOST_ERROR("Non-adjacent element with equivalent key " - "in bucket."); - break; + std::cerr << "Checked: " << count_checked << " elements" + << std::endl; + } else { + unsigned int count2 = 0; + for (; lit != lend && eq(get_key(*lit), key); ++lit) + ++count2; + if (count != count2) + BOOST_ERROR("Element count doesn't match local_iterator."); + for (; lit != lend; ++lit) { + if (eq(get_key(*lit), key)) { + BOOST_ERROR("Non-adjacent element with equivalent key " + "in bucket."); + break; + } } } }; diff --git a/test/helpers/test.hpp b/test/helpers/test.hpp index 84e900f2..4f21f0b9 100644 --- a/test/helpers/test.hpp +++ b/test/helpers/test.hpp @@ -93,8 +93,6 @@ static inline void run_tests() << BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \ << "BOOST_UNORDERED_EMPLACE_LIMIT: " \ << BOOST_UNORDERED_EMPLACE_LIMIT << "\n" \ - << "BOOST_UNORDERED_INTEROPERABLE_NODES: " \ - << BOOST_UNORDERED_INTEROPERABLE_NODES << "\n" \ << "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \ << BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \ << "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \ diff --git a/test/unordered/insert_stable_tests.cpp b/test/unordered/insert_stable_tests.cpp index c85dd188..afba2239 100644 --- a/test/unordered/insert_stable_tests.cpp +++ b/test/unordered/insert_stable_tests.cpp @@ -47,9 +47,9 @@ std::size_t hash_value(insert_stable::member const& x) } } -// This is now only supported when using grouped nodes. I can't see any -// efficient way to do it otherwise. -#if !BOOST_UNORDERED_INTEROPERABLE_NODES +// This is no longer supported, as there's no longer an efficient way to get to +// the end of a group of equivalent nodes. +#if 0 UNORDERED_AUTO_TEST(stable_insert_test1) { diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 15755ab8..3d5e7f97 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -99,7 +99,6 @@ UNORDERED_AUTO_TEST(merge_multiset) test::check_equivalent_keys(y); } -#if BOOST_UNORDERED_INTEROPERABLE_NODES UNORDERED_AUTO_TEST(merge_set_and_multiset) { boost::unordered_set x; @@ -139,7 +138,6 @@ UNORDERED_AUTO_TEST(merge_set_and_multiset) test::check_equivalent_keys(x); test::check_equivalent_keys(y); } -#endif template void merge_empty_test(X*, test::random_generator generator) {