diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 4337924..fc61af7 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -1115,10 +1115,10 @@ class tree std::pair insert_or_assign(const_iterator hint, BOOST_FWD_REF(KeyType) key, BOOST_FWD_REF(M) obj) { insert_commit_data data; - const key_type & k = key; //Support emulated rvalue references + const typename remove_cvref::type & k = key; //Support emulated rvalue references std::pair ret = - hint == const_iterator() ? this->icont().insert_unique_check(k, data) - : this->icont().insert_unique_check(hint.get(), k, data); + hint == const_iterator() ? this->icont().insert_unique_check(k, KeyNodeCompare(key_comp()), data) + : this->icont().insert_unique_check(hint.get(), k, KeyNodeCompare(key_comp()), data); if(ret.second){ ret.first = this->priv_insert_or_assign_commit(boost::forward(key), boost::forward(obj), data); } diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 1d2b47a..dde6035 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -611,6 +611,31 @@ class map inline 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)); } + //! Requires: This overload is available only if key_compare::is_transparent exists. + //! + //! 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)). + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! 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 + //! took place. The iterator component is pointing at the element that was inserted or updated. + //! + //! Complexity: Logarithmic in the size of the container. + template + + BOOST_CONTAINER_DOC1ST + ( std::pair + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I std::pair + >::type) //transparent + insert_or_assign(BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(const_iterator(), ::boost::forward(k), ::boost::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 @@ -645,6 +670,31 @@ class map inline 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)).first; } + //! Requires: This overload is available only if key_compare::is_transparent exists. + //! + //! 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. + //! + //! No iterators or references are invalidated. If the insertion is successful, pointers and references + //! 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 returned iterator points to the map element whose key is equivalent to k. + //! + //! 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_DOC1ST + ( iterator + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I iterator + >::type) //transparent + insert_or_assign(const_iterator hint, BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj) + { return this->base_t::insert_or_assign(hint, ::boost::forward(k), ::boost::forward(obj)).first; } + //! 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. diff --git a/test/map_test.cpp b/test/map_test.cpp index 4a3fddb..a2ed95f 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -261,115 +261,135 @@ void test_merge_from_different_comparison() bool test_heterogeneous_lookups() { - typedef map map_t; - typedef multimap mmap_t; - typedef map_t::value_type value_type; + { + typedef map map_t; + typedef multimap mmap_t; + typedef map_t::value_type value_type; - map_t map1; - mmap_t mmap1; + map_t map1; + mmap_t mmap1; - const map_t &cmap1 = map1; - const mmap_t &cmmap1 = mmap1; + const map_t &cmap1 = map1; + const mmap_t &cmmap1 = mmap1; - if(!map1.insert_or_assign(1, 'a').second) - return false; - if( map1.insert_or_assign(1, 'b').second) - return false; - if(!map1.insert_or_assign(2, 'c').second) - return false; - if( map1.insert_or_assign(2, 'd').second) - return false; - if(!map1.insert_or_assign(3, 'e').second) - return false; + if(!map1.insert_or_assign(1, 'a').second) + return false; + if( map1.insert_or_assign(1, 'b').second) + return false; + if(!map1.insert_or_assign(2, 'c').second) + return false; + if( map1.insert_or_assign(2, 'd').second) + return false; + if(!map1.insert_or_assign(3, 'e').second) + return false; - if(map1.insert_or_assign(1, 'a').second) - return false; - if(map1.insert_or_assign(1, 'b').second) - return false; - if(map1.insert_or_assign(2, 'c').second) - return false; - if(map1.insert_or_assign(2, 'd').second) - return false; - if(map1.insert_or_assign(3, 'e').second) - return false; + if(map1.insert_or_assign(1, 'a').second) + return false; + if(map1.insert_or_assign(1, 'b').second) + return false; + if(map1.insert_or_assign(2, 'c').second) + return false; + if(map1.insert_or_assign(2, 'd').second) + return false; + if(map1.insert_or_assign(3, 'e').second) + return false; - mmap1.insert(value_type(1, 'a')); - mmap1.insert(value_type(1, 'b')); - mmap1.insert(value_type(2, 'c')); - mmap1.insert(value_type(2, 'd')); - mmap1.insert(value_type(3, 'e')); + mmap1.insert(value_type(1, 'a')); + mmap1.insert(value_type(1, 'b')); + mmap1.insert(value_type(2, 'c')); + mmap1.insert(value_type(2, 'd')); + mmap1.insert(value_type(3, 'e')); - const test::non_copymovable_int find_me(2); + const test::non_copymovable_int find_me(2); - //find - if(map1.find(find_me)->second != 'd') - return false; - if(cmap1.find(find_me)->second != 'd') - return false; - if(mmap1.find(find_me)->second != 'c') - return false; - if(cmmap1.find(find_me)->second != 'c') - return false; + //find + if(map1.find(find_me)->second != 'd') + return false; + if(cmap1.find(find_me)->second != 'd') + return false; + if(mmap1.find(find_me)->second != 'c') + return false; + if(cmmap1.find(find_me)->second != 'c') + return false; - //count - if(map1.count(find_me) != 1) - return false; - if(cmap1.count(find_me) != 1) - return false; - if(mmap1.count(find_me) != 2) - return false; - if(cmmap1.count(find_me) != 2) - return false; + //count + if(map1.count(find_me) != 1) + return false; + if(cmap1.count(find_me) != 1) + return false; + if(mmap1.count(find_me) != 2) + return false; + if(cmmap1.count(find_me) != 2) + return false; - //contains - if(!map1.contains(find_me)) - return false; - if(!cmap1.contains(find_me)) - return false; - if(!mmap1.contains(find_me)) - return false; - if(!cmmap1.contains(find_me)) - return false; + //contains + if(!map1.contains(find_me)) + return false; + if(!cmap1.contains(find_me)) + return false; + if(!mmap1.contains(find_me)) + return false; + if(!cmmap1.contains(find_me)) + return false; - //lower_bound - if(map1.lower_bound(find_me)->second != 'd') - return false; - if(cmap1.lower_bound(find_me)->second != 'd') - return false; - if(mmap1.lower_bound(find_me)->second != 'c') - return false; - if(cmmap1.lower_bound(find_me)->second != 'c') - return false; + //lower_bound + if(map1.lower_bound(find_me)->second != 'd') + return false; + if(cmap1.lower_bound(find_me)->second != 'd') + return false; + if(mmap1.lower_bound(find_me)->second != 'c') + return false; + if(cmmap1.lower_bound(find_me)->second != 'c') + return false; - //upper_bound - if(map1.upper_bound(find_me)->second != 'e') - return false; - if(cmap1.upper_bound(find_me)->second != 'e') - return false; - if(mmap1.upper_bound(find_me)->second != 'e') - return false; - if(cmmap1.upper_bound(find_me)->second != 'e') - return false; + //upper_bound + if(map1.upper_bound(find_me)->second != 'e') + return false; + if(cmap1.upper_bound(find_me)->second != 'e') + return false; + if(mmap1.upper_bound(find_me)->second != 'e') + return false; + if(cmmap1.upper_bound(find_me)->second != 'e') + return false; - //equal_range - if(map1.equal_range(find_me).first->second != 'd') - return false; - if(cmap1.equal_range(find_me).second->second != 'e') - return false; - if(mmap1.equal_range(find_me).first->second != 'c') - return false; - if(cmmap1.equal_range(find_me).second->second != 'e') - return false; + //equal_range + if(map1.equal_range(find_me).first->second != 'd') + return false; + if(cmap1.equal_range(find_me).second->second != 'e') + return false; + if(mmap1.equal_range(find_me).first->second != 'c') + return false; + if(cmmap1.equal_range(find_me).second->second != 'e') + return false; - //erase - if (map1.erase(find_me) != 1) - return false; - if (map1.erase(find_me) != 0) - return false; - if (mmap1.erase(find_me) != 2) - return false; - if (mmap1.erase(find_me) != 0) - return false; + //erase + if (map1.erase(find_me) != 1) + return false; + if (map1.erase(find_me) != 0) + return false; + if (mmap1.erase(find_me) != 2) + return false; + if (mmap1.erase(find_me) != 0) + return false; + } + { + typedef map map_t; + + map_t map1; + + //insert_or_assign + if(!map1.insert_or_assign(1, 'e').second) + return false; + if(map1.insert_or_assign(1, 'b').second) + return false; + + //insert_or_assign with hint + if(map1.find(2) != map1.end()) + return false; + map_t::iterator i = map1.insert_or_assign(map1.begin(), 2, 'e'); + if(i != map1.insert_or_assign(map1.end(), 2, 'b')) + return false; + } return true; }