diff --git a/doc/container.qbk b/doc/container.qbk index cc70e52..ca86d2e 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1231,7 +1231,7 @@ 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 `insert_or_assign` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. +* Implemented C++17 `insert_or_assign` and `try_emplace`for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. [endsect] diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index b6029e0..69dc191 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -589,6 +589,29 @@ class flat_tree return this->insert_equal(hint, ::boost::move(val)); } + template + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace + (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args) + { + std::pair ret; + insert_commit_data data; + const key_type & k = key; + ret.second = hint == const_iterator() + ? this->priv_insert_unique_prepare(k, data) + : this->priv_insert_unique_prepare(hint, k, data); + + if(!ret.second){ + ret.first = this->nth(data.position - this->cbegin()); + } + else{ + typedef typename emplace_functor_type::type func_t; + typedef emplace_iterator it_t; + func_t func(try_emplace_t(), ::boost::forward(key), ::boost::forward(args)...); + ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t()); + } + return ret; + } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE(N) \ @@ -635,8 +658,30 @@ class flat_tree value_destructor d(a, val);\ return this->insert_equal(hint, ::boost::move(val));\ }\ + template \ + BOOST_CONTAINER_FORCEINLINE std::pair\ + try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + std::pair ret;\ + insert_commit_data data;\ + const key_type & k = key;\ + ret.second = hint == const_iterator()\ + ? this->priv_insert_unique_prepare(k, data)\ + : this->priv_insert_unique_prepare(hint, k, data);\ + \ + if(!ret.second){\ + ret.first = this->nth(data.position - this->cbegin());\ + }\ + else{\ + typedef typename emplace_functor_type::type func_t;\ + typedef emplace_iterator it_t;\ + func_t func(try_emplace_t(), ::boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + ret.first = this->m_data.m_vect.insert(data.position, it_t(func), it_t());\ + }\ + return ret;\ + }\ // - BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE) + BOOST_MOVE_ITERATE_0TO7(BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE) #undef BOOST_CONTAINER_FLAT_TREE_EMPLACE_CODE #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) diff --git a/include/boost/container/detail/pair.hpp b/include/boost/container/detail/pair.hpp index 101ba72..032e65b 100644 --- a/include/boost/container/detail/pair.hpp +++ b/include/boost/container/detail/pair.hpp @@ -70,6 +70,8 @@ namespace container { typedef const std::piecewise_construct_t & piecewise_construct_t; +struct try_emplace_t{}; + #else //! The piecewise_construct_t struct is an empty structure type used as a unique type to @@ -197,6 +199,25 @@ struct pair : first(::boost::move(p.first)), second(::boost::move(p.second)) {} + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< class KeyType, class ...Args> + pair(const try_emplace_t &, BOOST_FWD_REF(KeyType) k, Args && ...args) + : first(boost::forward(k)), second(::boost::forward(args)...)\ + {} + #else + + //piecewise construction from boost::tuple + #define BOOST_PAIR_TRY_EMPLACE_CONSTRUCT_CODE(N)\ + template< class KeyType BOOST_MOVE_I##N BOOST_MOVE_CLASS##N > \ + pair( try_emplace_t, BOOST_FWD_REF(KeyType) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N )\ + : first(boost::forward(k)), second(BOOST_MOVE_FWD##N)\ + {}\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_PAIR_TRY_EMPLACE_CONSTRUCT_CODE) + #undef BOOST_PAIR_TRY_EMPLACE_CONSTRUCT_CODE + + #endif //BOOST_NO_CXX11_VARIADIC_TEMPLATES + //piecewise construction from boost::tuple #define BOOST_PAIR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE(N,M)\ template< template class BoostTuple \ diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 0fa3f6a..65e64dd 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -920,7 +920,7 @@ class tree //No throw insertion part, release rollback destroy_deallocator.release(); return std::pair - ( iterator(iiterator(this->icont().insert_unique_commit(*p, data))) + ( iterator(this->icont().insert_unique_commit(*p, data)) , true ); } @@ -935,7 +935,7 @@ class tree Destroyer(this->node_alloc())(p); return ret.first; } - return iterator(iiterator(this->icont().insert_unique_commit(*p, data))); + return iterator(this->icont().insert_unique_commit(*p, data)); } public: @@ -971,6 +971,22 @@ class tree return ret; } + template + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace + (const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(Args)... args) + { + insert_commit_data data; + const key_type & k = key; //Support emulated rvalue references + std::pair ret = + hint == const_iterator() ? this->icont().insert_unique_check( k, KeyNodeCompare(value_comp()), data) + : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(value_comp()), data); + if(ret.second){ + ret.first = this->icont().insert_unique_commit + (*AllocHolder::create_node(try_emplace_t(), boost::forward(key), boost::forward(args)...), data); + } + return std::pair(iterator(ret.first), ret.second); + } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_TREE_EMPLACE_CODE(N) \ @@ -1002,6 +1018,22 @@ class tree destroy_deallocator.release();\ return ret;\ }\ + \ + template \ + BOOST_CONTAINER_FORCEINLINE std::pair\ + try_emplace(const_iterator hint, BOOST_FWD_REF(KeyType) key BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + insert_commit_data data;\ + const key_type & k = key;\ + std::pair ret =\ + hint == const_iterator() ? this->icont().insert_unique_check( k, KeyNodeCompare(value_comp()), data)\ + : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(value_comp()), data);\ + if(ret.second){\ + ret.first = this->icont().insert_unique_commit\ + (*AllocHolder::create_node(try_emplace_t(), boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N), data);\ + }\ + return std::pair(iterator(ret.first), ret.second);\ + }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_TREE_EMPLACE_CODE) #undef BOOST_CONTAINER_TREE_EMPLACE_CODE diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index afba9d1..69fea65 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -621,8 +621,7 @@ class flat_map { return container_detail::force_copy< std::pair > (this->m_flat_tree.insert_or_assign - ( container_detail::force_copy(const_iterator()) - , k, ::boost::forward(obj)) + ( impl_const_iterator(), k, ::boost::forward(obj)) ); } @@ -643,8 +642,7 @@ class flat_map { return container_detail::force_copy< std::pair > (this->m_flat_tree.insert_or_assign - ( container_detail::force_copy(const_iterator()) - , ::boost::move(k), ::boost::forward(obj)) + ( impl_const_iterator(), ::boost::move(k), ::boost::forward(obj)) ); } @@ -784,6 +782,79 @@ class flat_map , boost::forward(args)...)); } + //! 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 + //! 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 + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(const key_type& k, BOOST_FWD_REF(Args)... args) + { + return container_detail::force_copy< std::pair >( + m_flat_tree.try_emplace(impl_const_iterator(), k, boost::forward(args)...)); + } + + //! 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 + //! 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. + //! + //! Complexity: Logarithmic in general, but amortized constant if value + //! is inserted right before p. + template + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k, BOOST_FWD_REF(Args)... args) + { + return container_detail::force_copy(m_flat_tree.try_emplace + (container_detail::force_copy(hint), k, boost::forward(args)...).first); + } + + //! 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 + //! 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 + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! Complexity: Logarithmic. + template + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return container_detail::force_copy< std::pair > + (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, + //! 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 + //! 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. + //! + //! Complexity: Logarithmic in general, but amortized constant if value + //! is inserted right before p. + template + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { + return container_detail::force_copy + (m_flat_tree.try_emplace(container_detail::force_copy + (hint), boost::move(k), boost::forward(args)...).first); + } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE(N) \ @@ -800,6 +871,29 @@ class flat_map return container_detail::force_copy(m_flat_tree.emplace_hint_unique\ (container_detail::force_copy(hint) BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ }\ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(const key_type& k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return container_detail::force_copy< std::pair >\ + (m_flat_tree.try_emplace(impl_const_iterator(), k BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return container_detail::force_copy(m_flat_tree.try_emplace\ + (container_detail::force_copy(hint), k BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + return container_detail::force_copy< std::pair >\ + (m_flat_tree.try_emplace(impl_const_iterator(), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N));\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return container_detail::force_copy(m_flat_tree.try_emplace\ + (container_detail::force_copy(hint), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first); }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE) #undef BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index d2cf0ca..46dc7f8 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -484,20 +484,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 +507,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 +515,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 +531,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 +548,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 +566,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 +587,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); @@ -764,6 +764,66 @@ 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, + //! 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 + //! 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 + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! 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, + //! 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 + //! 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. + //! + //! Complexity: Logarithmic in general, but amortized constant if value + //! is inserted right before p. + template + 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, + //! 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 + //! 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 + //! insertion took place. The returned iterator points to the map element whose key is equivalent to k. + //! + //! 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, + //! 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 + //! 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. + //! + //! Complexity: Logarithmic in general, but amortized constant if value + //! is inserted right before p. + template + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k, BOOST_FWD_REF(Args)... args) + { return this->base_t::try_emplace(hint, boost::move(k), boost::forward(args)...).first; } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_MAP_EMPLACE_CODE(N) \ @@ -774,6 +834,22 @@ class map BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_CONTAINER_FORCEINLINE iterator emplace_hint(const_iterator hint BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ { return this->base_t::emplace_hint_unique(hint BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(const key_type& k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return this->base_t::try_emplace(const_iterator(), k BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, const key_type &k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return this->base_t::try_emplace(hint, k BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first; }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE std::pair try_emplace(BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return this->base_t::try_emplace(const_iterator(), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ + BOOST_CONTAINER_FORCEINLINE iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { return this->base_t::try_emplace(hint, boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first; }\ // BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_MAP_EMPLACE_CODE) #undef BOOST_CONTAINER_MAP_EMPLACE_CODE diff --git a/test/map_test.hpp b/test/map_test.hpp index 97b6f23..7e40360 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -726,6 +726,75 @@ int map_test() if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; } + { //try_emplace + boostmap.clear(); + boostmultimap.clear(); + stdmap.clear(); + stdmultimap.clear(); + + IntPairType aux_vect[max]; + for(int i = 0; i < max; ++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){ + IntType i1(i); + IntType i2(max-i); + new(&aux_vect2[i])IntPairType(boost::move(i1), boost::move(i2)); + } + + typedef typename MyBoostMap::iterator iterator; + for(int i = 0; i < max; ++i){ + iterator it; + if(i&1){ + std::pair ret = + boostmap.try_emplace(boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); + if(!ret.second) + return 1; + it = ret.first; + } + else{ + it = boostmap.try_emplace + (boostmap.upper_bound(aux_vect[i].first), boost::move(aux_vect[i].first), boost::move(aux_vect[i].second)); + } + if(boostmap.end() == it || it->first != aux_vect2[i].first || it->second != aux_vect2[i].first){ + return 1; + } + stdmap[i] = i; + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + + for(int i = 0; i < max; ++i){ + iterator it; + iterator itex = boostmap.find(aux_vect2[i].first); + if(itex == boostmap.end()) + return 1; + if(i&1){ + std::pair ret = + boostmap.try_emplace(boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); + if(ret.second) + return 1; + it = ret.first; + } + else{ + it = boostmap.try_emplace + (boostmap.upper_bound(aux_vect2[i].first), boost::move(aux_vect2[i].first), boost::move(aux_vect2[i].second)); + } + const IntType test_int(i); + if(boostmap.end() == it || it != itex || it->second != test_int){ + return 1; + } + } + + if(!CheckEqualPairContainers(boostmap, stdmap)) return 1; + if(!CheckEqualPairContainers(boostmultimap, stdmultimap)) return 1; + } + if(map_test_copyable (container_detail::bool_::value>())){ return 1; @@ -740,33 +809,33 @@ bool test_map_support_for_initialization_list_for() const std::initializer_list> il = { std::make_pair(1, 2), std::make_pair(3, 4) }; - const MapType expected(il.begin(), il.end()); + const MapType expected_map(il.begin(), il.end()); { const MapType sil = il; - if (sil != expected) + if (sil != expected_map) return false; MapType sila(il, typename MapType::allocator_type()); - if (sila != expected) + if (sila != expected_map) return false; MapType silca(il, typename MapType::key_compare(), typename MapType::allocator_type()); - if (silca != expected) + if (silca != expected_map) return false; const MapType sil_ordered(ordered_unique_range, il); - if (sil_ordered != expected) + if (sil_ordered != expected_map) return false; MapType sil_assign = { std::make_pair(99, 100) }; sil_assign = il; - if (sil_assign != expected) + if (sil_assign != expected_map) return false; } { MapType sil; sil.insert(il); - if (sil != expected) + if (sil != expected_map) return false; } return true;