From 4aa74e5febbe171f861a0a41cee76709831f9194 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 27 Feb 2017 03:59:02 +0000 Subject: [PATCH] Merge between set/multiset and map/multimap --- .../boost/unordered/detail/implementation.hpp | 20 +++-- include/boost/unordered/unordered_map.hpp | 79 ++++++++++++++++-- include/boost/unordered/unordered_set.hpp | 80 +++++++++++++++++-- test/unordered/merge_tests.cpp | 42 ++++++++++ 4 files changed, 199 insertions(+), 22 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 2e68d17c..871ad5a7 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include #include @@ -730,11 +732,8 @@ template struct identity #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0 #include -#include #include -#if defined(BOOST_NO_SFINAE_EXPR) -#include -#endif +#include #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ !defined(BOOST_NO_SFINAE_EXPR) @@ -3609,6 +3608,7 @@ struct table_impl : 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; @@ -4001,13 +4001,19 @@ struct table_impl : boost::unordered::detail::table return iterator(pos); } - template void merge_impl(table_impl& other) + 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 = Types2::node_algo::next_node(prev); + node_pointer n = other_table::node_algo::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); @@ -4016,6 +4022,8 @@ struct table_impl : boost::unordered::detail::table 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); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 8ba7e83d..0ff64fbf 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -39,6 +39,8 @@ template class unordered_map #if defined(BOOST_UNORDERED_USE_MOVE) BOOST_COPYABLE_AND_MOVABLE(unordered_map) #endif + template + friend class unordered_multimap; public: typedef K key_type; @@ -619,14 +621,21 @@ template class 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); + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template + void merge(boost::unordered_multimap& source); + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void merge(boost::unordered_multimap&& source); +#endif +#endif // observers @@ -723,6 +732,9 @@ template class unordered_multimap #if defined(BOOST_UNORDERED_USE_MOVE) BOOST_COPYABLE_AND_MOVABLE(unordered_multimap) #endif + template + friend class unordered_map; + public: typedef K key_type; typedef std::pair value_type; @@ -1068,14 +1080,21 @@ template class 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); + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template + void merge(boost::unordered_map& source); + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void merge(boost::unordered_map&& source); +#endif +#endif // observers @@ -1396,6 +1415,26 @@ void unordered_map::merge( } #endif +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template +template +void unordered_map::merge( + boost::unordered_multimap& source) +{ + table_.merge_impl(source.table_); +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template +template +void unordered_map::merge( + boost::unordered_multimap&& source) +{ + table_.merge_impl(source.table_); +} +#endif +#endif + // observers template @@ -1818,6 +1857,30 @@ void unordered_multimap::merge( } #endif +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template +template +void unordered_multimap::merge( + boost::unordered_map& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); + } +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template +template +void unordered_multimap::merge( + boost::unordered_map&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); + } +} +#endif +#endif + // lookup template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 9eb90898..40d566c2 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -39,6 +39,9 @@ template class unordered_set #if defined(BOOST_UNORDERED_USE_MOVE) BOOST_COPYABLE_AND_MOVABLE(unordered_set) #endif + template + friend class unordered_multiset; + public: typedef T key_type; typedef T value_type; @@ -393,14 +396,21 @@ template class 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); + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template + void merge(boost::unordered_multiset& source); + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void merge(boost::unordered_multiset&& source); +#endif +#endif // observers @@ -486,6 +496,9 @@ template class unordered_multiset #if defined(BOOST_UNORDERED_USE_MOVE) BOOST_COPYABLE_AND_MOVABLE(unordered_multiset) #endif + template + friend class unordered_set; + public: typedef T key_type; typedef T value_type; @@ -830,14 +843,21 @@ template class 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); + +#if BOOST_UNORDERED_INTEROPERABLE_NODES + template + void merge(boost::unordered_set& source); + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void merge(boost::unordered_set&& source); +#endif +#endif // observers @@ -1163,6 +1183,26 @@ void unordered_set::merge( } #endif +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template +template +void unordered_set::merge( + boost::unordered_multiset& source) +{ + table_.merge_impl(source.table_); +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template +template +void unordered_set::merge( + boost::unordered_multiset&& source) +{ + table_.merge_impl(source.table_); +} +#endif +#endif + // lookup template @@ -1522,6 +1562,30 @@ void unordered_multiset::merge( } #endif +#if BOOST_UNORDERED_INTEROPERABLE_NODES +template +template +void unordered_multiset::merge( + boost::unordered_set& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); + } +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template +template +void unordered_multiset::merge( + boost::unordered_set&& source) +{ + while (!source.empty()) { + insert(source.extract(source.begin())); + } +} +#endif +#endif + // lookup template diff --git a/test/unordered/merge_tests.cpp b/test/unordered/merge_tests.cpp index 10337559..15755ab8 100644 --- a/test/unordered/merge_tests.cpp +++ b/test/unordered/merge_tests.cpp @@ -99,6 +99,48 @@ UNORDERED_AUTO_TEST(merge_multiset) test::check_equivalent_keys(y); } +#if BOOST_UNORDERED_INTEROPERABLE_NODES +UNORDERED_AUTO_TEST(merge_set_and_multiset) +{ + boost::unordered_set 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(), 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); +} +#endif + template void merge_empty_test(X*, test::random_generator generator) { test::check_instances check_;