diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index cae1dc5..56b7c1e 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -36,6 +36,8 @@ doxygen autodoc \"BOOST_RV_REF(T)=T&&\" \\ \"BOOST_RV_REF_BEG=\" \\ \"BOOST_RV_REF_END=&&\" \\ + \"BOOST_RV_REF_BEG_IF_CXX11=\" \\ + \"BOOST_RV_REF_END_IF_CXX11=&&\" \\ \"BOOST_COPY_ASSIGN_REF(T)=const T &\" \\ \"BOOST_FWD_REF(a)=a &&\" \\ \"BOOST_INTRUSIVE_OPTION_CONSTANT(OPTION_NAME, TYPE, VALUE, CONSTANT_NAME) = template struct OPTION_NAME{};\" \\ diff --git a/doc/container.qbk b/doc/container.qbk index ca86d2e..1cf3f89 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1231,7 +1231,9 @@ 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` and `try_emplace`for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. +* 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], + [classref boost::container::set set], [classref boost::container::multiset multiset]. [endsect] diff --git a/include/boost/container/detail/mpl.hpp b/include/boost/container/detail/mpl.hpp index e1684ea..82fcc70 100644 --- a/include/boost/container/detail/mpl.hpp +++ b/include/boost/container/detail/mpl.hpp @@ -62,19 +62,18 @@ using boost::move_detail::disable_if_and; using boost::move_detail::enable_if_or; using boost::move_detail::disable_if_or; - -template +template struct select1st { - typedef Pair argument_type; - typedef typename Pair::first_type result_type; + typedef FirstType type; - template - const typename Pair::first_type& operator()(const OtherPair& x) const + template + const type& operator()(const T& x) const { return x.first; } - const typename Pair::first_type& operator()(const typename Pair::first_type& x) const - { return x; } + template + type& operator()(T& x) + { return const_cast(x.first); } }; } //namespace container_detail { diff --git a/include/boost/container/detail/pair.hpp b/include/boost/container/detail/pair.hpp index 032e65b..096f795 100644 --- a/include/boost/container/detail/pair.hpp +++ b/include/boost/container/detail/pair.hpp @@ -201,7 +201,7 @@ struct pair #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template< class KeyType, class ...Args> - pair(const try_emplace_t &, BOOST_FWD_REF(KeyType) k, Args && ...args) + pair(try_emplace_t, BOOST_FWD_REF(KeyType) k, Args && ...args) : first(boost::forward(k)), second(::boost::forward(args)...)\ {} #else diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 65e64dd..399860d 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -25,6 +25,7 @@ #include #include #include +#include // container/detail #include //algo_equal(), algo_lexicographical_compare @@ -135,7 +136,7 @@ struct tree_node typedef typename tree_internal_data_type::type internal_type; typedef tree_node< T, VoidPointer - , tree_type_value, OptimizeSize> node_type; + , tree_type_value, OptimizeSize> node_t; BOOST_CONTAINER_FORCEINLINE T &get_data() { @@ -294,18 +295,18 @@ 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_type; + , tree_type_value, OptimizeSize> node_t; typedef value_to_node_compare - node_compare_type; - //Deducing the hook type from node_type (e.g. node_type::hook_type) would - //provoke an early instantiation of node_type that could ruin recursive + 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. typedef typename intrusive_tree_hook ::type hook_type; public: typedef typename intrusive_tree_dispatch - < node_type, node_compare_type + < node_t, node_compare_type , size_type, hook_type , tree_type_value>::type type; }; @@ -351,7 +352,7 @@ template class RecyclingCloner { typedef typename AllocHolder::intrusive_container intrusive_container; - typedef typename AllocHolder::Node node_type; + typedef typename AllocHolder::Node node_t; typedef typename AllocHolder::NodePtr node_ptr_type; public: @@ -359,13 +360,13 @@ class RecyclingCloner : m_holder(holder), m_icont(itree) {} - BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_type &other, bool_) - { p->do_move_assign(const_cast(other).m_data); } + BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_t &other, bool_) + { p->do_move_assign(const_cast(other).m_data); } - BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_type &other, bool_) + BOOST_CONTAINER_FORCEINLINE static void do_assign(node_ptr_type &p, const node_t &other, bool_) { p->do_assign(other.m_data); } - node_ptr_type operator()(const node_type &other) const + node_ptr_type operator()(const node_t &other) const { if(node_ptr_type p = m_icont.unlink_leftmost_without_rebalance()){ //First recycle a node (this can't throw) @@ -479,11 +480,19 @@ class tree allocator_traits::size_type size_type; typedef typename boost::container:: allocator_traits::difference_type difference_type; - typedef difference_type tree_difference_type; - typedef pointer tree_pointer; - typedef const_pointer tree_const_pointer; - typedef reference tree_reference; - typedef const_reference tree_const_reference; + typedef container_detail::iterator_from_iiterator + iterator; + typedef container_detail::iterator_from_iiterator + const_iterator; + typedef boost::container::reverse_iterator + reverse_iterator; + typedef boost::container::reverse_iterator + const_reverse_iterator; + typedef node_handle + < Node, value_type, allocator_type, void> node_type; + typedef insert_return_type_base + insert_return_type; + typedef NodeAlloc stored_allocator_type; private: @@ -491,10 +500,6 @@ class tree typedef key_node_compare KeyNodeCompare; public: - typedef container_detail::iterator_from_iiterator iterator; - typedef container_detail::iterator_from_iiterator const_iterator; - typedef boost::container::reverse_iterator reverse_iterator; - typedef boost::container::reverse_iterator const_reverse_iterator; BOOST_CONTAINER_FORCEINLINE tree() : AllocHolder() @@ -823,15 +828,6 @@ class tree return std::pair(iterator(ret.first), ret.second); } - iterator insert_unique_commit(const value_type& v, insert_commit_data &data) - { - NodePtr tmp = AllocHolder::create_node(v); - scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); - iterator ret(this->icont().insert_unique_commit(*tmp, data)); - destroy_deallocator.release(); - return ret; - } - template iterator insert_unique_commit (BOOST_FWD_REF(MovableConvertible) v, insert_commit_data &data) @@ -843,17 +839,6 @@ class tree return ret; } - std::pair insert_unique(const value_type& v) - { - insert_commit_data data; - std::pair ret = - this->insert_unique_check(KeyOfValue()(v), data); - if(ret.second){ - ret.first = this->insert_unique_commit(v, data); - } - return ret; - } - template std::pair insert_unique(BOOST_FWD_REF(MovableConvertible) v) { @@ -868,17 +853,6 @@ class tree private: - template - iterator priv_insert_unique_key_commit - (BOOST_FWD_REF(KeyConvertible) key, insert_commit_data &data) - { - NodePtr tmp = AllocHolder::create_node_from_key(boost::forward(key)); - scoped_destroy_deallocator destroy_deallocator(tmp, this->node_alloc()); - iterator ret(this->icont().insert_unique_commit(*tmp, data)); - destroy_deallocator.release(); - return ret; - } - template iiterator priv_insert_or_assign_commit (BOOST_FWD_REF(KeyConvertible) key, BOOST_FWD_REF(M) obj, insert_commit_data &data) @@ -1100,18 +1074,6 @@ class tree this->insert_equal(*first); } - template - iterator insert_from_key(BOOST_FWD_REF(KeyConvertible) key) - { - insert_commit_data data; - const key_type & k = key; //Support emulated rvalue references - std::pair ret = - this->icont().insert_unique_check(k, KeyNodeCompare(value_comp()), data); - return ret.second - ? this->priv_insert_unique_key_commit(boost::forward(key), data) - : iterator(ret.first); - } - template std::pair insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj) { @@ -1145,6 +1107,73 @@ class tree return iterator(AllocHolder::erase_range(first.get(), last.get(), alloc_version())); } + node_type extract(const key_type& k) + { + iterator const it = this->find(k); + if(this->end() != it){ + return this->extract(it); + } + return node_type(); + } + + node_type extract(const_iterator position) + { + BOOST_ASSERT(position != this->cend() && (priv_is_linked)(position)); + iiterator const iit(position.get()); + this->icont().erase(iit); + return node_type(iit.operator->(), this->node_alloc()); + } + + insert_return_type insert_unique_node(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + return this->insert_unique_node(this->end(), boost::move(nh)); + } + + insert_return_type insert_unique_node(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + insert_return_type irt; //inserted == false, node.empty() + if(!nh.empty()){ + insert_commit_data data; + std::pair ret = + this->insert_unique_check(hint, KeyOfValue()(nh.value()), data); + if(ret.second){ + irt.inserted = true; + irt.position = iterator(this->icont().insert_unique_commit(*nh.get_node_pointer(), data)); + nh.release(); + } + else{ + irt.position = ret.first; + irt.node = boost::move(nh); + } + } + else{ + irt.position = this->end(); + } + return BOOST_MOVE_RET(insert_return_type, irt); + } + + iterator insert_equal_node(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + if(nh.empty()){ + return this->end(); + } + else{ + NodePtr const p(nh.release()); + return iterator(this->icont().insert_equal(*p)); + } + } + + iterator insert_equal_node(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + if(nh.empty()){ + return this->end(); + } + else{ + NodePtr const p(nh.release()); + return iterator(this->icont().insert_equal(hint.get(), *p)); + } + } + BOOST_CONTAINER_FORCEINLINE void clear() { AllocHolder::clear(alloc_version()); } diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index 69fea65..11cbad8 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -112,14 +112,14 @@ class flat_map //This is the tree that we should store if pair was movable typedef container_detail::flat_tree, - container_detail::select1st< std::pair >, + 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 >, + container_detail::select1st, Compare, typename allocator_traits::template portable_rebind_alloc >::type> impl_tree_t; @@ -131,7 +131,7 @@ class flat_map typedef typename impl_tree_t::allocator_type impl_allocator_type; typedef container_detail::flat_tree_value_compare < Compare - , container_detail::select1st< std::pair > + , container_detail::select1st , std::pair > value_compare_impl; typedef typename container_detail::get_flat_tree_iterators ::pointer>::iterator iterator_impl; @@ -782,17 +782,17 @@ class flat_map , boost::forward(args)...)); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(k), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), //! forward_as_tuple(forward(args)...). //! - //! Returns: The bool component of the returned pair is true if and only if the + //! Returns: The bool component of the returned pair is true if and only if the //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(const key_type& k, BOOST_FWD_REF(Args)... args) { @@ -800,14 +800,14 @@ class flat_map m_flat_tree.try_emplace(impl_const_iterator(), k, boost::forward(args)...)); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(k), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), //! forward_as_tuple(forward(args)...). //! - //! Returns: The returned iterator points to the map element whose key is equivalent to k. + //! Returns: The returned iterator points to the map element whose key is equivalent to k. //! //! Complexity: Logarithmic in general, but amortized constant if value //! is inserted right before p. @@ -818,17 +818,17 @@ class flat_map (container_detail::force_copy(hint), k, boost::forward(args)...).first); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(move(k)), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), //! forward_as_tuple(forward(args)...). //! - //! Returns: The bool component of the returned pair is true if and only if the + //! Returns: The bool component of the returned pair is true if and only if the //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { @@ -836,14 +836,14 @@ class flat_map (m_flat_tree.try_emplace(impl_const_iterator(), boost::move(k), boost::forward(args)...)); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(move(k)), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), //! forward_as_tuple(forward(args)...). //! - //! Returns: The returned iterator points to the map element whose key is equivalent to k. + //! Returns: The returned iterator points to the map element whose key is equivalent to k. //! //! Complexity: Logarithmic in general, but amortized constant if value //! is inserted right before p. @@ -1328,13 +1328,13 @@ class flat_multimap BOOST_COPYABLE_AND_MOVABLE(flat_multimap) typedef container_detail::flat_tree, - container_detail::select1st< std::pair >, + 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 >, + container_detail::select1st, Compare, typename allocator_traits::template portable_rebind_alloc >::type> impl_tree_t; @@ -1346,7 +1346,7 @@ class flat_multimap typedef typename impl_tree_t::allocator_type impl_allocator_type; typedef container_detail::flat_tree_value_compare < Compare - , container_detail::select1st< std::pair > + , container_detail::select1st , std::pair > value_compare_impl; typedef typename container_detail::get_flat_tree_iterators ::pointer>::iterator iterator_impl; diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 46dc7f8..219ffe1 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -53,6 +53,34 @@ namespace boost { namespace container { +///@cond + +template +struct pair_key_mapped_of_value +{ + typedef Key key_type; + typedef Mapped mapped_type; + + template + const key_type & key_of_value(const Pair &p) const + { return p.first; } + + template + const mapped_type & mapped_of_value(const Pair &p) const + { return p.second; } + + template + key_type & key_of_value(Pair &p) const + { return const_cast(p.first); } + + template + mapped_type & mapped_of_value(Pair &p) const + { return p.second; } + +}; + +///@endcond + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED //! A map is a kind of associative container that supports unique keys (contains at @@ -78,7 +106,7 @@ class map ///@cond : public container_detail::tree < Key, std::pair - , container_detail::select1st< std::pair > + , container_detail::select1st , Compare, Allocator, MapOptions> ///@endcond { @@ -86,13 +114,13 @@ class map private: BOOST_COPYABLE_AND_MOVABLE(map) - typedef std::pair value_type_impl; + typedef container_detail::select1st select_1st_t; + typedef std::pair value_type_impl; typedef container_detail::tree - , Compare, Allocator, MapOptions> base_t; - typedef container_detail::pair movable_value_type_impl; + base_t; + typedef container_detail::pair movable_value_type_impl; typedef container_detail::tree_value_compare - < Key, value_type_impl, Compare, container_detail::select1st - > value_compare_impl; + < Key, value_type_impl, Compare, select_1st_t> value_compare_impl; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED public: @@ -102,10 +130,10 @@ class map // ////////////////////////////////////////////// - typedef Key key_type; - typedef ::boost::container::allocator_traits allocator_traits_type; - typedef T mapped_type; - typedef std::pair value_type; + typedef Key key_type; + typedef ::boost::container::allocator_traits allocator_traits_type; + typedef T mapped_type; + typedef std::pair value_type; typedef typename boost::container::allocator_traits::pointer pointer; typedef typename boost::container::allocator_traits::const_pointer const_pointer; typedef typename boost::container::allocator_traits::reference reference; @@ -122,6 +150,14 @@ class map typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; typedef std::pair nonconst_value_type; typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; + typedef BOOST_CONTAINER_IMPDEF(node_handle< + typename base_t::node_type::container_node_type + BOOST_MOVE_I value_type + BOOST_MOVE_I allocator_type + BOOST_MOVE_I pair_key_mapped_of_value + >) node_type; + typedef BOOST_CONTAINER_IMPDEF + (insert_return_type_base) insert_return_type; ////////////////////////////////////////////// // @@ -484,20 +520,20 @@ class map #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) - //! Effects: If there is no key equivalent to x in the map, inserts + //! Effects: If there is no key equivalent to x in the map, inserts //! value_type(x, T()) into the map. //! - //! Returns: A reference to the mapped_type corresponding to x in *this. + //! Returns: A reference to the mapped_type corresponding to x in *this. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. mapped_type& operator[](const key_type &k); - //! Effects: If there is no key equivalent to x in the map, inserts + //! Effects: If there is no key equivalent to x in the map, inserts //! value_type(boost::move(x), T()) into the map (the key is move-constructed) //! - //! Returns: A reference to the mapped_type corresponding to x in *this. + //! Returns: A reference to the mapped_type corresponding to x in *this. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. mapped_type& operator[](key_type &&k); #elif defined(BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN) //in compilers like GCC 3.4, we can't catch temporaries @@ -507,7 +543,7 @@ class map BOOST_MOVE_CONVERSION_AWARE_CATCH( operator[] , key_type, mapped_type&, this->priv_subscript) #endif - //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value //! as if by insert, constructing it from value_type(k, forward(obj)). //! @@ -515,15 +551,15 @@ class map //! to the element obtained while it is held in the node handle are invalidated, and pointers and //! references obtained to that element before it was extracted become valid. //! - //! Returns: The bool component is true if the insertion took place and false if the assignment + //! Returns: The bool component is true if the insertion took place and false if the assignment //! took place. The iterator component is pointing at the element that was inserted or updated. //! - //! Complexity: Logarithmic in the size of the container. + //! Complexity: Logarithmic in the size of the container. template BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(const key_type& k, BOOST_FWD_REF(M) obj) { return this->base_t::insert_or_assign(const_iterator(), k, ::boost::forward(obj)); } - //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value //! as if by insert, constructing it from value_type(k, move(obj)). //! @@ -531,15 +567,15 @@ class map //! to the element obtained while it is held in the node handle are invalidated, and pointers and //! references obtained to that element before it was extracted become valid. //! - //! Returns: The bool component is true if the insertion took place and false if the assignment + //! Returns: The bool component is true if the insertion took place and false if the assignment //! took place. The iterator component is pointing at the element that was inserted or updated. //! - //! Complexity: Logarithmic in the size of the container. + //! Complexity: Logarithmic in the size of the container. template BOOST_CONTAINER_FORCEINLINE std::pair insert_or_assign(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { return this->base_t::insert_or_assign(const_iterator(), ::boost::move(k), ::boost::forward(obj)); } - //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value //! as if by insert, constructing it from value_type(k, forward(obj)) and the new element //! to the container as close as possible to the position just before hint. @@ -548,16 +584,16 @@ class map //! to the element obtained while it is held in the node handle are invalidated, and pointers and //! references obtained to that element before it was extracted become valid. //! - //! Returns: The bool component is true if the insertion took place and false if the assignment + //! Returns: The bool component is true if the insertion took place and false if the assignment //! took place. The iterator component is pointing at the element that was inserted or updated. //! - //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if //! the new element is inserted just before hint. template BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, const key_type& k, BOOST_FWD_REF(M) obj) { return this->base_t::insert_or_assign(hint, k, ::boost::forward(obj)); } - //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) + //! Effects: If a key equivalent to k already exists in the container, assigns forward(obj) //! to the mapped_type corresponding to the key k. If the key does not exist, inserts the new value //! as if by insert, constructing it from value_type(k, move(obj)) and the new element //! to the container as close as possible to the position just before hint. @@ -566,18 +602,18 @@ class map //! to the element obtained while it is held in the node handle are invalidated, and pointers and //! references obtained to that element before it was extracted become valid. //! - //! Returns: The bool component is true if the insertion took place and false if the assignment + //! Returns: The bool component is true if the insertion took place and false if the assignment //! took place. The iterator component is pointing at the element that was inserted or updated. //! - //! Complexity: Logarithmic in the size of the container in general, but amortized constant if + //! Complexity: Logarithmic in the size of the container in general, but amortized constant if //! the new element is inserted just before hint. template BOOST_CONTAINER_FORCEINLINE iterator insert_or_assign(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(M) obj) { return this->base_t::insert_or_assign(hint, ::boost::move(k), ::boost::forward(obj)); } - //! Returns: A reference to the element whose key is equivalent to x. + //! Returns: A reference to the element whose key is equivalent to x. //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. + //! Complexity: logarithmic. T& at(const key_type& k) { iterator i = this->find(k); @@ -587,9 +623,9 @@ class map return i->second; } - //! Returns: A reference to the element whose key is equivalent to x. + //! Returns: A reference to the element whose key is equivalent to x. //! Throws: An exception object of type out_of_range if no such element is present. - //! Complexity: logarithmic. + //! Complexity: logarithmic. const T& at(const key_type& k) const { const_iterator i = this->find(k); @@ -625,7 +661,7 @@ class map //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE std::pair insert(const nonconst_value_type& x) - { return this->base_t::insert_unique(x); } + { return this->try_emplace(x.first, x.second); } //! Effects: Inserts a new value_type move constructed from the pair if and //! only if there is no element in the container with key equivalent to the key of x. @@ -636,7 +672,7 @@ class map //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE std::pair insert(BOOST_RV_REF(nonconst_value_type) x) - { return this->base_t::insert_unique(boost::move(x)); } + { return this->try_emplace(boost::move(x.first), boost::move(x.second)); } //! Effects: Inserts a new value_type move constructed from the pair if and //! only if there is no element in the container with key equivalent to the key of x. @@ -647,7 +683,7 @@ class map //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE std::pair insert(BOOST_RV_REF(movable_value_type) x) - { return this->base_t::insert_unique(boost::move(x)); } + { return this->try_emplace(boost::move(x.first), boost::move(x.second)); } //! Effects: Move constructs a new value from x if and only if there is //! no element in the container with key equivalent to the key of x. @@ -682,7 +718,7 @@ class map //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. iterator insert(const_iterator p, BOOST_RV_REF(nonconst_value_type) x) - { return this->base_t::insert_unique_convertible(p, boost::move(x)); } + { return this->try_emplace(p, boost::move(x.first), boost::move(x.second)); } //! Effects: Move constructs a new value from x if and only if there is //! no element in the container with key equivalent to the key of x. @@ -694,7 +730,7 @@ class map //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. iterator insert(const_iterator p, BOOST_RV_REF(movable_value_type) x) - { return this->base_t::insert_unique_convertible(p, boost::move(x)); } + { return this->try_emplace(p, boost::move(x.first), boost::move(x.second)); } //! Effects: Inserts a copy of x in the container. //! p is a hint pointing to where the insert should start to search. @@ -703,7 +739,7 @@ class map //! //! Complexity: Logarithmic. iterator insert(const_iterator p, const nonconst_value_type& x) - { return this->base_t::insert_unique_convertible(p, x); } + { return this->try_emplace(p, x.first, x.second); } //! Effects: Inserts an element move constructed from x in the container. //! p is a hint pointing to where the insert should start to search. @@ -733,6 +769,38 @@ class map { this->base_t::insert_unique(il.begin(), il.end()); } #endif + //! Requires: nh is empty or this->get_allocator() == nh.get_allocator(). + //! + //! Effects: If nh is empty, has no effect. Otherwise, inserts the element owned + //! by nh if and only if there is no element in the container with a key equivalent to nh.key(). + //! + //! Returns: If nh is empty, insert_return_type.inserted is false, insert_return_type.position + //! is end(), and insert_return_type.node is empty. Otherwise if the insertion took place, + //! insert_return_type.inserted is true, insert_return_type.position points to the inserted element, + //! and insert_return_type.node is empty; if the insertion failed, insert_return_type.inserted is + //! false, insert_return_type.node has the previous value of nh, and insert_return_type.position + //! points to an element with a key equivalent to nh.key(). + //! + //! Complexity: Logarithmic + insert_return_type insert(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + typename base_t::node_type n(boost::move(nh)); + typename base_t::insert_return_type base_ret(this->base_t::insert_unique_node(boost::move(n))); + return insert_return_type (base_ret.inserted, base_ret.position, boost::move(base_ret.node)); + } + + //! Effects: Same as `insert(node_type && nh)` but the element is inserted as close as possible + //! to the position just prior to "hint". + //! + //! Complexity: logarithmic in general, but amortized constant if the element is inserted + //! right before "hint". + insert_return_type insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + typename base_t::node_type n(boost::move(nh)); + typename base_t::insert_return_type base_ret(this->base_t::insert_unique_node(hint, boost::move(n))); + return insert_return_type (base_ret.inserted, base_ret.position, boost::move(base_ret.node)); + } + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Inserts an object x of type T constructed with @@ -764,29 +832,29 @@ class map BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator p, BOOST_FWD_REF(Args)... args) { return this->base_t::emplace_hint_unique(p, boost::forward(args)...); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(k), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), //! forward_as_tuple(forward(args)...). //! - //! Returns: The bool component of the returned pair is true if and only if the + //! Returns: The bool component of the returned pair is true if and only if the //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(const key_type& k, BOOST_FWD_REF(Args)... args) { return this->base_t::try_emplace(const_iterator(), k, boost::forward(args)...); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(k), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(k), //! forward_as_tuple(forward(args)...). //! - //! Returns: The returned iterator points to the map element whose key is equivalent to k. + //! Returns: The returned iterator points to the map element whose key is equivalent to k. //! //! Complexity: Logarithmic in general, but amortized constant if value //! is inserted right before p. @@ -794,29 +862,29 @@ class map BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k, BOOST_FWD_REF(Args)... args) { return this->base_t::try_emplace(hint, k, boost::forward(args)...).first; } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(move(k)), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), //! forward_as_tuple(forward(args)...). //! - //! Returns: The bool component of the returned pair is true if and only if the + //! Returns: The bool component of the returned pair is true if and only if the //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. //! - //! Complexity: Logarithmic. + //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) { return this->base_t::try_emplace(const_iterator(), boost::move(k), boost::forward(args)...); } - //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, + //! Requires: value_type shall be EmplaceConstructible into map from piecewise_construct, //! forward_as_tuple(move(k)), forward_as_tuple(forward(args)...). //! - //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise + //! Effects: If the map already contains an element whose key is equivalent to k, there is no effect. Otherwise //! inserts an object of type value_type constructed with piecewise_construct, forward_as_tuple(move(k)), //! forward_as_tuple(forward(args)...). //! - //! Returns: The returned iterator points to the map element whose key is equivalent to k. + //! Returns: The returned iterator points to the map element whose key is equivalent to k. //! //! Complexity: Logarithmic in general, but amortized constant if value //! is inserted right before p. @@ -881,6 +949,33 @@ class map //! Complexity: log(size())+N where N is the distance from first to last. iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW; + #endif + + //! Effects: Removes the first element in the container with key equivalent to k. + //! + //! Returns: A node_type owning the element if found, otherwise an empty node_type. + //! + //! Complexity: log(a.size()). + node_type extract(const key_type& k) + { + typename base_t::node_type base_nh(this->base_t::extract(k)); + node_type nh(boost::move(base_nh)); + return BOOST_MOVE_RET(node_type, nh); + } + + //! Effects: Removes the element pointed to by "position". + //! + //! Returns: A node_type owning the element, otherwise an empty node_type. + //! + //! Complexity: Amortized constant. + node_type extract(const_iterator position) + { + typename base_t::node_type base_nh(this->base_t::extract(position)); + node_type nh(boost::move(base_nh)); + return BOOST_MOVE_RET(node_type, nh); + } + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Swaps the contents of *this and x. //! //! Throws: Nothing. @@ -1012,7 +1107,7 @@ class map template BOOST_CONTAINER_FORCEINLINE mapped_type& priv_subscript(BOOST_FWD_REF(KeyConvertible) k) { - return this->insert_from_key(boost::forward(k))->second; + return this->try_emplace(boost::forward(k)).first->second; } #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED }; @@ -1063,7 +1158,7 @@ class multimap ///@cond : public container_detail::tree < Key, std::pair - , container_detail::select1st< std::pair > + , container_detail::select1st , Compare, Allocator, MultiMapOptions> ///@endcond { @@ -1071,16 +1166,16 @@ class multimap private: BOOST_COPYABLE_AND_MOVABLE(multimap) - typedef std::pair value_type_impl; + typedef container_detail::select1st select_1st_t; + typedef std::pair value_type_impl; typedef container_detail::tree - , Compare, Allocator, MultiMapOptions> base_t; - typedef container_detail::pair movable_value_type_impl; + base_t; + typedef container_detail::pair movable_value_type_impl; typedef container_detail::tree_value_compare - < Key, value_type_impl, Compare, container_detail::select1st - > value_compare_impl; + value_compare_impl; #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED - typedef ::boost::container::allocator_traits allocator_traits_type; + typedef ::boost::container::allocator_traits allocator_traits_type; public: ////////////////////////////////////////////// @@ -1108,6 +1203,12 @@ class multimap typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; typedef std::pair nonconst_value_type; typedef BOOST_CONTAINER_IMPDEF(movable_value_type_impl) movable_value_type; + typedef BOOST_CONTAINER_IMPDEF(node_handle< + typename base_t::node_type::container_node_type + BOOST_MOVE_I value_type + BOOST_MOVE_I allocator_type + BOOST_MOVE_I pair_key_mapped_of_value + >) node_type; ////////////////////////////////////////////// // @@ -1426,21 +1527,21 @@ class multimap //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator insert(const nonconst_value_type& x) - { return this->base_t::insert_equal(x); } + { return this->base_t::emplace_equal(x); } //! Effects: Inserts a new value move-constructed from x and returns //! the iterator pointing to the newly inserted element. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator insert(BOOST_RV_REF(nonconst_value_type) x) - { return this->base_t::insert_equal(boost::move(x)); } + { return this->base_t::emplace_equal(boost::move(x)); } //! Effects: Inserts a new value move-constructed from x and returns //! the iterator pointing to the newly inserted element. //! //! Complexity: Logarithmic. iterator insert(BOOST_RV_REF(movable_value_type) x) - { return this->base_t::insert_equal(boost::move(x)); } + { return this->base_t::emplace_equal(boost::move(x)); } //! Effects: Inserts a copy of x in the container. //! p is a hint pointing to where the insert should start to search. @@ -1462,7 +1563,7 @@ class multimap //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, const nonconst_value_type& x) - { return this->base_t::insert_equal_convertible(p, x); } + { return this->base_t::emplace_hint_equal(p, x); } //! Effects: Inserts a new value move constructed from x in the container. //! p is a hint pointing to where the insert should start to search. @@ -1473,7 +1574,7 @@ class multimap //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, BOOST_RV_REF(nonconst_value_type) x) - { return this->base_t::insert_equal_convertible(p, boost::move(x)); } + { return this->base_t::emplace_hint_equal(p, boost::move(x)); } //! Effects: Inserts a new value move constructed from x in the container. //! p is a hint pointing to where the insert should start to search. @@ -1484,7 +1585,7 @@ class multimap //! Complexity: Logarithmic in general, but amortized constant if t //! is inserted right before p. BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, BOOST_RV_REF(movable_value_type) x) - { return this->base_t::insert_equal_convertible(p, boost::move(x)); } + { return this->base_t::emplace_hint_equal(p, boost::move(x)); } //! Requires: first, last are not iterators into *this. //! @@ -1503,6 +1604,31 @@ class multimap { this->base_t::insert_equal(il.begin(), il.end()); } #endif + //! Requires: nh is empty or this->get_allocator() == nh.get_allocator(). + //! + //! Effects/Returns: If nh is empty, has no effect and returns end(). Otherwise, inserts + //! the element owned by nh and returns an iterator pointing to the newly inserted element. + //! If a range containing elements with keys equivalent to nh.key() exists, + //! the element is inserted at the end of that range. nh is always emptied. + //! + //! Complexity: Logarithmic + iterator insert(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + typename base_t::node_type n(boost::move(nh)); + return this->base_t::insert_equal_node(boost::move(n)); + } + + //! Effects: Same as `insert(node_type && nh)` but the element is inserted as close as possible + //! to the position just prior to "hint". + //! + //! Complexity: logarithmic in general, but amortized constant if the element is inserted + //! right before "hint". + iterator insert(const_iterator hint, BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { + typename base_t::node_type n(boost::move(nh)); + return this->base_t::insert_equal_node(hint, boost::move(n)); + } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::set::erase(const_iterator) @@ -1513,7 +1639,23 @@ class multimap //! @copydoc ::boost::container::set::erase(const_iterator,const_iterator) iterator erase(const_iterator first, const_iterator last); + #endif + //! @copydoc ::boost::container::map::extract(const key_type&) + node_type extract(const key_type& k) + { + typename base_t::node_type base_nh(this->base_t::extract(k)); + return node_type(boost::move(base_nh)); + } + + //! @copydoc ::boost::container::map::extract(const_iterator) + node_type extract(const_iterator position) + { + typename base_t::node_type base_nh(this->base_t::extract(position)); + return node_type (boost::move(base_nh)); + } + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::set::swap void swap(multiset& x) BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 36ead84..3f0dbe6 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -100,6 +100,8 @@ class set typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(base_t::node_type) node_type; + typedef typename BOOST_CONTAINER_IMPDEF(base_t::insert_return_type) insert_return_type; ////////////////////////////////////////////// // @@ -523,6 +525,14 @@ class set { this->base_t::insert_unique(il.begin(), il.end()); } #endif + //! @copydoc ::boost::container::map::insert(node_type&&) + insert_return_type insert(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { return this->base_t::insert_unique_node(boost::move(nh)); } + + //! @copydoc ::boost::container::map::insert(const_iterator, node_type&&) + 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)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! Effects: Erases the element pointed to by p. @@ -782,6 +792,7 @@ class multiset typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_iterator) const_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::reverse_iterator) reverse_iterator; typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; + typedef typename BOOST_CONTAINER_IMPDEF(base_t::node_type) node_type; ////////////////////////////////////////////// // @@ -1049,6 +1060,14 @@ class multiset { this->base_t::insert_equal(il.begin(), il.end()); } #endif + //! @copydoc ::boost::container::multimap::insert(node_type&&) + iterator insert(BOOST_RV_REF_BEG_IF_CXX11 node_type BOOST_RV_REF_END_IF_CXX11 nh) + { return this->base_t::insert_equal_node(boost::move(nh)); } + + //! @copydoc ::boost::container::multimap::insert(const_iterator, node_type&&) + 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)); } + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) //! @copydoc ::boost::container::set::erase(const_iterator) diff --git a/proj/vc7ide/alloc_lib.vcproj b/proj/vc7ide/alloc_lib.vcproj index 4e5a755..31983cc 100644 --- a/proj/vc7ide/alloc_lib.vcproj +++ b/proj/vc7ide/alloc_lib.vcproj @@ -108,9 +108,6 @@ - - diff --git a/proj/vc7ide/container.sln b/proj/vc7ide/container.sln index 178ee63..7d059aa 100644 --- a/proj/vc7ide/container.sln +++ b/proj/vc7ide/container.sln @@ -303,6 +303,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmr_string_test", "pmr_stri ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "node_handle_test", "node_handle_test.vcproj", "{5A17C6C5-6C29-A74F-48FE-A7FA7A063106}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -613,6 +617,10 @@ Global {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Debug.Build.0 = Debug|Win32 {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Release.ActiveCfg = Release|Win32 {85EADC21-42FA-F8A3-306C-A2029D5E7233}.Release.Build.0 = Release|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Debug.ActiveCfg = Debug|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Debug.Build.0 = Debug|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Release.ActiveCfg = Release|Win32 + {5A17C6C5-6C29-A74F-48FE-A7FA7A063106}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/container.vcproj b/proj/vc7ide/container.vcproj index 4344eb0..dec8759 100644 --- a/proj/vc7ide/container.vcproj +++ b/proj/vc7ide/container.vcproj @@ -131,6 +131,9 @@ + + @@ -523,9 +526,6 @@ - - diff --git a/test/map_test.cpp b/test/map_test.cpp index 26ebd37..e608abb 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -110,6 +110,118 @@ void test_move() move_assign.swap(original); } +bool node_type_test() +{ + using namespace boost::container; + { + typedef map map_type; + map_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_11(11), mv_12(12), mv_13(13); + src.try_emplace(boost::move(mv_1), boost::move(mv_11)); + src.try_emplace(boost::move(mv_2), boost::move(mv_12)); + src.try_emplace(boost::move(mv_3), boost::move(mv_13)); + } + if(src.size() != 3) + return false; + + map_type dst; + { + test::movable_int mv_3(3), mv_33(33); + dst.try_emplace(boost::move(mv_3), boost::move(mv_33)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_33(33); + const test::movable_int mv_13(13); + map_type::insert_return_type r; + + r = dst.insert(src.extract(mv_33)); // Key version, try to insert empty node + if(! (r.position == dst.end() && r.inserted == false && r.node.empty()) ) + return false; + r = dst.insert(src.extract(src.find(mv_1))); // Iterator version, successful + if(! (r.position == dst.find(mv_1) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(dst.begin(), src.extract(mv_2)); // Key type version, successful + if(! (r.position == dst.find(mv_2) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(src.extract(mv_3)); // Key type version, unsuccessful + + if(!src.empty()) + return false; + if(dst.size() != 3) + return false; + if(! (r.position == dst.find(mv_3) && r.inserted == false && r.node.key() == mv_3 && r.node.mapped() == mv_13) ) + return false; + } + + { + typedef multimap multimap_type; + multimap_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_3bis(3), mv_11(11), mv_12(12), mv_13(13), mv_23(23); + src.emplace(boost::move(mv_1), boost::move(mv_11)); + src.emplace(boost::move(mv_2), boost::move(mv_12)); + src.emplace(boost::move(mv_3), boost::move(mv_13)); + src.emplace_hint(src.begin(), boost::move(mv_3bis), boost::move(mv_23)); + } + if(src.size() != 4) + return false; + + multimap_type dst; + { + test::movable_int mv_3(3), mv_33(33); + dst.emplace(boost::move(mv_3), boost::move(mv_33)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_4(4); + const test::movable_int mv_33(33); + const test::movable_int mv_13(13); + const test::movable_int mv_23(23); + multimap_type::iterator r; + + multimap_type::node_type nt(src.extract(mv_3)); + r = dst.insert(dst.begin(), boost::move(nt)); + if(! (r->first == mv_3 && r->second == mv_23 && dst.find(mv_3) == r && nt.empty()) ) + return false; + + nt = src.extract(src.find(mv_1)); + r = dst.insert(boost::move(nt)); // Iterator version, successful + if(! (r->first == mv_1 && nt.empty()) ) + return false; + + nt = src.extract(mv_2); + r = dst.insert(boost::move(nt)); // Key type version, successful + if(! (r->first == mv_2 && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_3)); // Key type version, successful + if(! (r->first == mv_3 && r->second == mv_13 && r == --multimap_type::iterator(dst.upper_bound(mv_3)) && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_4)); // Key type version, unsuccessful + if(! (r == dst.end()) ) + return false; + + if(!src.empty()) + return false; + if(dst.size() != 5) + return false; + } + return true; +} + template struct GetAllocatorMap { @@ -329,6 +441,12 @@ int main () } } + //////////////////////////////////// + // Node extraction/insertion testing functions + //////////////////////////////////// + if(!node_type_test()) + return 1; + //////////////////////////////////// // Test optimize_size option //////////////////////////////////// diff --git a/test/set_test.cpp b/test/set_test.cpp index c447060..bc9f2cd 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -136,6 +136,114 @@ void test_move() move_assign.swap(original); } +bool node_type_test() +{ + using namespace boost::container; + { + typedef set set_type; + set_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3); + src.emplace(boost::move(mv_1)); + src.emplace(boost::move(mv_2)); + src.emplace(boost::move(mv_3)); + } + if(src.size() != 3) + return false; + + set_type dst; + { + test::movable_int mv_3(3); + dst.emplace(boost::move(mv_3)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_33(33); + set_type::insert_return_type r; + + r = dst.insert(src.extract(mv_33)); // Key version, try to insert empty node + if(! (r.position == dst.end() && r.inserted == false && r.node.empty()) ) + return false; + r = dst.insert(src.extract(src.find(mv_1))); // Iterator version, successful + if(! (r.position == dst.find(mv_1) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(dst.begin(), src.extract(mv_2)); // Key type version, successful + if(! (r.position == dst.find(mv_2) && r.inserted == true && r.node.empty()) ) + return false; + r = dst.insert(src.extract(mv_3)); // Key type version, unsuccessful + + if(!src.empty()) + return false; + if(dst.size() != 3) + return false; + if(! (r.position == dst.find(mv_3) && r.inserted == false && r.node.value() == mv_3) ) + return false; + } + + { + typedef multiset multiset_type; + multiset_type src; + { + test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_3bis(3); + src.emplace(boost::move(mv_1)); + src.emplace(boost::move(mv_2)); + src.emplace(boost::move(mv_3)); + src.emplace_hint(src.begin(), boost::move(mv_3bis)); + } + if(src.size() != 4) + return false; + + multiset_type dst; + { + test::movable_int mv_3(3); + dst.emplace(boost::move(mv_3)); + } + + if(dst.size() != 1) + return false; + + const test::movable_int mv_1(1); + const test::movable_int mv_2(2); + const test::movable_int mv_3(3); + const test::movable_int mv_4(4); + multiset_type::iterator r; + + multiset_type::node_type nt(src.extract(mv_3)); + r = dst.insert(dst.begin(), boost::move(nt)); + if(! (*r == mv_3 && dst.find(mv_3) == r && nt.empty()) ) + return false; + + nt = src.extract(src.find(mv_1)); + r = dst.insert(boost::move(nt)); // Iterator version, successful + if(! (*r == mv_1 && nt.empty()) ) + return false; + + nt = src.extract(mv_2); + r = dst.insert(boost::move(nt)); // Key type version, successful + if(! (*r == mv_2 && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_3)); // Key type version, successful + if(! (*r == mv_3 && r == --multiset_type::iterator(dst.upper_bound(mv_3)) && nt.empty()) ) + return false; + + r = dst.insert(src.extract(mv_4)); // Key type version, unsuccessful + if(! (r == dst.end()) ) + return false; + + if(!src.empty()) + return false; + if(dst.size() != 5) + return false; + } + return true; +} + struct boost_container_set; struct boost_container_multiset; @@ -271,7 +379,6 @@ int main () std::pair p(0, 0); s.insert(p); s.emplace(p); - return 0; } //////////////////////////////////// @@ -382,6 +489,13 @@ int main () return 1; } } + + //////////////////////////////////// + // Node extraction/insertion testing functions + //////////////////////////////////// + if(!node_type_test()) + return 1; + return 0; }