diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 937b0a0e..25a7e615 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -185,9 +185,6 @@ template struct table; template struct bucket; struct ptr_bucket; -template struct table_unique; -template struct table_equiv; - template struct unique_node; template struct ptr_node; template struct node_algo; @@ -198,13 +195,21 @@ template struct grouped_node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; + struct move_tag { }; + struct empty_emplace { }; +struct no_key +{ + no_key() {} + template no_key(T const&) {} +}; + namespace func { template inline void ignore_unused_variable_warning(T const&) {} } @@ -2041,8 +2046,6 @@ struct iterator : public std::iterator friend struct boost::unordered::iterator_detail::c_iterator; template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_unique; - template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -2097,8 +2100,6 @@ struct c_iterator #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template friend struct boost::unordered::detail::table; - template friend struct boost::unordered::detail::table_unique; - template friend struct boost::unordered::detail::table_equiv; private: #endif @@ -2694,6 +2695,8 @@ struct table : boost::unordered::detail::functions node_tmp; + typedef std::pair emplace_return; + //////////////////////////////////////////////////////////////////////// // Members @@ -3116,7 +3119,12 @@ struct table : boost::unordered::detail::functions(this)->assign_buckets(x); + + if (Types::is_unique) { + assign_buckets_unique(x); + } else { + assign_buckets_equiv(x); + } } void assign(table const& x, true_type) @@ -3140,7 +3148,11 @@ struct table : boost::unordered::detail::functions(this)->copy_buckets(x); + if (Types::is_unique) { + copy_buckets_unique(x); + } else { + copy_buckets_equiv(x); + } } } } @@ -3194,7 +3206,12 @@ struct table : boost::unordered::detail::functions(this)->move_assign_buckets(x); + + if (Types::is_unique) { + move_assign_buckets_unique(x); + } else { + move_assign_buckets_equiv(x); + } } } @@ -3298,6 +3315,874 @@ struct table : boost::unordered::detail::functionssize_ != other.size_) + return false; + + for (node_pointer n1 = this->begin(); n1; + n1 = node_algo::next_node(n1)) { + node_pointer n2 = other.find_node(other.get_key(n1)); + + if (!n2 || n1->value() != n2->value()) + return false; + } + + return true; + } + + // Emplace/Insert + + inline node_pointer add_node_unique(node_pointer n, std::size_t key_hash) + { + n->hash_ = key_hash; + + bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + + 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; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } else { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + + ++this->size_; + return n; + } + + inline node_pointer resize_and_add_node_unique( + node_pointer n, std::size_t key_hash) + { + node_tmp b(n, this->node_alloc()); + this->reserve_for_insert(this->size_ + 1); + return this->add_node_unique(b.release(), key_hash); + } + + template + iterator emplace_hint_unique( + c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) + { + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { + return iterator(hint.node_); + } else { + return emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + } + } + + template + emplace_return emplace_unique( + const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node_unique( + boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + key_hash)), + true); + } + } + + template + iterator emplace_hint_unique( + c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_tmp b(boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + const_key_type& k = this->get_key(b.node_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { + return iterator(hint.node_); + } + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return iterator(pos); + } else { + return iterator( + this->resize_and_add_node_unique(b.release(), key_hash)); + } + } + + template + emplace_return emplace_unique(no_key, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_tmp b(boost::unordered::detail::func::construct_node_from_args( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + const_key_type& k = this->get_key(b.node_); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return(iterator(this->resize_and_add_node_unique( + b.release(), key_hash)), + true); + } + } + + template + emplace_return try_emplace_unique(BOOST_FWD_REF(Key) k) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node_unique( + boost::unordered::detail::func::construct_node_pair( + this->node_alloc(), boost::forward(k)), + key_hash)), + true); + } + } + + template + iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k) + { + if (hint.node_ && this->key_eq()(hint->first, k)) { + return iterator(hint.node_); + } else { + return try_emplace_unique(k).first; + } + } + + template + emplace_return try_emplace_unique( + BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (pos) { + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node_unique( + boost::unordered::detail::func:: + construct_node_pair_from_args(this->node_alloc(), + boost::forward(k), + BOOST_UNORDERED_EMPLACE_FORWARD), + key_hash)), + true); + } + } + + template + iterator try_emplace_hint_unique( + c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) + { + if (hint.node_ && this->key_eq()(hint->first, k)) { + return iterator(hint.node_); + } else { + return try_emplace_unique(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; + } + } + + template + emplace_return insert_or_assign_unique( + BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + pos->value().second = boost::forward(obj); + return emplace_return(iterator(pos), false); + } else { + return emplace_return( + iterator(this->resize_and_add_node_unique( + boost::unordered::detail::func::construct_node_pair( + this->node_alloc(), boost::forward(k), + boost::forward(obj)), + key_hash)), + true); + } + } + + template + void move_insert_node_type_unique(NodeType& np, InsertReturnType& result) + { + if (np) { + const_key_type& k = this->get_key(np.ptr_); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + result.node = boost::move(np); + result.position = iterator(pos); + } else { + this->reserve_for_insert(this->size_ + 1); + result.position = + iterator(this->add_node_unique(np.ptr_, key_hash)); + result.inserted = true; + np.ptr_ = node_pointer(); + } + } + } + + template + iterator move_insert_node_type_with_hint_unique( + c_iterator hint, NodeType& np) + { + if (!np) { + return iterator(); + } + const_key_type& k = this->get_key(np.ptr_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { + return iterator(hint.node_); + } + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + if (!pos) { + this->reserve_for_insert(this->size_ + 1); + pos = this->add_node_unique(np.ptr_, key_hash); + np.ptr_ = node_pointer(); + } + return iterator(pos); + } + + template + void merge_unique(boost::unordered::detail::table& other) + { + typedef boost::unordered::detail::table other_table; + BOOST_STATIC_ASSERT( + (boost::is_same::value)); + BOOST_ASSERT(this->node_alloc() == other.node_alloc()); + + if (other.size_) { + link_pointer prev = other.get_previous_start(); + + 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); + + if (pos) { + 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); + } + } + } + } + + //////////////////////////////////////////////////////////////////////// + // Insert range methods + // + // if hash function throws, or inserting > 1 element, basic exception + // safety strong otherwise + + template + void insert_range_unique(const_key_type& k, InputIt i, InputIt j) + { + insert_range_unique2(k, i, j); + + while (++i != j) { + // Note: can't use get_key as '*i' might not be value_type - it + // could be a pair with first_types as key_type without const or + // a different second_type. + insert_range_unique2(extractor::extract(*i), i, j); + } + } + + template + void insert_range_unique2(const_key_type& k, InputIt i, InputIt j) + { + // No side effects in this initial code + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (!pos) { + node_tmp b(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i), + this->node_alloc()); + if (this->size_ + 1 > this->max_load_) + this->reserve_for_insert( + this->size_ + boost::unordered::detail::insert_size(i, j)); + this->add_node_unique(b.release(), key_hash); + } + } + + template + void insert_range_unique(no_key, InputIt i, InputIt j) + { + node_constructor a(this->node_alloc()); + + do { + if (!a.node_) { + a.create_node(); + } + BOOST_UNORDERED_CALL_CONSTRUCT1( + node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i); + node_tmp b(a.release(), a.alloc_); + + const_key_type& k = this->get_key(b.node_); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + + if (pos) { + a.reclaim(b.release()); + } else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + this->reserve_for_insert(this->size_ + 1); + this->add_node_unique(b.release(), key_hash); + } + } while (++i != j); + } + + //////////////////////////////////////////////////////////////////////// + // Extract + + inline node_pointer extract_by_iterator_unique(c_iterator i) + { + node_pointer n = i.node_; + BOOST_ASSERT(n); + std::size_t key_hash = n->hash_; + std::size_t bucket_index = this->hash_to_bucket(key_hash); + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != n) { + prev = prev->next_; + } + prev->next_ = n->next_; + --this->size_; + this->fix_bucket(bucket_index, prev); + n->next_ = link_pointer(); + return n; + } + + //////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw + + std::size_t erase_key_unique(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 = this->find_previous_node(k, key_hash, bucket_index); + if (!prev) + return 0; + link_pointer end = node_algo::next_node(prev)->next_; + this->delete_nodes(prev, end); + this->fix_bucket(bucket_index, prev); + return 1; + } + + void erase_nodes_unique(node_pointer i, node_pointer j) + { + std::size_t bucket_index = this->hash_to_bucket(i->hash_); + + // Find the node before i. + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) + prev = prev->next_; + + // Delete the nodes. + do { + this->delete_node(prev); + bucket_index = this->fix_bucket(bucket_index, prev); + } while (prev->next_ != j); + } + + //////////////////////////////////////////////////////////////////////// + // fill_buckets_unique + + void copy_buckets_unique(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node_unique( + boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + n->hash_); + } + } + + // TODO: Should be move_buckets_uniq + void move_buckets(table const& src) + { + this->create_buckets(this->bucket_count_); + + for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + this->add_node_unique( + boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + n->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_); + } + } + + 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_); + } + } + + //////////////////////////////////////////////////////////////////////// + // Equivalent keys + + // Equality + + bool equals_equiv(table const& other) const + { + if (this->size_ != other.size_) + return false; + + for (node_pointer n1 = this->begin(); n1;) { + node_pointer n2 = other.find_node(other.get_key(n1)); + if (!n2) + return false; + node_pointer end1 = node_algo::next_group(n1, this); + node_pointer end2 = node_algo::next_group(n2, this); + if (!group_equals_equiv(n1, end1, n2, end2)) + return false; + n1 = end1; + } + + return true; + } + + static bool group_equals_equiv( + node_pointer n1, node_pointer end1, node_pointer n2, node_pointer end2) + { + for (;;) { + if (n1->value() != n2->value()) + break; + + n1 = node_algo::next_node(n1); + n2 = node_algo::next_node(n2); + + if (n1 == end1) + return n2 == end2; + if (n2 == end2) + return false; + } + + for (node_pointer n1a = n1, n2a = n2;;) { + n1a = node_algo::next_node(n1a); + n2a = node_algo::next_node(n2a); + + if (n1a == end1) { + if (n2a == end2) + break; + else + return false; + } + + if (n2a == end2) + return false; + } + + node_pointer start = n1; + for (; n1 != end1; n1 = node_algo::next_node(n1)) { + value_type const& v = n1->value(); + 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)) + return false; + } + } + + return true; + } + + static bool find_equiv( + node_pointer n, node_pointer end, value_type const& v) + { + for (; n != end; n = node_algo::next_node(n)) + if (n->value() == v) + return true; + return false; + } + + static std::size_t count_equal_equiv( + node_pointer n, node_pointer end, value_type const& v) + { + std::size_t count = 0; + for (; n != end; n = node_algo::next_node(n)) + if (n->value() == v) + ++count; + return count; + } + + // Emplace/Insert + + inline node_pointer add_node_equiv( + node_pointer n, std::size_t key_hash, node_pointer pos) + { + n->hash_ = key_hash; + if (pos) { + node_algo::add_to_node(n, pos); + 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)) { + this->get_bucket(next_bucket)->next_ = n; + } + } + } else { + bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); + + 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; + } + + b->next_ = start_node; + n->next_ = start_node->next_; + start_node->next_ = n; + } else { + n->next_ = b->next_->next_; + b->next_->next_ = n; + } + } + ++this->size_; + return n; + } + + inline node_pointer add_using_hint_equiv(node_pointer n, node_pointer hint) + { + n->hash_ = hint->hash_; + node_algo::add_to_node(n, hint); + 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_)) { + this->get_bucket(next_bucket)->next_ = n; + } + } + ++this->size_; + return n; + } + + iterator emplace_equiv(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_); + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return iterator(this->add_node_equiv(a.release(), key_hash, position)); + } + + iterator emplace_hint_equiv(c_iterator hint, node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_); + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { + this->reserve_for_insert(this->size_ + 1); + return iterator( + this->add_using_hint_equiv(a.release(), hint.node_)); + } else { + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + return iterator( + this->add_node_equiv(a.release(), key_hash, position)); + } + } + + void emplace_no_rehash_equiv(node_pointer n) + { + node_tmp a(n, this->node_alloc()); + const_key_type& k = this->get_key(a.node_); + std::size_t key_hash = this->hash(k); + node_pointer position = this->find_node(key_hash, k); + this->add_node_equiv(a.release(), key_hash, position); + } + + template + iterator move_insert_node_type_equiv(NodeType& np) + { + iterator result; + + if (np) { + const_key_type& k = this->get_key(np.ptr_); + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos)); + np.ptr_ = node_pointer(); + } + + return result; + } + + template + iterator move_insert_node_type_with_hint_equiv( + c_iterator hint, NodeType& np) + { + iterator result; + + if (np) { + const_key_type& k = this->get_key(np.ptr_); + + if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { + this->reserve_for_insert(this->size_ + 1); + result = + iterator(this->add_using_hint_equiv(np.ptr_, hint.node_)); + } else { + std::size_t key_hash = this->hash(k); + node_pointer pos = this->find_node(key_hash, k); + this->reserve_for_insert(this->size_ + 1); + result = iterator(this->add_node_equiv(np.ptr_, key_hash, pos)); + } + np.ptr_ = node_pointer(); + } + + return result; + } + + //////////////////////////////////////////////////////////////////////// + // Insert range methods + + // if hash function throws, or inserting > 1 element, basic exception + // safety. Strong otherwise + template + void insert_range_equiv(I i, I j, + typename boost::unordered::detail::enable_if_forward::type = + 0) + { + if (i == j) + return; + + std::size_t distance = static_cast(std::distance(i, j)); + if (distance == 1) { + emplace_equiv(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } else { + // Only require basic exception safety here + this->reserve_for_insert(this->size_ + distance); + + for (; i != j; ++i) { + emplace_no_rehash_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } + } + } + + template + void insert_range_equiv(I i, I j, + typename boost::unordered::detail::disable_if_forward::type = + 0) + { + for (; i != j; ++i) { + emplace_equiv(boost::unordered::detail::func::construct_node( + this->node_alloc(), *i)); + } + } + + //////////////////////////////////////////////////////////////////////// + // Extract + + inline node_pointer extract_by_iterator_equiv(c_iterator n) + { + node_pointer i = n.node_; + BOOST_ASSERT(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 = 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); + } + } + + prev->next_ = i->next_; + --this->size_; + this->fix_bucket(bucket_index, prev); + i->next_ = link_pointer(); + + return i; + } + + //////////////////////////////////////////////////////////////////////// + // Erase + // + // no throw + + std::size_t erase_key_equiv(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 = this->find_previous_node(k, key_hash, 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); + + std::size_t deleted_count = this->delete_nodes(prev, end); + this->fix_bucket(bucket_index, prev); + return deleted_count; + } + + link_pointer erase_nodes_equiv(node_pointer i, node_pointer j) + { + 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 = 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); + } + } + + // Delete the nodes. + // Is it inefficient to call fix_bucket for every node? + do { + this->delete_node(prev); + bucket_index = this->fix_bucket(bucket_index, prev); + } while (prev->next_ != j); + + return prev; + } + + //////////////////////////////////////////////////////////////////////// + // fill_buckets + + void copy_buckets_equiv(table const& src) + { + this->create_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)); + 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)) { + this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), n->value()), + key_hash, pos); + } + } + } + + void move_buckets_equiv(table const& src) + { + this->create_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)); + 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)) { + this->add_node_equiv( + boost::unordered::detail::func::construct_node( + this->node_alloc(), boost::move(n->value())), + key_hash, pos); + } + } + } + + void assign_buckets_equiv(table const& src) + { + node_holder 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)); + 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)) { + this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos); + } + } + } + + void move_assign_buckets_equiv(table& src) + { + node_holder 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)); + 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)) { + this->add_node_equiv( + holder.move_copy_of(n->value()), key_hash, pos); + } + } + } }; //////////////////////////////////////////////////////////////////////////// @@ -3378,12 +4263,6 @@ inline void table::rehash_impl(std::size_t num_buckets) // for the different cases, but that's a bit tricky on compilers without // variadic templates. -struct no_key -{ - no_key() {} - template no_key(T const&) {} -}; - template struct is_key { template static choice1::type test(T2 const&); @@ -3624,7 +4503,7 @@ template struct node_algo // 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) + static inline void add_to_node(node_pointer n, node_pointer pos) { n->next_ = pos->next_; pos->next_ = n; @@ -3692,508 +4571,6 @@ template struct pick_node typedef boost::unordered::detail::node_algo node_algo; }; -template -struct table_unique : boost::unordered::detail::table -{ - typedef boost::unordered::detail::table table; - typedef typename table::value_type value_type; - typedef typename table::node node; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::const_key_type const_key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - 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; - - // Constructors - - table_unique(std::size_t n, hasher const& hf, key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - { - } - - table_unique(table_unique const& x) - : table(x, node_allocator_traits::select_on_container_copy_construction( - x.node_alloc())) - { - if (x.size_) { - this->copy_buckets(x); - } - } - - table_unique(table_unique const& x, node_allocator const& a) : table(x, a) - { - if (x.size_) { - this->copy_buckets(x); - } - } - - table_unique(table_unique& x, boost::unordered::detail::move_tag m) - : table(x, m) - { - // The move is done in the base class. - } - - table_unique(table_unique& x, node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - if (this->node_alloc() == x.node_alloc()) { - this->move_buckets_from(x); - } else if (x.size_) { - // TODO: Could pick new bucket size? - this->move_buckets(x); - } - } - - // equals - - bool equals(table_unique const& other) const - { - if (this->size_ != other.size_) - return false; - - for (node_pointer n1 = this->begin(); n1; - n1 = node_algo::next_node(n1)) { - node_pointer n2 = other.find_node(other.get_key(n1)); - - if (!n2 || n1->value() != n2->value()) - return false; - } - - return true; - } - - // Emplace/Insert - - inline node_pointer add_node(node_pointer n, std::size_t key_hash) - { - n->hash_ = key_hash; - - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); - - 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; - } - - b->next_ = start_node; - n->next_ = start_node->next_; - start_node->next_ = n; - } else { - n->next_ = b->next_->next_; - b->next_->next_ = n; - } - - ++this->size_; - return n; - } - - inline node_pointer resize_and_add_node( - node_pointer n, std::size_t key_hash) - { - node_tmp b(n, this->node_alloc()); - this->reserve_for_insert(this->size_ + 1); - return this->add_node(b.release(), key_hash); - } - - template - iterator emplace_hint_impl( - c_iterator hint, const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) - { - if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { - return iterator(hint.node_); - } else { - return emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; - } - } - - template - emplace_return emplace_impl(const_key_type& k, BOOST_UNORDERED_EMPLACE_ARGS) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } else { - return emplace_return( - iterator(this->resize_and_add_node( - boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - key_hash)), - true); - } - } - - template - iterator emplace_hint_impl( - c_iterator hint, no_key, BOOST_UNORDERED_EMPLACE_ARGS) - { - node_tmp b(boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - const_key_type& k = this->get_key(b.node_); - if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { - return iterator(hint.node_); - } - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return iterator(pos); - } else { - return iterator(this->resize_and_add_node(b.release(), key_hash)); - } - } - - template - emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) - { - node_tmp b(boost::unordered::detail::func::construct_node_from_args( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - const_key_type& k = this->get_key(b.node_); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } else { - return emplace_return( - iterator(this->resize_and_add_node(b.release(), key_hash)), - true); - } - } - - template - emplace_return try_emplace_impl(BOOST_FWD_REF(Key) k) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } else { - return emplace_return( - iterator(this->resize_and_add_node( - boost::unordered::detail::func::construct_node_pair( - this->node_alloc(), boost::forward(k)), - key_hash)), - true); - } - } - - template - iterator try_emplace_hint_impl(c_iterator hint, BOOST_FWD_REF(Key) k) - { - if (hint.node_ && this->key_eq()(hint->first, k)) { - return iterator(hint.node_); - } else { - return try_emplace_impl(k).first; - } - } - - template - emplace_return try_emplace_impl( - BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (pos) { - return emplace_return(iterator(pos), false); - } else { - return emplace_return( - iterator(this->resize_and_add_node( - boost::unordered::detail::func:: - construct_node_pair_from_args(this->node_alloc(), - boost::forward(k), - BOOST_UNORDERED_EMPLACE_FORWARD), - key_hash)), - true); - } - } - - template - iterator try_emplace_hint_impl( - c_iterator hint, BOOST_FWD_REF(Key) k, BOOST_UNORDERED_EMPLACE_ARGS) - { - if (hint.node_ && this->key_eq()(hint->first, k)) { - return iterator(hint.node_); - } else { - return try_emplace_impl(k, BOOST_UNORDERED_EMPLACE_FORWARD).first; - } - } - - template - emplace_return insert_or_assign_impl( - BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) - { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (pos) { - pos->value().second = boost::forward(obj); - return emplace_return(iterator(pos), false); - } else { - return emplace_return( - iterator(this->resize_and_add_node( - boost::unordered::detail::func::construct_node_pair( - this->node_alloc(), boost::forward(k), - boost::forward(obj)), - key_hash)), - true); - } - } - - template - void move_insert_node_type(NodeType& np, InsertReturnType& result) - { - if (np) { - const_key_type& k = this->get_key(np.ptr_); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (pos) { - result.node = boost::move(np); - result.position = iterator(pos); - } else { - this->reserve_for_insert(this->size_ + 1); - result.position = iterator(this->add_node(np.ptr_, key_hash)); - result.inserted = true; - np.ptr_ = node_pointer(); - } - } - } - - template - iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) - { - if (!np) { - return iterator(); - } - const_key_type& k = this->get_key(np.ptr_); - if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { - return iterator(hint.node_); - } - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - if (!pos) { - this->reserve_for_insert(this->size_ + 1); - pos = this->add_node(np.ptr_, key_hash); - np.ptr_ = node_pointer(); - } - return iterator(pos); - } - - template - void merge_impl(boost::unordered::detail::table& other) - { - typedef boost::unordered::detail::table other_table; - BOOST_STATIC_ASSERT( - (boost::is_same::value)); - BOOST_ASSERT(this->node_alloc() == other.node_alloc()); - - if (other.size_) { - link_pointer prev = other.get_previous_start(); - - 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); - - if (pos) { - 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(n, key_hash); - } - } - } - } - - //////////////////////////////////////////////////////////////////////// - // Insert range methods - // - // if hash function throws, or inserting > 1 element, basic exception - // safety strong otherwise - - template - void insert_range_impl(const_key_type& k, InputIt i, InputIt j) - { - insert_range_impl2(k, i, j); - - while (++i != j) { - // Note: can't use get_key as '*i' might not be value_type - it - // could be a pair with first_types as key_type without const or - // a different second_type. - insert_range_impl2(extractor::extract(*i), i, j); - } - } - - template - void insert_range_impl2(const_key_type& k, InputIt i, InputIt j) - { - // No side effects in this initial code - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (!pos) { - node_tmp b(boost::unordered::detail::func::construct_node( - this->node_alloc(), *i), - this->node_alloc()); - if (this->size_ + 1 > this->max_load_) - this->reserve_for_insert( - this->size_ + boost::unordered::detail::insert_size(i, j)); - this->add_node(b.release(), key_hash); - } - } - - template - void insert_range_impl(no_key, InputIt i, InputIt j) - { - node_constructor a(this->node_alloc()); - - do { - if (!a.node_) { - a.create_node(); - } - BOOST_UNORDERED_CALL_CONSTRUCT1( - node_allocator_traits, a.alloc_, a.node_->value_ptr(), *i); - node_tmp b(a.release(), a.alloc_); - - const_key_type& k = this->get_key(b.node_); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - - if (pos) { - a.reclaim(b.release()); - } else { - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - this->reserve_for_insert(this->size_ + 1); - this->add_node(b.release(), key_hash); - } - } while (++i != j); - } - - //////////////////////////////////////////////////////////////////////// - // Extract - - inline node_pointer extract_by_iterator(c_iterator i) - { - node_pointer n = i.node_; - BOOST_ASSERT(n); - std::size_t key_hash = n->hash_; - std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->get_previous_start(bucket_index); - while (prev->next_ != n) { - prev = prev->next_; - } - prev->next_ = n->next_; - --this->size_; - this->fix_bucket(bucket_index, prev); - n->next_ = link_pointer(); - return n; - } - - //////////////////////////////////////////////////////////////////////// - // Erase - // - // no throw - - 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 = this->find_previous_node(k, key_hash, bucket_index); - if (!prev) - return 0; - link_pointer end = node_algo::next_node(prev)->next_; - this->delete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); - return 1; - } - - void erase_nodes(node_pointer i, node_pointer j) - { - std::size_t bucket_index = this->hash_to_bucket(i->hash_); - - // Find the node before i. - link_pointer prev = this->get_previous_start(bucket_index); - while (prev->next_ != i) - prev = prev->next_; - - // Delete the nodes. - do { - this->delete_node(prev); - bucket_index = this->fix_bucket(bucket_index, prev); - } while (prev->next_ != j); - } - - //////////////////////////////////////////////////////////////////////// - // fill_buckets - - void copy_buckets(table const& src) - { - this->create_buckets(this->bucket_count_); - - 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_); - } - } - - void move_buckets(table const& src) - { - this->create_buckets(this->bucket_count_); - - 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_); - } - } - - void assign_buckets(table const& src) - { - node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(holder.copy_of(n->value()), n->hash_); - } - } - - void move_assign_buckets(table& src) - { - node_holder holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { - this->add_node(holder.move_copy_of(n->value()), n->hash_); - } - } -}; - //////////////////////////////////////////////////////////////////////// // Grouped nodes @@ -4297,7 +4674,7 @@ template struct grouped_node_algo // 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) + static inline void add_to_node(node_pointer n, node_pointer pos) { n->next_ = pos->group_prev_->next_; n->group_prev_ = pos->group_prev_; @@ -4397,483 +4774,6 @@ template struct pick_grouped_node typedef typename pick::link_pointer link_pointer; typedef boost::unordered::detail::grouped_node_algo node_algo; }; - -template -struct table_equiv : boost::unordered::detail::table -{ - typedef boost::unordered::detail::table table; - typedef typename table::value_type value_type; - typedef typename table::bucket bucket; - typedef typename table::policy policy; - typedef typename table::node_pointer node_pointer; - typedef typename table::node_allocator node_allocator; - typedef typename table::node_allocator_traits node_allocator_traits; - typedef typename table::bucket_pointer bucket_pointer; - typedef typename table::link_pointer link_pointer; - typedef typename table::hasher hasher; - typedef typename table::key_equal key_equal; - typedef typename table::const_key_type const_key_type; - typedef typename table::node_constructor node_constructor; - typedef typename table::node_tmp node_tmp; - 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 - - table_equiv(std::size_t n, hasher const& hf, key_equal const& eq, - node_allocator const& a) - : table(n, hf, eq, a) - { - } - - table_equiv(table_equiv const& x) - : table(x, node_allocator_traits::select_on_container_copy_construction( - x.node_alloc())) - { - if (x.size_) { - copy_buckets(x); - } - } - - table_equiv(table_equiv const& x, node_allocator const& a) : table(x, a) - { - if (x.size_) { - copy_buckets(x); - } - } - - table_equiv(table_equiv& x, boost::unordered::detail::move_tag m) - : table(x, m) - { - // The move is done in the base class. - } - - table_equiv(table_equiv& x, node_allocator const& a, - boost::unordered::detail::move_tag m) - : table(x, a, m) - { - if (this->node_alloc() == x.node_alloc()) { - this->move_buckets_from(x); - } else if (x.size_) { - // TODO: Could pick new bucket size? - this->move_buckets(x); - } - } - - // Equality - - bool equals(table_equiv const& other) const - { - if (this->size_ != other.size_) - return false; - - for (node_pointer n1 = this->begin(); n1;) { - node_pointer n2 = other.find_node(other.get_key(n1)); - if (!n2) - return false; - 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; - } - - return true; - } - - static bool group_equals( - node_pointer n1, node_pointer end1, node_pointer n2, node_pointer end2) - { - for (;;) { - if (n1->value() != n2->value()) - break; - - n1 = node_algo::next_node(n1); - n2 = node_algo::next_node(n2); - - if (n1 == end1) - return n2 == end2; - if (n2 == end2) - return false; - } - - for (node_pointer n1a = n1, n2a = n2;;) { - n1a = node_algo::next_node(n1a); - n2a = node_algo::next_node(n2a); - - if (n1a == end1) { - if (n2a == end2) - break; - else - return false; - } - - if (n2a == end2) - return false; - } - - node_pointer start = 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(node_algo::next_node(n1), end1, v)) - return false; - } - } - - return true; - } - - static bool find(node_pointer n, node_pointer end, value_type const& v) - { - for (; n != end; n = node_algo::next_node(n)) - if (n->value() == v) - return true; - return false; - } - - static std::size_t count_equal( - node_pointer n, node_pointer end, value_type const& v) - { - std::size_t count = 0; - for (; n != end; n = node_algo::next_node(n)) - if (n->value() == v) - ++count; - return count; - } - - // Emplace/Insert - - inline node_pointer add_node( - node_pointer n, std::size_t key_hash, node_pointer pos) - { - n->hash_ = key_hash; - if (pos) { - node_algo::add_to_node_group(n, pos); - 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)) { - this->get_bucket(next_bucket)->next_ = n; - } - } - } else { - bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash)); - - 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; - } - - b->next_ = start_node; - n->next_ = start_node->next_; - start_node->next_ = n; - } else { - n->next_ = b->next_->next_; - b->next_->next_ = n; - } - } - ++this->size_; - return n; - } - - inline node_pointer add_using_hint(node_pointer n, node_pointer hint) - { - n->hash_ = hint->hash_; - node_algo::add_to_node_group(n, hint); - 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_)) { - this->get_bucket(next_bucket)->next_ = n; - } - } - ++this->size_; - return n; - } - - iterator emplace_impl(node_pointer n) - { - node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_); - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); - } - - iterator emplace_hint_impl(c_iterator hint, node_pointer n) - { - node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_); - if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_using_hint(a.release(), hint.node_)); - } else { - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - return iterator(this->add_node(a.release(), key_hash, position)); - } - } - - void emplace_impl_no_rehash(node_pointer n) - { - node_tmp a(n, this->node_alloc()); - const_key_type& k = this->get_key(a.node_); - std::size_t key_hash = this->hash(k); - node_pointer position = this->find_node(key_hash, k); - this->add_node(a.release(), key_hash, position); - } - - template iterator move_insert_node_type(NodeType& np) - { - iterator result; - - if (np) { - const_key_type& k = this->get_key(np.ptr_); - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_node(np.ptr_, key_hash, pos)); - np.ptr_ = node_pointer(); - } - - return result; - } - - template - iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np) - { - iterator result; - - if (np) { - const_key_type& k = this->get_key(np.ptr_); - - if (hint.node_ && this->key_eq()(k, this->get_key(hint.node_))) { - this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_using_hint(np.ptr_, hint.node_)); - } else { - std::size_t key_hash = this->hash(k); - node_pointer pos = this->find_node(key_hash, k); - this->reserve_for_insert(this->size_ + 1); - result = iterator(this->add_node(np.ptr_, key_hash, pos)); - } - np.ptr_ = node_pointer(); - } - - return result; - } - - //////////////////////////////////////////////////////////////////////// - // Insert range methods - - // if hash function throws, or inserting > 1 element, basic exception - // safety. Strong otherwise - template - void insert_range(I i, I j, - typename boost::unordered::detail::enable_if_forward::type = - 0) - { - if (i == j) - return; - - std::size_t distance = static_cast(std::distance(i, j)); - if (distance == 1) { - emplace_impl(boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } else { - // Only require basic exception safety here - this->reserve_for_insert(this->size_ + distance); - - for (; i != j; ++i) { - emplace_impl_no_rehash( - boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } - } - } - - template - void insert_range(I i, I j, - typename boost::unordered::detail::disable_if_forward::type = - 0) - { - for (; i != j; ++i) { - emplace_impl(boost::unordered::detail::func::construct_node( - this->node_alloc(), *i)); - } - } - - //////////////////////////////////////////////////////////////////////// - // Extract - - inline node_pointer extract_by_iterator(c_iterator n) - { - node_pointer i = n.node_; - BOOST_ASSERT(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 = 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); - } - } - - prev->next_ = i->next_; - --this->size_; - this->fix_bucket(bucket_index, prev); - i->next_ = link_pointer(); - - return i; - } - - //////////////////////////////////////////////////////////////////////// - // Erase - // - // no throw - - 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 = this->find_previous_node(k, key_hash, 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); - - std::size_t deleted_count = this->delete_nodes(prev, end); - this->fix_bucket(bucket_index, prev); - return deleted_count; - } - - link_pointer erase_nodes(node_pointer i, node_pointer j) - { - 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 = 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); - } - } - - // Delete the nodes. - // Is it inefficient to call fix_bucket for every node? - do { - this->delete_node(prev); - bucket_index = this->fix_bucket(bucket_index, prev); - } while (prev->next_ != j); - - return prev; - } - - //////////////////////////////////////////////////////////////////////// - // fill_buckets - - void copy_buckets(table const& src) - { - this->create_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)); - node_pointer pos = - this->add_node(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)) { - this->add_node(boost::unordered::detail::func::construct_node( - this->node_alloc(), n->value()), - key_hash, pos); - } - } - } - - void move_buckets(table const& src) - { - this->create_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)); - 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 = 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); - } - } - } - - void assign_buckets(table const& src) - { - node_holder 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)); - node_pointer pos = this->add_node( - 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)) { - this->add_node(holder.copy_of(n->value()), key_hash, pos); - } - } - } - - void move_assign_buckets(table& src) - { - node_holder 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)); - node_pointer pos = this->add_node( - 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)) { - this->add_node(holder.move_copy_of(n->value()), key_hash, pos); - } - } - } -}; } } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index a8bf9f3a..1d963965 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -29,8 +29,12 @@ template struct map typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_unique table; + 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; @@ -71,8 +75,12 @@ struct multimap typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_equiv table; + 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; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 2e7d6ef5..7b9bdca3 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -29,8 +29,12 @@ template struct set typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_unique table; + 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; @@ -70,8 +74,12 @@ template struct multiset typedef typename pick::link_pointer link_pointer; typedef typename pick::node_algo node_algo; - typedef boost::unordered::detail::table_equiv table; + 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; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index a55e2b5c..57798ca5 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -101,6 +101,7 @@ template class unordered_map BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -222,7 +223,7 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -248,7 +249,7 @@ template class unordered_map template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( boost::forward(a0))); @@ -258,7 +259,7 @@ template class unordered_map std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -269,7 +270,7 @@ template class unordered_map std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -284,7 +285,7 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -306,17 +307,17 @@ template class unordered_map template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -327,7 +328,7 @@ template class unordered_map iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -344,7 +345,7 @@ template class unordered_map std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_impl( \ + return table_.emplace_unique( \ table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -355,7 +356,7 @@ template class unordered_map iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint_impl( \ + return table_.emplace_hint_unique( \ hint, table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -424,7 +425,7 @@ template class unordered_map node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_unique(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -435,13 +436,13 @@ template class unordered_map insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; - table_.move_insert_node_type(np, result); + table_.move_insert_node_type_unique(np, result); return boost::move(result); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_unique(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -459,14 +460,14 @@ template class unordered_map std::pair try_emplace( key_type const& k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_impl(k, boost::forward(args)...); + return table_.try_emplace_unique(k, boost::forward(args)...); } template iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::forward(args)...); } @@ -474,7 +475,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::forward(args)...); } @@ -482,7 +483,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::forward(args)...); } @@ -491,20 +492,20 @@ template class unordered_map template std::pair try_emplace(BOOST_FWD_REF(Key) k) { - return table_.try_emplace_impl(boost::forward(k)); + return table_.try_emplace_unique(boost::forward(k)); } template iterator try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k) { - return table_.try_emplace_hint_impl(hint, boost::forward(k)); + return table_.try_emplace_hint_unique(hint, boost::forward(k)); } template std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -513,7 +514,7 @@ template class unordered_map iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -522,7 +523,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_impl( + return table_.try_emplace_hint_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -531,7 +532,7 @@ template class unordered_map iterator try_emplace( const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0))); } @@ -540,7 +541,7 @@ template class unordered_map std::pair try_emplace( key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); } @@ -549,7 +550,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); } @@ -558,7 +559,7 @@ template class unordered_map std::pair try_emplace( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); @@ -568,7 +569,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1))); @@ -578,7 +579,7 @@ template class unordered_map std::pair try_emplace(key_type const& k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))); @@ -589,7 +590,7 @@ template class unordered_map BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { return table_ - .try_emplace_impl_( + .try_emplace_unique( hint, k, boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))) @@ -600,7 +601,7 @@ template class unordered_map std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_impl( + return table_.try_emplace_unique( boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), boost::forward(a2))); @@ -610,7 +611,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.try_emplace_hint_impl( + return table_.try_emplace_hint_unique( hint, boost::move(k), boost::unordered::detail::create_emplace_args( boost::forward(a0), boost::forward(a1), @@ -623,7 +624,7 @@ template class unordered_map std::pair try_emplace( \ key_type const& k, BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_impl( \ + return table_.try_emplace_unique( \ k, boost::unordered::detail::create_emplace_args( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -632,7 +633,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, key_type const& k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_hint_impl(hint, k, \ + return table_.try_emplace_hint_unique(hint, k, \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -641,7 +642,7 @@ template class unordered_map std::pair try_emplace(BOOST_RV_REF(key_type) k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_impl(boost::move(k), \ + return table_.try_emplace_unique(boost::move(k), \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } \ @@ -650,7 +651,7 @@ template class unordered_map iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.try_emplace_hint_impl(hint, boost::move(k), \ + return table_.try_emplace_hint_unique(hint, boost::move(k), \ boost::unordered::detail::create_emplace_args(BOOST_PP_ENUM_##z( \ n, BOOST_UNORDERED_CALL_FORWARD, a))); \ } @@ -666,14 +667,14 @@ template class unordered_map std::pair insert_or_assign( key_type const& k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl(k, boost::forward(obj)); + return table_.insert_or_assign_unique(k, boost::forward(obj)); } template std::pair insert_or_assign( BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl( + return table_.insert_or_assign_unique( boost::move(k), boost::forward(obj)); } @@ -681,7 +682,7 @@ template class unordered_map iterator insert_or_assign( const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) { - return table_.insert_or_assign_impl(k, boost::forward(obj)).first; + return table_.insert_or_assign_unique(k, boost::forward(obj)).first; } template @@ -689,7 +690,7 @@ template class unordered_map const_iterator, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { return table_ - .insert_or_assign_impl(boost::move(k), boost::forward(obj)) + .insert_or_assign_unique(boost::move(k), boost::forward(obj)) .first; } @@ -883,6 +884,7 @@ template class unordered_multimap BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -1004,7 +1006,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -1028,7 +1030,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1038,7 +1040,7 @@ template class unordered_multimap template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1049,7 +1051,7 @@ template class unordered_multimap iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1064,7 +1066,7 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -1086,7 +1088,7 @@ template class unordered_multimap template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1097,7 +1099,7 @@ template class unordered_multimap iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1108,7 +1110,7 @@ template class unordered_multimap iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -1124,7 +1126,7 @@ template class unordered_multimap template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_impl( \ + return iterator(table_.emplace_equiv( \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ boost::unordered::detail::create_emplace_args( \ @@ -1135,7 +1137,7 @@ template class unordered_multimap iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_hint_impl( \ + return iterator(table_.emplace_hint_equiv( \ hint, \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ @@ -1202,7 +1204,7 @@ template class unordered_multimap node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_equiv(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -1212,12 +1214,12 @@ template class unordered_multimap iterator insert(BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type(np); + return table_.move_insert_node_type_equiv(np); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_equiv(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1376,8 +1378,13 @@ unordered_map::unordered_map(InputIt f, InputIt l, size_type n, template unordered_map::unordered_map(unordered_map const& other) - : table_(other.table_) + : table_(other.table_, + unordered_map::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { + if (other.table_.size_) { + table_.copy_buckets_unique(other.table_); + } } template @@ -1392,6 +1399,9 @@ unordered_map::unordered_map( unordered_map const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets_unique(other.table_); + } } template @@ -1399,6 +1409,12 @@ unordered_map::unordered_map( BOOST_RV_REF(unordered_map) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1515,7 +1531,7 @@ template void unordered_map::insert(InputIt first, InputIt last) { if (first != last) { - table_.insert_range_impl( + table_.insert_range_unique( table::extractor::extract(*first), first, last); } } @@ -1536,7 +1552,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); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1547,7 +1563,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); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1555,7 +1571,7 @@ template typename unordered_map::size_type unordered_map::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_unique(k); } template @@ -1565,7 +1581,7 @@ unordered_map::erase(const_iterator first, const_iterator last) node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_unique(table::get_node(first), last_node); return iterator(last_node); } @@ -1593,7 +1609,7 @@ template void unordered_map::merge( boost::unordered_map& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1602,7 +1618,7 @@ template void unordered_map::merge( boost::unordered_map&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif @@ -1612,7 +1628,7 @@ template void unordered_map::merge( boost::unordered_multimap& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1621,7 +1637,7 @@ template void unordered_map::merge( boost::unordered_multimap&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif #endif @@ -1709,14 +1725,14 @@ template typename unordered_map::mapped_type& unordered_map::operator[](const key_type& k) { - return table_.try_emplace_impl(k).first->second; + return table_.try_emplace_unique(k).first->second; } template typename unordered_map::mapped_type& unordered_map::operator[](BOOST_RV_REF(key_type) k) { - return table_.try_emplace_impl(boost::move(k)).first->second; + return table_.try_emplace_unique(boost::move(k)).first->second; } template @@ -1793,7 +1809,7 @@ inline bool operator==(unordered_map const& m1, unordered_map x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_unique(m2.table_); } template @@ -1806,7 +1822,7 @@ inline bool operator!=(unordered_map const& m1, unordered_map x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_unique(m2.table_); } template @@ -1852,8 +1868,13 @@ unordered_multimap::unordered_multimap(InputIt f, InputIt l, template unordered_multimap::unordered_multimap( unordered_multimap const& other) - : table_(other.table_) + : table_(other.table_, + unordered_multimap::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { + if (other.table_.size_) { + table_.copy_buckets_equiv(other.table_); + } } template @@ -1868,6 +1889,9 @@ unordered_multimap::unordered_multimap( unordered_multimap const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets_equiv(other.table_); + } } template @@ -1875,6 +1899,12 @@ unordered_multimap::unordered_multimap( BOOST_RV_REF(unordered_multimap) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets_equiv(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1990,7 +2020,7 @@ template template void unordered_multimap::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + table_.insert_range_equiv(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -2009,7 +2039,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); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2020,7 +2050,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); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2028,7 +2058,7 @@ template typename unordered_multimap::size_type unordered_multimap::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_equiv(k); } template @@ -2039,7 +2069,7 @@ unordered_multimap::erase( node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_equiv(table::get_node(first), last_node); return iterator(last_node); } @@ -2234,7 +2264,7 @@ inline bool operator==(unordered_multimap const& m1, unordered_multimap x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_equiv(m2.table_); } template @@ -2247,7 +2277,7 @@ inline bool operator!=(unordered_multimap const& m1, unordered_multimap x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_equiv(m2.table_); } template @@ -2268,10 +2298,7 @@ template class node_handle_map { BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map) - template - friend struct ::boost::unordered::detail::table_unique; - template - friend struct ::boost::unordered::detail::table_equiv; + template friend struct ::boost::unordered::detail::table; template friend class boost::unordered::unordered_map; template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 7bb86954..36645b99 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -99,6 +99,7 @@ template class unordered_set BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -220,7 +221,7 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(Args)... args) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -246,7 +247,7 @@ template class unordered_set template std::pair emplace(BOOST_FWD_REF(A0) a0) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( boost::forward(a0))); @@ -256,7 +257,7 @@ template class unordered_set std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -267,7 +268,7 @@ template class unordered_set std::pair emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_impl( + return table_.emplace_unique( table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -282,7 +283,7 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(args)...), boost::forward(args)...); } @@ -304,17 +305,17 @@ template class unordered_set template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return table_.emplace_hint_impl(hint, + return table_.emplace_hint_unique(hint, table::extractor::extract(boost::forward(a0)), boost::unordered::detail::create_emplace_args( - boost::forward(a0))); + boost::forward(a0))); } template iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -325,7 +326,7 @@ template class unordered_set iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return table_.emplace_hint_impl( + return table_.emplace_hint_unique( hint, table::extractor::extract( boost::forward(a0), boost::forward(a1)), boost::unordered::detail::create_emplace_args( @@ -342,7 +343,7 @@ template class unordered_set std::pair emplace( \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_impl( \ + return table_.emplace_unique( \ table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -353,7 +354,7 @@ template class unordered_set iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return table_.emplace_hint_impl( \ + return table_.emplace_hint_unique( \ hint, table::extractor::extract( \ boost::forward(a0), boost::forward(a1)), \ boost::unordered::detail::create_emplace_args( \ @@ -404,7 +405,7 @@ template class unordered_set node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_unique(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -415,13 +416,13 @@ template class unordered_set insert_return_type insert(BOOST_RV_REF(node_type) np) { insert_return_type result; - table_.move_insert_node_type(np, result); + table_.move_insert_node_type_unique(np, result); return boost::move(result); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_unique(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -609,6 +610,7 @@ template class unordered_multiset BOOST_NOEXCEPT_IF(table::nothrow_move_constructible) : table_(other.table_, boost::unordered::detail::move_tag()) { + // The move is done in table_ } #endif @@ -730,7 +732,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -754,7 +756,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -764,7 +766,7 @@ template class unordered_multiset template iterator emplace(BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -775,7 +777,7 @@ template class unordered_multiset iterator emplace( BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_impl( + return iterator(table_.emplace_equiv( boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -790,7 +792,7 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(Args)... args) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::forward(args)...))); } @@ -812,7 +814,7 @@ template class unordered_multiset template iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -823,7 +825,7 @@ template class unordered_multiset iterator emplace_hint( const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -834,7 +836,7 @@ template class unordered_multiset iterator emplace_hint(const_iterator hint, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) { - return iterator(table_.emplace_hint_impl( + return iterator(table_.emplace_hint_equiv( hint, boost::unordered::detail::func::construct_node_from_args( table_.node_alloc(), boost::unordered::detail::create_emplace_args( @@ -850,7 +852,7 @@ template class unordered_multiset template \ iterator emplace(BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_impl( \ + return iterator(table_.emplace_equiv( \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ boost::unordered::detail::create_emplace_args( \ @@ -861,7 +863,7 @@ template class unordered_multiset iterator emplace_hint(const_iterator hint, \ BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a)) \ { \ - return iterator(table_.emplace_hint_impl( \ + return iterator(table_.emplace_hint_equiv( \ hint, \ boost::unordered::detail::func::construct_node_from_args( \ table_.node_alloc(), \ @@ -910,7 +912,7 @@ template class unordered_multiset node_type extract(const_iterator position) { return node_type( - table_.extract_by_iterator(position), table_.node_alloc()); + table_.extract_by_iterator_equiv(position), table_.node_alloc()); } node_type extract(const key_type& k) @@ -920,12 +922,12 @@ template class unordered_multiset iterator insert(BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type(np); + return table_.move_insert_node_type_equiv(np); } iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np) { - return table_.move_insert_node_type_with_hint(hint, np); + return table_.move_insert_node_type_with_hint_equiv(hint, np); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1075,8 +1077,13 @@ unordered_set::unordered_set(InputIt f, InputIt l, size_type n, template unordered_set::unordered_set(unordered_set const& other) - : table_(other.table_) + : table_(other.table_, + unordered_set::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { + if (other.table_.size_) { + table_.copy_buckets_unique(other.table_); + } } template @@ -1091,6 +1098,9 @@ unordered_set::unordered_set( unordered_set const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets_unique(other.table_); + } } template @@ -1098,6 +1108,12 @@ unordered_set::unordered_set( BOOST_RV_REF(unordered_set) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1211,7 +1227,7 @@ template void unordered_set::insert(InputIt first, InputIt last) { if (first != last) { - table_.insert_range_impl( + table_.insert_range_unique( table::extractor::extract(*first), first, last); } } @@ -1231,7 +1247,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); - table_.erase_nodes(node, next); + table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1239,7 +1255,7 @@ template typename unordered_set::size_type unordered_set::erase( const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_unique(k); } template @@ -1249,7 +1265,7 @@ typename unordered_set::iterator unordered_set::erase( node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_unique(table::get_node(first), last_node); return iterator(last_node); } @@ -1293,7 +1309,7 @@ template void unordered_set::merge( boost::unordered_set& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1302,7 +1318,7 @@ template void unordered_set::merge( boost::unordered_set&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif @@ -1312,7 +1328,7 @@ template void unordered_set::merge( boost::unordered_multiset& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -1321,7 +1337,7 @@ template void unordered_set::merge( boost::unordered_multiset&& source) { - table_.merge_impl(source.table_); + table_.merge_unique(source.table_); } #endif #endif @@ -1408,7 +1424,7 @@ inline bool operator==( unordered_set x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_unique(m2.table_); } template @@ -1421,7 +1437,7 @@ inline bool operator!=( unordered_set x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_unique(m2.table_); } template @@ -1466,8 +1482,13 @@ unordered_multiset::unordered_multiset(InputIt f, InputIt l, template unordered_multiset::unordered_multiset( unordered_multiset const& other) - : table_(other.table_) + : table_(other.table_, + unordered_multiset::value_allocator_traits:: + select_on_container_copy_construction(other.get_allocator())) { + if (other.table_.size_) { + table_.copy_buckets_equiv(other.table_); + } } template @@ -1482,6 +1503,9 @@ unordered_multiset::unordered_multiset( unordered_multiset const& other, allocator_type const& a) : table_(other.table_, a) { + if (other.table_.size_) { + table_.copy_buckets_equiv(other.table_); + } } template @@ -1489,6 +1513,12 @@ unordered_multiset::unordered_multiset( BOOST_RV_REF(unordered_multiset) other, allocator_type const& a) : table_(other.table_, a, boost::unordered::detail::move_tag()) { + if (table_.node_alloc() == other.table_.node_alloc()) { + table_.move_buckets_from(other.table_); + } else if (other.table_.size_) { + // TODO: Could pick new bucket size? + table_.move_buckets_equiv(other.table_); + } } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1604,7 +1634,7 @@ template template void unordered_multiset::insert(InputIt first, InputIt last) { - table_.insert_range(first, last); + table_.insert_range_equiv(first, last); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1623,7 +1653,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); - table_.erase_nodes(node, next); + table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -1631,7 +1661,7 @@ template typename unordered_multiset::size_type unordered_multiset::erase(const key_type& k) { - return table_.erase_key(k); + return table_.erase_key_equiv(k); } template @@ -1641,7 +1671,7 @@ unordered_multiset::erase(const_iterator first, const_iterator last) node_pointer last_node = table::get_node(last); if (first == last) return iterator(last_node); - table_.erase_nodes(table::get_node(first), last_node); + table_.erase_nodes_equiv(table::get_node(first), last_node); return iterator(last_node); } @@ -1809,7 +1839,7 @@ inline bool operator==(unordered_multiset const& m1, unordered_multiset x; }; #endif - return m1.table_.equals(m2.table_); + return m1.table_.equals_equiv(m2.table_); } template @@ -1822,7 +1852,7 @@ inline bool operator!=(unordered_multiset const& m1, unordered_multiset x; }; #endif - return !m1.table_.equals(m2.table_); + return !m1.table_.equals_equiv(m2.table_); } template @@ -1843,10 +1873,7 @@ template class node_handle_set { BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set) - template - friend struct ::boost::unordered::detail::table_unique; - template - friend struct ::boost::unordered::detail::table_equiv; + template friend struct ::boost::unordered::detail::table; template friend class unordered_set; template diff --git a/test/unordered/incomplete_test.cpp b/test/unordered/incomplete_test.cpp index 8848fe80..860606b3 100644 --- a/test/unordered/incomplete_test.cpp +++ b/test/unordered/incomplete_test.cpp @@ -65,6 +65,11 @@ template struct allocator : std::allocator allocator(const allocator& other) : std::allocator(other) { } + + template + allocator(const std::allocator& other) : std::allocator(other) + { + } }; // Declare some members of a structs.