From f540b83ccd04f1c2572ab36d7b778bafd06ad16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sat, 3 Sep 2016 00:03:42 +0200 Subject: [PATCH] * Implemented `merge` operations for associative containers. * Update tree-based containers to changes done in Intrusive internal utilities in order to fix Trac 12432. --- doc/container.qbk | 7 +- include/boost/container/detail/flat_tree.hpp | 39 ++- .../container/detail/node_alloc_holder.hpp | 13 +- include/boost/container/detail/tree.hpp | 29 +- include/boost/container/flat_map.hpp | 90 +++++- include/boost/container/flat_set.hpp | 68 ++++- include/boost/container/map.hpp | 111 ++++++- include/boost/container/set.hpp | 84 +++++- test/flat_set_test.cpp | 2 - test/map_test.cpp | 53 +++- test/map_test.hpp | 282 ++++++++++++------ test/set_test.cpp | 12 +- test/set_test.hpp | 104 ++++++- 13 files changed, 722 insertions(+), 172 deletions(-) diff --git a/doc/container.qbk b/doc/container.qbk index d802f5d..f7ff43f 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1231,10 +1231,11 @@ use [*Boost.Container]? There are several reasons for that: * [@https://svn.boost.org/trac/boost/ticket/12319 Trac #12319: ['"flat_set` should be nothrow move constructible"]]. * Revised noexcept expressions of default and move constructors in all containers. -* Implemented C++17 `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. -* Implemented C++17 `extract`/`insert(node)` for [classref boost::container::map map], [classref boost::container::multimap multimap], +* Implemented C++17's `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. +* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0083r3.pdf ['Splicing Maps and Sets (Revision 5)]] + Splicing Maps and Sets (Revision 5) for [classref boost::container::map map], [classref boost::container::multimap multimap], [classref boost::container::set set], [classref boost::container::multiset multiset]. -* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf P0084R2 Emplace Return Type] +* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf ['P0084R2 Emplace Return Type]] in `deque`, `vector`, `stable_vector`, `small_vector`, `static_vector`, `list` and `slist`. [endsect] diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 69dc191..db73c41 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -46,6 +46,7 @@ #endif #include //pair +#include namespace boost { namespace container { @@ -100,7 +101,7 @@ struct get_flat_tree_iterators typedef boost::container::reverse_iterator const_reverse_iterator; }; -template class flat_tree { @@ -185,7 +186,7 @@ class flat_tree typedef typename vector_t::const_pointer const_pointer; typedef typename vector_t::reference reference; typedef typename vector_t::const_reference const_reference; - typedef Key key_type; + typedef typename KeyOfValue::type key_type; typedef Compare key_compare; typedef typename vector_t::allocator_type allocator_type; typedef typename vector_t::size_type size_type; @@ -778,6 +779,36 @@ class flat_tree return n; } + template + void merge_unique(flat_tree& source) + { + this->insert( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end())); + } + + template + void merge_equal(flat_tree& source) + { + this->insert( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end())); + } + + void merge_unique(flat_tree& source) + { + this->m_data.m_vect.merge_unique + ( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end()) + , static_cast(this->m_data)); + } + + void merge_equal(flat_tree& source) + { + this->m_data.m_vect.merge + ( boost::make_move_iterator(source.begin()) + , boost::make_move_iterator(source.end()) + , static_cast(this->m_data)); + } + BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& k) { return this->priv_lower_bound(this->begin(), this->end(), k); } @@ -1062,9 +1093,9 @@ class flat_tree //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +struct has_trivial_destructor_after_move > { typedef typename ::boost::container::allocator_traits::pointer pointer; static const bool value = ::boost::has_trivial_destructor_after_move::value && diff --git a/include/boost/container/detail/node_alloc_holder.hpp b/include/boost/container/detail/node_alloc_holder.hpp index 1b7c4d7..7ef5d28 100644 --- a/include/boost/container/detail/node_alloc_holder.hpp +++ b/include/boost/container/detail/node_alloc_holder.hpp @@ -394,12 +394,6 @@ struct node_alloc_holder ICont &non_const_icont() const { return const_cast(this->members_.m_icont); } - ICont &icont() - { return this->members_.m_icont; } - - const ICont &icont() const - { return this->members_.m_icont; } - NodeAlloc &node_alloc() { return static_cast(this->members_); } @@ -407,6 +401,13 @@ struct node_alloc_holder { return static_cast(this->members_); } members_holder members_; + + public: + ICont &icont() + { return this->members_.m_icont; } + + const ICont &icont() const + { return this->members_.m_icont; } }; } //namespace container_detail { diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index d8b3a6e..853d0ad 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -295,9 +295,9 @@ struct intrusive_tree_type allocator_traits::size_type size_type; typedef typename container_detail::tree_node < value_type, void_pointer - , tree_type_value, OptimizeSize> node_t; + , tree_type_value, OptimizeSize> node_t; typedef value_to_node_compare - node_compare_type; + node_compare_type; //Deducing the hook type from node_t (e.g. node_t::hook_type) would //provoke an early instantiation of node_t that could ruin recursive //tree definitions, so retype the complete type to avoid any problem. @@ -429,26 +429,28 @@ struct key_node_compare { return this->key_comp()(key_of_value()(nonkey1.get_data()), key_of_value()(nonkey2.get_data())); } }; -template class tree - : protected container_detail::node_alloc_holder + : public container_detail::node_alloc_holder < Allocator , typename container_detail::intrusive_tree_type - < Allocator, tree_value_compare //ValComp + < Allocator, tree_value_compare + ::pointer, Compare, KeyOfValue> , Options::tree_type, Options::optimize_size>::type > { typedef tree_value_compare - ValComp; + < typename allocator_traits::pointer + , Compare, KeyOfValue> ValComp; typedef typename container_detail::intrusive_tree_type < Allocator, ValComp, Options::tree_type , Options::optimize_size>::type Icont; typedef container_detail::node_alloc_holder AllocHolder; typedef typename AllocHolder::NodePtr NodePtr; - typedef tree < Key, T, KeyOfValue + typedef tree < T, KeyOfValue , Compare, Allocator, Options> ThisType; typedef typename AllocHolder::NodeAlloc NodeAlloc; typedef boost::container:: @@ -465,7 +467,7 @@ class tree public: - typedef Key key_type; + typedef typename KeyOfValue::type key_type; typedef T value_type; typedef Allocator allocator_type; typedef Compare key_compare; @@ -1176,6 +1178,13 @@ class tree } } + template + BOOST_CONTAINER_FORCEINLINE void merge_unique(tree& source) + { return this->icont().merge_unique(source.icont()); } + + template + BOOST_CONTAINER_FORCEINLINE void merge_equal(tree& source) + { return this->icont().merge_equal(source.icont()); } BOOST_CONTAINER_FORCEINLINE void clear() { AllocHolder::clear(alloc_version()); } @@ -1265,11 +1274,11 @@ struct has_trivial_destructor_after_move; //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template +template struct has_trivial_destructor_after_move < ::boost::container::container_detail::tree - + > { typedef typename ::boost::container::allocator_traits::pointer pointer; diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 11cbad8..b842101 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -53,6 +53,9 @@ namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +template +class flat_multimap; + namespace container_detail{ template @@ -110,14 +113,14 @@ class flat_map private: BOOST_COPYABLE_AND_MOVABLE(flat_map) //This is the tree that we should store if pair was movable - typedef container_detail::flat_tree, container_detail::select1st, Compare, Allocator> tree_t; //This is the real tree stored here. It's based on a movable pair - typedef container_detail::flat_tree, container_detail::select1st, Compare, @@ -143,6 +146,13 @@ class flat_map ::pointer>::const_reverse_iterator const_reverse_iterator_impl; public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + + impl_tree_t &tree() + { return m_flat_tree; } + + const impl_tree_t &tree() const + { return m_flat_tree; } + private: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1056,6 +1066,39 @@ class flat_map { m_flat_tree.insert_unique(ordered_unique_range, il.begin(), il.end()); } #endif + //! Requires: this->get_allocator() == source.get_allocator(). + //! + //! Effects: Attempts to extract each element in source and insert it into a using + //! the comparison object of *this. If there is an element in a with key equivalent to the + //! key of an element from source, then that element is not extracted from source. + //! + //! Postcondition: Pointers and references to the transferred elements of source refer + //! to those same elements but as members of *this. Iterators referring to the transferred + //! elements will continue to refer to their elements, but they now behave as iterators into *this, + //! not into source. + //! + //! Throws: Nothing unless the comparison object throws. + //! + //! Complexity: N log(a.size() + N) (N has the value source.size()) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) + { m_flat_tree.merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) + { m_flat_tree.merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + //! Effects: Erases the element pointed to by p. //! //! Returns: Returns an iterator pointing to the element immediately @@ -1326,13 +1369,13 @@ class flat_multimap #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(flat_multimap) - typedef container_detail::flat_tree, container_detail::select1st, Compare, Allocator> tree_t; //This is the real tree stored here. It's based on a movable pair - typedef container_detail::flat_tree, container_detail::select1st, Compare, @@ -1358,6 +1401,13 @@ class flat_multimap ::pointer>::const_reverse_iterator const_reverse_iterator_impl; public: typedef typename impl_tree_t::stored_allocator_type impl_stored_allocator_type; + + impl_tree_t &tree() + { return m_flat_tree; } + + const impl_tree_t &tree() const + { return m_flat_tree; } + private: #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1993,6 +2043,38 @@ class flat_multimap { m_flat_tree.insert_equal(ordered_range, il.begin(), il.end()); } #endif + //! Requires: this->get_allocator() == source.get_allocator(). + //! + //! Effects: Extracts each element in source and insert it into a using + //! the comparison object of *this. + //! + //! Postcondition: Pointers and references to the transferred elements of source refer + //! to those same elements but as members of *this. Iterators referring to the transferred + //! elements will continue to refer to their elements, but they now behave as iterators into *this, + //! not into source. + //! + //! Throws: Nothing unless the comparison object throws. + //! + //! Complexity: N log(a.size() + N) (N has the value source.size()) + template + void merge(flat_multimap& source) + { m_flat_tree.merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + template + void merge(BOOST_RV_REF_BEG flat_multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + template + void merge(flat_map& source) + { m_flat_tree.merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + template + void merge(BOOST_RV_REF_BEG flat_map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + //! Effects: Erases the element pointed to by p. //! //! Returns: Returns an iterator pointing to the element immediately diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index b0c473a..fa27006 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -47,6 +47,11 @@ namespace boost { namespace container { +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) +template +class flat_multimap; +#endif + //! flat_set is a Sorted Associative Container that stores objects of type Key. //! It is also a Unique Associative Container, meaning that no two elements are the same. //! @@ -69,13 +74,21 @@ template #endif class flat_set ///@cond - : public container_detail::flat_tree, Compare, Allocator> + : public container_detail::flat_tree, Compare, Allocator> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(flat_set) - typedef container_detail::flat_tree, Compare, Allocator> base_t; + typedef container_detail::flat_tree, Compare, Allocator> base_t; + + public: + base_t &tree() + { return *this; } + + const base_t &tree() const + { return *this; } + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -605,6 +618,26 @@ class flat_set { this->base_t::insert_unique(ordered_unique_range, il.begin(), il.end()); } #endif + //! @copydoc ::boost::container::flat_map::merge(flat_map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) + { this->base_t::merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_set&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::flat_map::merge(flat_multimap&) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) + { this->base_t::merge_unique(source.tree()); } + + //! @copydoc ::boost::container::flat_map::merge(flat_multiset&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Erases the element pointed to by p. @@ -867,13 +900,20 @@ template #endif class flat_multiset ///@cond - : public container_detail::flat_tree, Compare, Allocator> + : public container_detail::flat_tree, Compare, Allocator> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(flat_multiset) - typedef container_detail::flat_tree, Compare, Allocator> base_t; + typedef container_detail::flat_tree, Compare, Allocator> base_t; + + public: + base_t &tree() + { return *this; } + + const base_t &tree() const + { return *this; } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -1233,6 +1273,26 @@ class flat_multiset { this->base_t::insert_equal(ordered_range, il.begin(), il.end()); } #endif + //! @copydoc ::boost::container::flat_multimap::merge(flat_multimap&) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_multiset& source) + { this->base_t::merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multiset::merge(flat_multiset&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::flat_multimap::merge(flat_map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(flat_set& source) + { this->base_t::merge_equal(source.tree()); } + + //! @copydoc ::boost::container::flat_multiset::merge(flat_set&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG flat_set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::flat_set::erase(const_iterator) diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 76dad08..5520fb4 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -96,18 +96,18 @@ struct pair_key_mapped_of_value //! \tparam Compare is the ordering function for Keys (e.g. std::less). //! \tparam Allocator is the allocator to allocate the value_types //! (e.g. allocator< std::pair > ). -//! \tparam MapOptions is an packed option type generated using using boost::container::tree_assoc_options. +//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options. template < class Key, class T, class Compare = std::less - , class Allocator = new_allocator< std::pair< const Key, T> >, class MapOptions = tree_assoc_defaults > + , class Allocator = new_allocator< std::pair< const Key, T> >, class Options = tree_assoc_defaults > #else -template +template #endif class map ///@cond : public container_detail::tree - < Key, std::pair + < std::pair , container_detail::select1st - , Compare, Allocator, MapOptions> + , Compare, Allocator, Options> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -117,10 +117,9 @@ class map typedef container_detail::select1st select_1st_t; typedef std::pair value_type_impl; typedef container_detail::tree - base_t; + base_t; typedef container_detail::pair movable_value_type_impl; - typedef container_detail::tree_value_compare - value_compare_impl; + typedef typename base_t::value_compare value_compare_impl; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -975,6 +974,47 @@ class map return BOOST_MOVE_RET(node_type, nh); } + //! Requires: this->get_allocator() == source.get_allocator(). + //! + //! Effects: Attempts to extract each element in source and insert it into a using + //! the comparison object of *this. If there is an element in a with key equivalent to the + //! key of an element from source, then that element is not extracted from source. + //! + //! Postcondition: Pointers and references to the transferred elements of source refer + //! to those same elements but as members of *this. Iterators referring to the transferred + //! elements will continue to refer to their elements, but they now behave as iterators into *this, + //! not into source. + //! + //! Throws: Nothing unless the comparison object throws. + //! + //! Complexity: N log(a.size() + N) (N has the value source.size()) + template + BOOST_CONTAINER_FORCEINLINE void merge(map& source) + { + typedef container_detail::tree + base2_t; + this->merge_unique(static_cast(source)); + } + + //! @copydoc ::boost::container::map::merge(map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::map::merge(map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(multimap& source) + { + typedef container_detail::tree + base2_t; + this->base_t::merge_unique(static_cast(source)); + } + + //! @copydoc ::boost::container::map::merge(map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Swaps the contents of *this and x. //! @@ -1148,18 +1188,18 @@ namespace container { //! \tparam Compare is the ordering function for Keys (e.g. std::less). //! \tparam Allocator is the allocator to allocate the value_types //! (e.g. allocator< std::pair > ). -//! \tparam MultiMapOptions is an packed option type generated using using boost::container::tree_assoc_options. +//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options. template < class Key, class T, class Compare = std::less - , class Allocator = new_allocator< std::pair< const Key, T> >, class MultiMapOptions = tree_assoc_defaults> + , class Allocator = new_allocator< std::pair< const Key, T> >, class Options = tree_assoc_defaults> #else -template +template #endif class multimap ///@cond : public container_detail::tree - < Key, std::pair + < std::pair , container_detail::select1st - , Compare, Allocator, MultiMapOptions> + , Compare, Allocator, Options> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED @@ -1169,10 +1209,9 @@ class multimap typedef container_detail::select1st select_1st_t; typedef std::pair value_type_impl; typedef container_detail::tree - base_t; + base_t; typedef container_detail::pair movable_value_type_impl; - typedef container_detail::tree_value_compare - value_compare_impl; + typedef typename base_t::value_compare value_compare_impl; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED typedef ::boost::container::allocator_traits allocator_traits_type; @@ -1655,6 +1694,46 @@ class multimap return node_type (boost::move(base_nh)); } + //! Requires: this->get_allocator() == source.get_allocator(). + //! + //! Effects: Extracts each element in source and insert it into a using + //! the comparison object of *this. + //! + //! Postcondition: Pointers and references to the transferred elements of source refer + //! to those same elements but as members of *this. Iterators referring to the transferred + //! elements will continue to refer to their elements, but they now behave as iterators into *this, + //! not into source. + //! + //! Throws: Nothing unless the comparison object throws. + //! + //! Complexity: N log(a.size() + N) (N has the value source.size()) + template + void merge(multimap& source) + { + typedef container_detail::tree + base2_t; + this->base_t::merge_equal(static_cast(source)); + } + + //! @copydoc ::boost::container::multimap::merge(multimap&) + template + void merge(BOOST_RV_REF_BEG multimap BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::multimap::merge(multimap&) + template + void merge(map& source) + { + typedef container_detail::tree + base2_t; + this->base_t::merge_equal(static_cast(source)); + } + + //! @copydoc ::boost::container::multimap::merge(multimap&) + template + void merge(BOOST_RV_REF_BEG map BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::set::swap void swap(multiset& x) diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 3f0dbe6..5cf0f96 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -59,22 +59,22 @@ namespace container { //! \tparam Key is the type to be inserted in the set, which is also the key_type //! \tparam Compare is the comparison functor used to order keys //! \tparam Allocator is the allocator to be used to allocate memory for this container -//! \tparam SetOptions is an packed option type generated using using boost::container::tree_assoc_options. -template , class Allocator = new_allocator, class SetOptions = tree_assoc_defaults > +//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options. +template , class Allocator = new_allocator, class Options = tree_assoc_defaults > #else -template +template #endif class set ///@cond : public container_detail::tree - < Key, Key, container_detail::identity, Compare, Allocator, SetOptions> + < Key, container_detail::identity, Compare, Allocator, Options> ///@endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(set) typedef container_detail::tree - < Key, Key, container_detail::identity, Compare, Allocator, SetOptions> base_t; + < Key, container_detail::identity, Compare, Allocator, Options> base_t; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -533,6 +533,34 @@ class set insert_return_type insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) { return this->base_t::insert_unique_node(hint, boost::move(nh)); } + //! @copydoc ::boost::container::map::merge(map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(set& source) + { + typedef container_detail::tree + , C2, Allocator, Options> base2_t; + this->base_t::merge_unique(static_cast(source)); + } + + //! @copydoc ::boost::container::set::merge(set&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::map::merge(multimap&) + template + BOOST_CONTAINER_FORCEINLINE void merge(multiset& source) + { + typedef container_detail::tree + , C2, Allocator, Options> base2_t; + this->base_t::merge_unique(static_cast(source)); + } + + //! @copydoc ::boost::container::set::merge(multiset&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Erases the element pointed to by p. @@ -724,8 +752,8 @@ class set //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { typedef typename ::boost::container::allocator_traits::pointer pointer; static const bool value = ::boost::has_trivial_destructor_after_move::value && @@ -750,22 +778,22 @@ namespace container { //! \tparam Key is the type to be inserted in the set, which is also the key_type //! \tparam Compare is the comparison functor used to order keys //! \tparam Allocator is the allocator to be used to allocate memory for this container -//! \tparam MultiSetOptions is an packed option type generated using using boost::container::tree_assoc_options. -template , class Allocator = new_allocator, class MultiSetOptions = tree_assoc_defaults > +//! \tparam Options is an packed option type generated using using boost::container::tree_assoc_options. +template , class Allocator = new_allocator, class Options = tree_assoc_defaults > #else -template +template #endif class multiset /// @cond : public container_detail::tree - , Compare, Allocator, MultiSetOptions> + , Compare, Allocator, Options> /// @endcond { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED private: BOOST_COPYABLE_AND_MOVABLE(multiset) typedef container_detail::tree - , Compare, Allocator, MultiSetOptions> base_t; + , Compare, Allocator, Options> base_t; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -1068,6 +1096,34 @@ class multiset iterator insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) { return this->base_t::insert_equal_node(hint, boost::move(nh)); } + //! @copydoc ::boost::container::multimap::merge(multimap&) + template + BOOST_CONTAINER_FORCEINLINE void merge(multiset& source) + { + typedef container_detail::tree + , C2, Allocator, Options> base2_t; + this->base_t::merge_equal(static_cast(source)); + } + + //! @copydoc ::boost::container::multiset::merge(multiset&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG multiset BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + + //! @copydoc ::boost::container::multimap::merge(map&) + template + BOOST_CONTAINER_FORCEINLINE void merge(set& source) + { + typedef container_detail::tree + , C2, Allocator, Options> base2_t; + this->base_t::merge_equal(static_cast(source)); + } + + //! @copydoc ::boost::container::multiset::merge(set&) + template + BOOST_CONTAINER_FORCEINLINE void merge(BOOST_RV_REF_BEG set BOOST_RV_REF_END source) + { return this->merge(static_cast&>(source)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::set::erase(const_iterator) @@ -1179,8 +1235,8 @@ class multiset //!has_trivial_destructor_after_move<> == true_type //!specialization for optimizations -template -struct has_trivial_destructor_after_move > +template +struct has_trivial_destructor_after_move > { typedef typename ::boost::container::allocator_traits::pointer pointer; static const bool value = ::boost::has_trivial_destructor_after_move::value && diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index 67b5dfb..b9e436f 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -62,7 +62,6 @@ namespace container_detail { //Instantiate base class as previous instantiations don't instantiate inherited members template class flat_tree < test::movable_and_copyable_int - , test::movable_and_copyable_int , identity , std::less , test::simple_allocator @@ -70,7 +69,6 @@ template class flat_tree template class flat_tree < test::movable_and_copyable_int - , test::movable_and_copyable_int , identity , std::less , allocator diff --git a/test/map_test.cpp b/test/map_test.cpp index e608abb..ae7abf0 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -23,6 +23,8 @@ using namespace boost::container; +typedef std::pair pair_t; + namespace boost { namespace container { @@ -33,34 +35,59 @@ template class map < test::movable_and_copyable_int , test::movable_and_copyable_int , std::less - , test::simple_allocator - < std::pair > + , test::simple_allocator< pair_t > >; template class map < test::movable_and_copyable_int , test::movable_and_copyable_int , std::less - , std::allocator - < std::pair > + , std::allocator< pair_t > >; template class map < test::movable_and_copyable_int , test::movable_and_copyable_int , std::less - , adaptive_pool - < std::pair > + , adaptive_pool< pair_t > >; template class multimap < test::movable_and_copyable_int , test::movable_and_copyable_int , std::less - , std::allocator - < std::pair > + , std::allocator< pair_t > >; +namespace container_detail { + +//Instantiate base class as previous instantiations don't instantiate inherited members +template class tree + < pair_t + , select1st + , std::less + , test::simple_allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , std::allocator + , tree_assoc_defaults + >; + +template class tree + < pair_t + , select1st + , std::less + , adaptive_pool + , tree_assoc_defaults + >; + +} //container_detail { + }} //boost::container class recursive_map @@ -334,6 +361,13 @@ struct alloc_propagate_base }; }; +void test_merge_from_different_comparison() +{ + map map1; + map > map2; + map1.merge(map2); +} + }}} //namespace boost::container::test int main () @@ -357,7 +391,6 @@ int main () //Test std::pair value type as tree has workarounds to make old std::pair //implementations movable that can break things { - typedef std::pair pair_t; boost::container::map s; std::pair p; s.insert(p); @@ -447,6 +480,8 @@ int main () if(!node_type_test()) return 1; + test::test_merge_from_different_comparison(); + //////////////////////////////////// // Test optimize_size option //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index 7e40360..9731943 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -68,7 +68,7 @@ int map_test_copyable(boost::container::container_detail::true_type) typedef container_detail::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; - const int max = 50; + const int MaxElem = 50; ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique(); @@ -86,7 +86,7 @@ int map_test_copyable(boost::container::container_detail::true_type) boostmultimap.insert(boostmultimap.begin(), boostmultimap.end()); int i; - for(i = 0; i < max; ++i){ + for(i = 0; i < MaxElem; ++i){ { IntType i1(i), i2(i); IntPairType intpair1(boost::move(i1), boost::move(i2)); @@ -138,7 +138,7 @@ int map_test() typedef typename MyBoostMap::key_type IntType; typedef container_detail::pair IntPairType; typedef typename MyStdMap::value_type StdPairType; - const int max = 50; + const int MaxElem = 50; typedef typename MyStdMap::value_type StdValueType; typedef typename MyStdMap::key_type StdKeyType; typedef typename MyStdMap::mapped_type StdMappedType; @@ -146,20 +146,20 @@ int map_test() //Test construction from a range { - IntPairType aux_vect[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - StdValueType aux_vect2[50]; - for(int i = 0; i < 50; ++i){ + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); } - IntPairType aux_vect3[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); @@ -167,33 +167,33 @@ int map_test() ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[0] + 50), typename MyBoostMap::key_compare()); + , boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::key_compare()); ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare()); + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1; ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect3[0]) - , boost::make_move_iterator(&aux_vect3[0] + 50), typename MyBoostMap::key_compare()); + , boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::key_compare()); ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare()); + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1; } { - IntPairType aux_vect[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - StdValueType aux_vect2[50]; - for(int i = 0; i < 50; ++i){ + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); } - IntPairType aux_vect3[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); @@ -201,16 +201,16 @@ int map_test() ::boost::movelib::unique_ptr const pboostmap = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[0] + 50), typename MyBoostMap::allocator_type()); + , boost::make_move_iterator(&aux_vect[0] + MaxElem), typename MyBoostMap::allocator_type()); ::boost::movelib::unique_ptr const pstdmap = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare()); + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); if(!CheckEqualContainers(*pboostmap, *pstdmap)) return 1; ::boost::movelib::unique_ptr const pboostmultimap = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect3[0]) - , boost::make_move_iterator(&aux_vect3[0] + 50), typename MyBoostMap::allocator_type()); + , boost::make_move_iterator(&aux_vect3[0] + MaxElem), typename MyBoostMap::allocator_type()); ::boost::movelib::unique_ptr const pstdmultimap = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50, typename MyStdMap::key_compare()); + (&aux_vect2[0], &aux_vect2[0] + MaxElem, typename MyStdMap::key_compare()); if(!CheckEqualContainers(*pboostmultimap, *pstdmultimap)) return 1; } @@ -225,8 +225,8 @@ int map_test() { //This is really nasty, but we have no other simple choice - IntPairType aux_vect[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); @@ -235,13 +235,13 @@ int map_test() typedef typename MyStdMap::value_type StdValueType; typedef typename MyStdMap::key_type StdKeyType; typedef typename MyStdMap::mapped_type StdMappedType; - StdValueType aux_vect2[50]; - for(int i = 0; i < 50; ++i){ + StdValueType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ new(&aux_vect2[i])StdValueType(StdKeyType(i/2), StdMappedType(i/2)); } - IntPairType aux_vect3[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i/2); IntType i2(i/2); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); @@ -249,14 +249,14 @@ int map_test() ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[0] + 50)); + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); ::boost::movelib::unique_ptr const pstdmap2 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50); + (&aux_vect2[0], &aux_vect2[0] + MaxElem); ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect3[0]) - , boost::make_move_iterator(&aux_vect3[0] + 50)); + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); ::boost::movelib::unique_ptr const pstdmultimap2 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50); + (&aux_vect2[0], &aux_vect2[0] + MaxElem); MyBoostMap &boostmap2 = *pboostmap2; MyStdMap &stdmap2 = *pstdmap2; MyBoostMultiMap &boostmultimap2 = *pboostmultimap2; @@ -267,17 +267,17 @@ int map_test() //ordered range insertion //This is really nasty, but we have no other simple choice - for(int i = 0; i < 50; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - for(int i = 0; i < 50; ++i){ + for(int i = 0; i < MaxElem; ++i){ new(&aux_vect2[i])StdValueType(StdKeyType(i), StdMappedType(i)); } - for(int i = 0; i < 50; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); @@ -301,14 +301,14 @@ int map_test() ::boost::movelib::unique_ptr const pboostmap3 = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect[0]) - , boost::make_move_iterator(&aux_vect[0] + 50)); + , boost::make_move_iterator(&aux_vect[0] + MaxElem)); ::boost::movelib::unique_ptr const pstdmap3 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50); + (&aux_vect2[0], &aux_vect2[0] + MaxElem); ::boost::movelib::unique_ptr const pboostmultimap3 = ::boost::movelib::make_unique ( boost::make_move_iterator(&aux_vect3[0]) - , boost::make_move_iterator(&aux_vect3[0] + 50)); + , boost::make_move_iterator(&aux_vect3[0] + MaxElem)); ::boost::movelib::unique_ptr const pstdmultimap3 = ::boost::movelib::make_unique - (&aux_vect2[0], &aux_vect2[0] + 50); + (&aux_vect2[0], &aux_vect2[0] + MaxElem); MyBoostMap &boostmap3 = *pboostmap3; MyStdMap &stdmap3 = *pstdmap3; MyBoostMultiMap &boostmultimap3 = *pboostmultimap3; @@ -344,20 +344,20 @@ int map_test() } { //This is really nasty, but we have no other simple choice - IntPairType aux_vect[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect3[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ boostmap.insert(boost::move(aux_vect[i])); stdmap.insert(StdPairType(i, i)); boostmultimap.insert(boost::move(aux_vect3[i])); @@ -405,22 +405,22 @@ int map_test() //Initialize values { //This is really nasty, but we have no other simple choice - IntPairType aux_vect[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect3[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); } - boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); - boostmultimap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50)); - for(std::size_t i = 0; i != 50; ++i){ + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + for(int i = 0; i != MaxElem; ++i){ StdPairType stdpairtype(-1, -1); stdmap.insert(stdpairtype); stdmultimap.insert(stdpairtype); @@ -439,40 +439,40 @@ int map_test() if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } { - IntPairType aux_vect[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect3[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect4[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect4[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect4[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect5[50]; - for(int i = 0; i < 50; ++i){ + IntPairType aux_vect5[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(-1); IntType i2(-1); new(&aux_vect5[i])IntPairType(boost::move(i1), boost::move(i2)); } - boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + 50)); - boostmap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + 50)); - boostmultimap.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(aux_vect4 + 50)); - boostmultimap.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(aux_vect5 + 50)); + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmap.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect4[0]), boost::make_move_iterator(aux_vect4 + MaxElem)); + boostmultimap.insert(boost::make_move_iterator(&aux_vect5[0]), boost::make_move_iterator(aux_vect5 + MaxElem)); - for(std::size_t i = 0; i != 50; ++i){ + for(int i = 0; i != MaxElem; ++i){ StdPairType stdpairtype(-1, -1); stdmap.insert(stdpairtype); stdmultimap.insert(stdpairtype); @@ -492,20 +492,20 @@ int map_test() { //This is really nasty, but we have no other simple choice - IntPairType aux_vect[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect3[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ boostmap.insert(boost::move(aux_vect[i])); stdmap.insert(StdPairType(i, i)); boostmultimap.insert(boost::move(aux_vect3[i])); @@ -515,7 +515,7 @@ int map_test() if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntPairType intpair; { IntType i1(i); @@ -629,7 +629,7 @@ int map_test() } //Compare count with std containers - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType k(i); if(boostmap.count(k) != stdmap.count(i)){ return -1; @@ -673,14 +673,14 @@ int map_test() stdmap.clear(); stdmultimap.clear(); - IntPairType aux_vect[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ boostmap[boost::move(aux_vect[i].first)] = boost::move(aux_vect[i].second); stdmap[i] = i; } @@ -695,21 +695,21 @@ int map_test() stdmap.clear(); stdmultimap.clear(); - IntPairType aux_vect[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect2[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); - IntType i2(max-i); + IntType i2(MaxElem-i); new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ boostmap.insert_or_assign(boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); stdmap[i] = i; } @@ -717,9 +717,9 @@ int map_test() if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ boostmap.insert_or_assign(boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); - stdmap[i] = max-i; + stdmap[i] = MaxElem-i; } if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; @@ -732,22 +732,22 @@ int map_test() stdmap.clear(); stdmultimap.clear(); - IntPairType aux_vect[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); IntType i2(i); new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); } - IntPairType aux_vect2[max]; - for(int i = 0; i < max; ++i){ + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ IntType i1(i); - IntType i2(max-i); + IntType i2(MaxElem-i); new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); } typedef typename MyBoostMap::iterator iterator; - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ iterator it; if(i&1){ std::pair ret = @@ -769,7 +769,7 @@ int map_test() if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ iterator it; iterator itex = boostmap.find(aux_vect2[i].first); if(itex == boostmap.end()) @@ -795,6 +795,108 @@ int map_test() if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } + { //merge + ::boost::movelib::unique_ptr const pboostmap2 = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultimap2 = ::boost::movelib::make_unique(); + + MyBoostMap &boostmap2 = *pboostmap2; + MyBoostMultiMap &boostmultimap2 = *pboostmultimap2; + + boostmap.clear(); + boostmap2.clear(); + boostmultimap.clear(); + boostmultimap2.clear(); + stdmap.clear(); + stdmultimap.clear(); + + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem/2+i); + IntType i2(MaxElem-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem*2/2+i); + IntType i2(MaxElem*2+i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + boostmap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmultimap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(i, i)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(MaxElem/2+i, MaxElem-i)); + } + + boostmap.merge(boost::move(boostmap2)); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i)); + } + + boostmap.merge(boost::move(boostmultimap2)); + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + + boostmap.clear(); + boostmap2.clear(); + boostmultimap.clear(); + boostmultimap2.clear(); + stdmap.clear(); + stdmultimap.clear(); + { + IntPairType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(i); + IntType i2(i); + new(&aux_vect[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + IntPairType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem/2+i); + IntType i2(MaxElem-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + IntPairType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + IntType i1(MaxElem*2/2+i); + IntType i2(MaxElem*2+i); + new(&aux_vect3[i])IntPairType(boost::move(i1), boost::move(i2)); + } + boostmultimap.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultimap2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmap2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(i, i)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(MaxElem/2+i, MaxElem-i)); + } + boostmultimap.merge(boost::move(boostmultimap2)); + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmultimap.insert(StdPairType(MaxElem*2/2+i, MaxElem*2+i)); + } + + boostmultimap.merge(boost::move(boostmap2)); + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + if(map_test_copyable (container_detail::bool_::value>())){ return 1; diff --git a/test/set_test.cpp b/test/set_test.cpp index bc9f2cd..5caaa29 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -58,7 +58,6 @@ namespace container_detail { //Instantiate base class as previous instantiations don't instantiate inherited members template class tree < test::movable_and_copyable_int - , test::movable_and_copyable_int , identity , std::less , test::simple_allocator @@ -67,7 +66,6 @@ template class tree template class tree < test::movable_and_copyable_int - , test::movable_and_copyable_int , identity , std::less , std::allocator @@ -76,7 +74,6 @@ template class tree template class tree < test::movable_and_copyable_int - , test::movable_and_copyable_int , identity , std::less , adaptive_pool @@ -354,6 +351,13 @@ int test_set_variants() return 0; } +void test_merge_from_different_comparison() +{ + set set1; + set > set2; + set1.merge(set2); +} + int main () { @@ -381,6 +385,8 @@ int main () s.emplace(p); } + test_merge_from_different_comparison(); + //////////////////////////////////// // Testing allocator implementations //////////////////////////////////// diff --git a/test/set_test.hpp b/test/set_test.hpp index 0b1be22..d123eb1 100644 --- a/test/set_test.hpp +++ b/test/set_test.hpp @@ -46,6 +46,8 @@ template const pboostset = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdset = ::boost::movelib::make_unique(); @@ -71,7 +72,7 @@ int set_test_copyable(boost::container::container_detail::true_type) boostset.insert(boostset.begin(), boostset.end()); boostmultiset.insert(boostmultiset.begin(), boostmultiset.end()); - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType move_me(i); boostset.insert(boost::move(move_me)); stdset.insert(i); @@ -134,7 +135,6 @@ template const pboostset = ::boost::movelib::make_unique(); ::boost::movelib::unique_ptr const pstdset = ::boost::movelib::make_unique(); @@ -293,7 +293,7 @@ int set_test () } } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType move_me(i); boostset.insert(boost::move(move_me)); stdset.insert(i); @@ -474,7 +474,7 @@ int set_test () } } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType move_me(i); boostset.insert(boost::move(move_me)); stdset.insert(i); @@ -492,7 +492,7 @@ int set_test () return 1; } - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ { IntType move_me(i); boostset.insert(boostset.begin(), boost::move(move_me)); @@ -579,7 +579,7 @@ int set_test () } //Compare count with std containers - for(int i = 0; i < max; ++i){ + for(int i = 0; i < MaxElem; ++i){ IntType count_me(i); if(boostset.count(count_me) != stdset.count(i)){ return -1; @@ -703,6 +703,96 @@ int set_test () } } + { //merge + ::boost::movelib::unique_ptr const pboostset2 = ::boost::movelib::make_unique(); + ::boost::movelib::unique_ptr const pboostmultiset2 = ::boost::movelib::make_unique(); + + MyBoostSet &boostset2 = *pboostset2; + MyBoostMultiSet &boostmultiset2 = *pboostmultiset2; + + boostset.clear(); + boostset2.clear(); + boostmultiset.clear(); + boostmultiset2.clear(); + stdset.clear(); + stdmultiset.clear(); + + { + IntType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect[i] = i; + } + + IntType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect2[i] = MaxElem/2+i; + } + IntType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect3[i] = MaxElem*2/2+i; + } + boostset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostmultiset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(i); + } + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(MaxElem/2+i); + } + + boostset.merge(boost::move(boostset2)); + if(!CheckEqualContainers(boostset, stdset)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdset.insert(MaxElem*2/2+i); + } + + boostset.merge(boost::move(boostmultiset2)); + if(!CheckEqualContainers(boostset, stdset)) return 1; + + boostset.clear(); + boostset2.clear(); + boostmultiset.clear(); + boostmultiset2.clear(); + stdset.clear(); + stdmultiset.clear(); + { + IntType aux_vect[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect[i] = i; + } + + IntType aux_vect2[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect2[i] = MaxElem/2+i; + } + IntType aux_vect3[MaxElem]; + for(int i = 0; i < MaxElem; ++i){ + aux_vect3[i] = MaxElem*2/2+i; + } + boostmultiset.insert(boost::make_move_iterator(&aux_vect[0]), boost::make_move_iterator(&aux_vect[0] + MaxElem)); + boostmultiset2.insert(boost::make_move_iterator(&aux_vect2[0]), boost::make_move_iterator(&aux_vect2[0] + MaxElem)); + boostset2.insert(boost::make_move_iterator(&aux_vect3[0]), boost::make_move_iterator(&aux_vect3[0] + MaxElem)); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(i); + } + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(MaxElem/2+i); + } + boostmultiset.merge(boost::move(boostmultiset2)); + if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1; + + for(int i = 0; i < MaxElem; ++i){ + stdmultiset.insert(MaxElem*2/2+i); + } + + boostmultiset.merge(boost::move(boostset2)); + if(!CheckEqualContainers(boostmultiset, stdmultiset)) return 1; + } + if(set_test_copyable (container_detail::bool_::value>())){ return 1;