Only consider one node from each group in merge_unique

This commit is contained in:
Daniel James
2017-04-27 18:22:44 +01:00
parent a1b1df84a0
commit 20b0c0a6d8

View File

@@ -3577,8 +3577,6 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
return iterator(pos); return iterator(pos);
} }
// TODO: Could speed this up a little by only considering
// the first node in a group.
template <typename Types2> template <typename Types2>
void merge_unique(boost::unordered::detail::table<Types2>& other) void merge_unique(boost::unordered::detail::table<Types2>& other)
{ {
@@ -3587,26 +3585,45 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
(boost::is_same<node, typename other_table::node>::value)); (boost::is_same<node, typename other_table::node>::value));
BOOST_ASSERT(this->node_alloc() == other.node_alloc()); BOOST_ASSERT(this->node_alloc() == other.node_alloc());
if (other.size_) { if (!other.size_) {
link_pointer prev = other.get_previous_start(); return;
}
while (prev->next_) { link_pointer prev = other.get_previous_start();
node_pointer n = other_table::next_node(prev); node_pointer n = other_table::next_node(prev);
while (n) {
const_key_type& k = this->get_key(n); const_key_type& k = this->get_key(n);
std::size_t key_hash = this->hash(k); std::size_t key_hash = this->hash(k);
node_pointer pos = this->find_node(key_hash, k); node_pointer pos = this->find_node(key_hash, k);
if (pos) { if (pos) {
prev = n; prev = n;
n = other_table::next_node(prev);
} else { } else {
this->reserve_for_insert(this->size_ + 1); this->reserve_for_insert(this->size_ + 1);
prev->next_ = n->next_; prev->next_ = n->next_;
if (prev->next_ && n->is_first_in_group()) {
next_node(prev)->set_first_in_group();
}
--other.size_; --other.size_;
other.fix_bucket(other.node_bucket(n), prev); other.fix_bucket(other.node_bucket(n), prev);
this->add_node_unique(n, key_hash); this->add_node_unique(n, key_hash);
n = other_table::next_node(prev);
// If the next node was from the same group, it's now
// the first node in the group.
if (n && !n->is_first_in_group()) {
n->set_first_in_group();
prev = n;
n = other_table::next_node(prev);
}
}
// Skip over rest of group of nodes with equivalent keys,
// as we know there's already one in the container.
while (n && !n->is_first_in_group()) {
prev = n;
n = other_table::next_node(prev);
if (!n) {
return;
} }
} }
} }