forked from boostorg/unordered
Fix merging between containers with different hash/equality
This reverts commit 20b0c0a6d8
.
This commit is contained in:
@ -3540,45 +3540,26 @@ struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
(boost::is_same<node, typename other_table::node>::value));
|
||||
BOOST_ASSERT(this->node_alloc() == other.node_alloc());
|
||||
|
||||
if (!other.size_) {
|
||||
return;
|
||||
}
|
||||
if (other.size_) {
|
||||
link_pointer prev = other.get_previous_start();
|
||||
|
||||
link_pointer prev = other.get_previous_start();
|
||||
node_pointer n = other_table::next_node(prev);
|
||||
while (n) {
|
||||
const_key_type& k = this->get_key(n);
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
while (prev->next_) {
|
||||
node_pointer n = other_table::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;
|
||||
n = other_table::next_node(prev);
|
||||
} else {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
|
||||
prev->next_ = n->next_;
|
||||
--other.size_;
|
||||
other.fix_bucket(other.node_bucket(n), prev);
|
||||
this->add_node_unique(n, key_hash);
|
||||
n = other_table::next_node(prev);
|
||||
|
||||
// If the next node was from the same group, it's now
|
||||
// the first node in the group.
|
||||
if (n && !n->is_first_in_group()) {
|
||||
n->set_first_in_group();
|
||||
if (pos) {
|
||||
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;
|
||||
} else {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
prev->next_ = n->next_;
|
||||
if (prev->next_ && n->is_first_in_group()) {
|
||||
next_node(prev)->set_first_in_group();
|
||||
}
|
||||
--other.size_;
|
||||
other.fix_bucket(other.node_bucket(n), prev);
|
||||
this->add_node_unique(n, key_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,8 @@ void merge_into_empty_test(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator)
|
||||
void merge_into_unique_keys_test(
|
||||
X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -179,8 +180,10 @@ void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator)
|
||||
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
|
||||
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
|
||||
|
||||
X1 x1(v1.begin(), v1.end());
|
||||
X2 x2(v2.begin(), v2.end());
|
||||
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
|
||||
test::equal_to(hash_equal1));
|
||||
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
|
||||
test::equal_to(hash_equal2));
|
||||
x1.merge(x2);
|
||||
|
||||
test::ordered<X1> tracker1 = test::create_ordered(x1);
|
||||
@ -203,7 +206,8 @@ void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void merge_into_equiv_keys_test(X1*, X2*, test::random_generator generator)
|
||||
void merge_into_equiv_keys_test(
|
||||
X1*, X2*, int hash_equal1, int hash_equal2, test::random_generator generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@ -212,16 +216,21 @@ void merge_into_equiv_keys_test(X1*, X2*, test::random_generator generator)
|
||||
v1.insert(v2.begin(), boost::next(v2.begin(), 100));
|
||||
v2.insert(v1.begin(), boost::next(v1.begin(), 100));
|
||||
|
||||
X1 x1(v1.begin(), v1.end());
|
||||
X2 x2(v2.begin(), v2.end());
|
||||
X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1),
|
||||
test::equal_to(hash_equal1));
|
||||
X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2),
|
||||
test::equal_to(hash_equal2));
|
||||
x1.merge(x2);
|
||||
|
||||
test::ordered<X1> tracker1 = test::create_ordered(x1);
|
||||
test::ordered<X2> tracker2 = test::create_ordered(x2);
|
||||
tracker1.insert(v1.begin(), v1.end());
|
||||
tracker1.insert(v2.begin(), v2.end());
|
||||
tracker2.insert(v2.begin(), v2.end());
|
||||
tracker1.insert(tracker2.begin(), tracker2.end());
|
||||
tracker2.clear();
|
||||
|
||||
tracker1.compare(x1);
|
||||
BOOST_TEST(x2.empty());
|
||||
tracker2.compare(x2);
|
||||
test::check_equivalent_keys(x1);
|
||||
test::check_equivalent_keys(x2);
|
||||
}
|
||||
@ -231,8 +240,8 @@ boost::unordered_set<test::movable, test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_multiset_std_alloc;
|
||||
|
||||
boost::unordered_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_map_std_alloc;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
|
||||
@ -283,35 +292,51 @@ UNORDERED_TEST(merge_into_empty_test,
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_set_std_alloc))
|
||||
((test_set_std_alloc)(test_multiset_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_map_std_alloc))
|
||||
((test_map_std_alloc)(test_multimap_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_set))
|
||||
((test_set)(test_multiset))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_map))
|
||||
((test_map)(test_multimap))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
|
||||
UNORDERED_TEST(merge_into_equiv_keys_test,
|
||||
((test_multiset_std_alloc))
|
||||
((test_set_std_alloc)(test_multiset_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_equiv_keys_test,
|
||||
((test_multimap_std_alloc))
|
||||
((test_map_std_alloc)(test_multimap_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_equiv_keys_test,
|
||||
((test_multiset))
|
||||
((test_set)(test_multiset))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_equiv_keys_test,
|
||||
((test_multimap))
|
||||
((test_map)(test_multimap))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
// clang-format on
|
||||
|
||||
|
Reference in New Issue
Block a user