diff --git a/doc/ref.php b/doc/ref.php
index f6e26e91..abdb9a17 100644
--- a/doc/ref.php
+++ b/doc/ref.php
@@ -7,6 +7,10 @@ function echo_unordered_docs(
$name = 'unordered_'.
($equivalent_keys ? 'multi' : '').
($map ? 'map' : 'set');
+ // For merge....
+ $node_partner = 'unordered_'.
+ ($equivalent_keys ? '' : 'multi').
+ ($map ? 'map' : 'set');
if ($map)
{
@@ -1157,6 +1161,68 @@ EOL;
the equality predieate and hash function are swapped using their copy constructors.
+
+
+
+
+
+
+
+
+
+ <Key, Mapped, H2, P2, Alloc>&
+
+ <Value, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+
+
+ <Key, Mapped, H2, P2, Alloc>&&
+
+ <Value, H2, P2, Alloc>&&
+
+
+
+
+
+
+
+
+
+
+
+
+ <Key, Mapped, H2, P2, Alloc>&
+
+ <Value, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+
+
+ <Key, Mapped, H2, P2, Alloc>&&
+
+ <Value, H2, P2, Alloc>&&
+
+
+
+*/ ?>
diff --git a/doc/ref.xml b/doc/ref.xml
index bdb368e0..755721ca 100644
--- a/doc/ref.xml
+++ b/doc/ref.xml
@@ -1028,6 +1028,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
the equality predieate and hash function are swapped using their copy constructors.
+
+
+
+
+
+
+
+
+ unordered_set<Value, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+ unordered_set<Value, H2, P2, Alloc>&&
+
+
@@ -2382,6 +2404,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
the equality predieate and hash function are swapped using their copy constructors.
+
+
+
+
+
+
+
+
+ unordered_multiset<Value, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+ unordered_multiset<Value, H2, P2, Alloc>&&
+
+
@@ -3859,6 +3903,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
the equality predieate and hash function are swapped using their copy constructors.
+
+
+
+
+
+
+
+
+ unordered_map<Key, Mapped, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+ unordered_map<Key, Mapped, H2, P2, Alloc>&&
+
+
@@ -5260,6 +5326,28 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
the equality predieate and hash function are swapped using their copy constructors.
+
+
+
+
+
+
+
+
+ unordered_multimap<Key, Mapped, H2, P2, Alloc>&
+
+
+
+
+
+
+
+
+
+
+ unordered_multimap<Key, Mapped, H2, P2, Alloc>&&
+
+
diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp
index bbda40b1..cb6b14bc 100644
--- a/include/boost/unordered/detail/implementation.hpp
+++ b/include/boost/unordered/detail/implementation.hpp
@@ -3840,6 +3840,30 @@ struct table_impl : boost::unordered::detail::table
return iterator(pos);
}
+ template void merge_impl(table_impl& other)
+ {
+ if (other.size_) {
+ link_pointer prev = other.get_previous_start();
+
+ while (prev->next_) {
+ node_pointer n = other.next_node(prev);
+ const_key_type& k = this->get_key(n->value());
+ 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);
+ 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
//
diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp
index ab1c79e7..8ba7e83d 100644
--- a/include/boost/unordered/unordered_map.hpp
+++ b/include/boost/unordered/unordered_map.hpp
@@ -617,6 +617,17 @@ template class unordered_map
void clear();
void swap(unordered_map&);
+ template
+ void merge(boost::unordered_map& source);
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template
+ void merge(boost::unordered_map&& source);
+#endif
+ // template
+ // void merge(boost::unordered_multimap& source);
+ // template
+ // void merge(boost::unordered_multimap&& source);
+
// observers
hasher hash_function() const;
@@ -1055,6 +1066,17 @@ template class unordered_multimap
void clear();
void swap(unordered_multimap&);
+ template
+ void merge(boost::unordered_multimap& source);
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template
+ void merge(boost::unordered_multimap&& source);
+#endif
+ // template
+ // void merge(boost::unordered_map& source);
+ // template
+ // void merge(boost::unordered_map&& source);
+
// observers
hasher hash_function() const;
@@ -1356,6 +1378,24 @@ void unordered_map::swap(unordered_map& other)
table_.swap(other.table_);
}
+template
+template
+void unordered_map::merge(
+ boost::unordered_map& source)
+{
+ table_.merge_impl(source.table_);
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+template
+template
+void unordered_map::merge(
+ boost::unordered_map&& source)
+{
+ table_.merge_impl(source.table_);
+}
+#endif
+
// observers
template
@@ -1756,6 +1796,28 @@ unordered_multimap::key_eq() const
return table_.key_eq();
}
+template
+template
+void unordered_multimap::merge(
+ boost::unordered_multimap& source)
+{
+ while (!source.empty()) {
+ insert(source.extract(source.begin()));
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+template
+template
+void unordered_multimap::merge(
+ boost::unordered_multimap&& source)
+{
+ while (!source.empty()) {
+ insert(source.extract(source.begin()));
+ }
+}
+#endif
+
// lookup
template
diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp
index 1f1efe47..9eb90898 100644
--- a/include/boost/unordered/unordered_set.hpp
+++ b/include/boost/unordered/unordered_set.hpp
@@ -391,6 +391,17 @@ template class unordered_set
void clear();
void swap(unordered_set&);
+ template
+ void merge(boost::unordered_set& source);
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template
+ void merge(boost::unordered_set&& source);
+#endif
+ // template
+ // void merge(boost::unordered_multiset& source);
+ // template
+ // void merge(boost::unordered_multiset&& source);
+
// observers
hasher hash_function() const;
@@ -817,6 +828,17 @@ template class unordered_multiset
void clear();
void swap(unordered_multiset&);
+ template
+ void merge(boost::unordered_multiset& source);
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ template
+ void merge(boost::unordered_multiset&& source);
+#endif
+ // template
+ // void merge(boost::unordered_set& source);
+ // template
+ // void merge(boost::unordered_set&& source);
+
// observers
hasher hash_function() const;
@@ -1123,6 +1145,24 @@ unordered_set::key_eq() const
return table_.key_eq();
}
+template
+template
+void unordered_set::merge(
+ boost::unordered_set& source)
+{
+ table_.merge_impl(source.table_);
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+template
+template
+void unordered_set::merge(
+ boost::unordered_set&& source)
+{
+ table_.merge_impl(source.table_);
+}
+#endif
+
// lookup
template
@@ -1460,6 +1500,28 @@ unordered_multiset::key_eq() const
return table_.key_eq();
}
+template
+template
+void unordered_multiset::merge(
+ boost::unordered_multiset& source)
+{
+ while (!source.empty()) {
+ insert(source.extract(source.begin()));
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+template
+template
+void unordered_multiset::merge(
+ boost::unordered_multiset&& source)
+{
+ while (!source.empty()) {
+ insert(source.extract(source.begin()));
+ }
+}
+#endif
+
// lookup
template
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 3d7c26c8..2aad7e8d 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -49,6 +49,7 @@ test-suite unordered
[ run unordered/erase_equiv_tests.cpp ]
[ run unordered/extract_tests.cpp ]
[ run unordered/node_handle_tests.cpp ]
+ [ run unordered/merge_tests.cpp ]
[ compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MAP : insert_node_type_fail_map ]
[ compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ]
[ compile-fail unordered/insert_node_type_fail.cpp : UNORDERED_TEST_SET : insert_node_type_fail_set ]
diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp
index b8a6dc8a..c84b04e9 100644
--- a/test/unordered/compile_tests.hpp
+++ b/test/unordered/compile_tests.hpp
@@ -551,6 +551,11 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
a.max_load_factor((float)2.0);
a.rehash(100);
+ a.merge(a2);
+#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
+ a.merge(rvalue_default());
+#endif
+
// Avoid unused variable warnings:
sink(a);
diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp
new file mode 100644
index 00000000..10337559
--- /dev/null
+++ b/test/unordered/merge_tests.cpp
@@ -0,0 +1,214 @@
+
+// Copyright 2016 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include "../helpers/postfix.hpp"
+#include "../helpers/prefix.hpp"
+#include
+#include
+
+#include "../helpers/count.hpp"
+#include "../helpers/helpers.hpp"
+#include "../helpers/invariants.hpp"
+#include "../helpers/random_values.hpp"
+#include "../helpers/test.hpp"
+#include "../helpers/tracker.hpp"
+#include "../objects/test.hpp"
+#include
+
+namespace merge_tests {
+
+UNORDERED_AUTO_TEST(merge_set)
+{
+ boost::unordered_set x;
+ boost::unordered_set y;
+
+ x.merge(y);
+ BOOST_TEST(x.empty());
+ BOOST_TEST(y.empty());
+
+ x.insert(10);
+ x.merge(y);
+ BOOST_TEST(x.size() == 1);
+ BOOST_TEST(x.count(10) == 1);
+ BOOST_TEST(y.empty());
+
+ y.merge(x);
+ BOOST_TEST(x.empty());
+ BOOST_TEST(y.size() == 1);
+ BOOST_TEST(y.count(10) == 1);
+
+ x.insert(10);
+ x.insert(50);
+ y.insert(70);
+ y.insert(80);
+ x.merge(y);
+ BOOST_TEST_EQ(x.size(), 4u);
+ BOOST_TEST_EQ(y.size(), 1u);
+ BOOST_TEST_EQ(x.count(10), 1u);
+ BOOST_TEST_EQ(x.count(50), 1u);
+ BOOST_TEST_EQ(x.count(70), 1u);
+ BOOST_TEST_EQ(x.count(80), 1u);
+ BOOST_TEST_EQ(y.count(10), 1u);
+ BOOST_TEST_EQ(y.count(50), 0u);
+ BOOST_TEST_EQ(y.count(70), 0u);
+ BOOST_TEST_EQ(y.count(80), 0u);
+
+ test::check_equivalent_keys(x);
+ test::check_equivalent_keys(y);
+}
+
+UNORDERED_AUTO_TEST(merge_multiset)
+{
+ boost::unordered_multiset x;
+ boost::unordered_multiset y;
+
+ x.merge(y);
+ BOOST_TEST(x.empty());
+ BOOST_TEST(y.empty());
+
+ x.insert(10);
+ x.merge(y);
+ BOOST_TEST(x.size() == 1);
+ BOOST_TEST(x.count(10) == 1);
+ BOOST_TEST(y.empty());
+
+ y.merge(x);
+ BOOST_TEST(x.empty());
+ BOOST_TEST(y.size() == 1);
+ BOOST_TEST(y.count(10) == 1);
+
+ x.insert(10);
+ x.insert(50);
+ y.insert(70);
+ y.insert(80);
+ x.merge(y);
+ BOOST_TEST_EQ(x.size(), 5u);
+ BOOST_TEST_EQ(y.size(), 0u);
+ BOOST_TEST_EQ(x.count(10), 2u);
+ BOOST_TEST_EQ(x.count(50), 1u);
+ BOOST_TEST_EQ(x.count(70), 1u);
+ BOOST_TEST_EQ(x.count(80), 1u);
+ BOOST_TEST_EQ(y.count(10), 0u);
+ BOOST_TEST_EQ(y.count(50), 0u);
+ BOOST_TEST_EQ(y.count(70), 0u);
+ BOOST_TEST_EQ(y.count(80), 0u);
+
+ test::check_equivalent_keys(x);
+ test::check_equivalent_keys(y);
+}
+
+template void merge_empty_test(X*, test::random_generator generator)
+{
+ test::check_instances check_;
+
+ test::random_values v(1000, generator);
+ X x1(v.begin(), v.end()), x2;
+ x1.merge(x2);
+ test::check_container(x1, v);
+ BOOST_TEST(x2.empty());
+ test::check_equivalent_keys(x1);
+ test::check_equivalent_keys(x2);
+}
+
+template
+void merge_into_empty_test(X*, test::random_generator generator)
+{
+ test::check_instances check_;
+
+ test::random_values v(1000, generator);
+ X x1, x2(v.begin(), v.end());
+ x1.merge(x2);
+ test::check_container(x1, v);
+ BOOST_TEST(x2.empty());
+ test::check_equivalent_keys(x1);
+ test::check_equivalent_keys(x2);
+}
+
+template void unique_merge_test(X*, test::random_generator generator)
+{
+ test::check_instances check_;
+
+ test::random_values v1(1000, generator);
+ test::random_values v2(1000, generator);
+ v1.insert(v2.begin(), boost::next(v2.begin(), 100));
+ v2.insert(v1.begin(), boost::next(v1.begin(), 100));
+
+ X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
+ x1.merge(x2);
+
+ test::ordered tracker1 = test::create_ordered(x1);
+ test::ordered tracker2 = test::create_ordered(x2);
+ test::ordered tracker_tmp = test::create_ordered(x2);
+ tracker1.insert(v1.begin(), v1.end());
+ tracker_tmp.insert(v2.begin(), v2.end());
+ for (BOOST_DEDUCED_TYPENAME test::ordered::iterator it =
+ tracker_tmp.begin();
+ it != tracker_tmp.end(); ++it) {
+ if (!tracker1.insert(*it).second) {
+ tracker2.insert(*it);
+ }
+ }
+
+ tracker1.compare(x1);
+ tracker2.compare(x2);
+ test::check_equivalent_keys(x1);
+ test::check_equivalent_keys(x2);
+}
+
+template void equiv_merge_test(X*, test::random_generator generator)
+{
+ test::check_instances check_;
+
+ test::random_values v1(1000, generator);
+ test::random_values v2(1000, generator);
+ v1.insert(v2.begin(), boost::next(v2.begin(), 100));
+ v2.insert(v1.begin(), boost::next(v1.begin(), 100));
+
+ X x1(v1.begin(), v1.end()), x2(v2.begin(), v2.end());
+ x1.merge(x2);
+
+ test::ordered tracker1 = test::create_ordered(x1);
+ tracker1.insert(v1.begin(), v1.end());
+ tracker1.insert(v2.begin(), v2.end());
+
+ tracker1.compare(x1);
+ BOOST_TEST(x2.empty());
+ test::check_equivalent_keys(x1);
+ test::check_equivalent_keys(x2);
+}
+
+boost::unordered_set >* test_set_std_alloc;
+boost::unordered_multimap >* test_multimap_std_alloc;
+
+boost::unordered_set >* test_set;
+boost::unordered_multiset >* test_multiset;
+boost::unordered_map >* test_map;
+boost::unordered_multimap >* test_multimap;
+
+using test::default_generator;
+using test::generate_collisions;
+
+UNORDERED_TEST(merge_empty_test,
+ ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
+ test_map)(test_multimap))((default_generator)(generate_collisions)))
+
+UNORDERED_TEST(merge_into_empty_test,
+ ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_multiset)(
+ test_map)(test_multimap))((default_generator)(generate_collisions)))
+
+UNORDERED_TEST(unique_merge_test,
+ ((test_set_std_alloc)(test_set)(test_map))((default_generator)))
+
+UNORDERED_TEST(equiv_merge_test, ((test_multimap_std_alloc)(test_multiset)(
+ test_multimap))((default_generator)))
+}
+
+RUN_TESTS()