diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 6774ce00..f006a03b 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3540,45 +3540,26 @@ struct table : boost::unordered::detail::functions::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); } } } diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index b848e4f3..59b0b4a5 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -170,7 +170,8 @@ void merge_into_empty_test(X*, test::random_generator generator) } template -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 tracker1 = test::create_ordered(x1); @@ -203,7 +206,8 @@ void merge_into_unique_keys_test(X1*, X2*, test::random_generator generator) } template -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 tracker1 = test::create_ordered(x1); + test::ordered 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_multiset_std_alloc; -boost::unordered_map >* test_map_std_alloc; +boost::unordered_map >* test_map_std_alloc; boost::unordered_multimap >* 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