diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index ee6e84f..0deb7eb 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -1046,7 +1046,7 @@ class flat_tree { std::pair ret; insert_commit_data data; - const key_type & k = key; + const typename remove_cvref::type & k = key; //Support emulated rvalue references ret.second = hint == const_iterator() ? this->priv_insert_unique_prepare(k, data) : this->priv_insert_unique_prepare(hint, k, data); @@ -1112,7 +1112,7 @@ class flat_tree {\ std::pair ret;\ insert_commit_data data;\ - const key_type & k = key;\ + const typename remove_cvref::type & k = key;\ ret.second = hint == const_iterator()\ ? this->priv_insert_unique_prepare(k, data)\ : this->priv_insert_unique_prepare(hint, k, data);\ diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index ff0a666..569d04a 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -1007,10 +1007,10 @@ class tree (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 + 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->icont().insert_unique_commit (*AllocHolder::create_node(try_emplace_t(), boost::forward(key), boost::forward(args)...), data); @@ -1055,10 +1055,10 @@ class tree 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;\ + const typename remove_cvref::type & k = key;\ 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->icont().insert_unique_commit\ (*AllocHolder::create_node(try_emplace_t(), boost::forward(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N), data);\ diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index dc4aca3..1458878 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -842,12 +842,14 @@ class flat_map //! //! 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 + inline BOOST_CONTAINER_DOC1ST + (std::pair + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I std::pair + >::type) insert_or_assign(BOOST_FWD_REF(K) k, BOOST_FWD_REF(M) obj) { return dtl::force_copy< std::pair > @@ -1086,6 +1088,61 @@ class flat_map (hint), boost::move(k), boost::forward(args)...).first); } + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! 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 search time plus linear insertion time in case the key is not present. + template + inline BOOST_CONTAINER_DOC1ST + (std::pair + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I std::pair + >::type) + try_emplace(BOOST_FWD_REF(K) k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy< std::pair > + (m_flat_tree.try_emplace(impl_const_iterator(), boost::forward(k), boost::forward(args)...)); + } + + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! 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. Linear insertion time in case no equivalent key is present. + template + inline BOOST_CONTAINER_DOC1ST + ( iterator + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I iterator + >::type) //transparent + try_emplace(const_iterator hint, BOOST_FWD_REF(K) k, BOOST_FWD_REF(Args)... args) + { + return dtl::force_copy + (m_flat_tree.try_emplace(dtl::force_copy + (hint), boost::forward(k), boost::forward(args)...).first); + } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_FLAT_MAP_EMPLACE_CODE(N) \ @@ -1125,6 +1182,31 @@ class flat_map inline iterator try_emplace(const_iterator hint, BOOST_RV_REF(key_type) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ { return dtl::force_copy(m_flat_tree.try_emplace\ (dtl::force_copy(hint), boost::move(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N).first); }\ + \ + template \ + typename dtl::enable_if_c< \ + dtl::is_transparent::value && \ + !dtl::is_convertible::value && \ + !dtl::is_convertible::value \ + BOOST_MOVE_I std::pair \ + >::type \ + try_emplace(BOOST_FWD_REF(K) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ + { \ + return dtl::force_copy< std::pair > \ + (m_flat_tree.try_emplace(impl_const_iterator() BOOST_MOVE_I boost::forward(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N)); \ + } \ + \ + template \ + typename dtl::enable_if_transparent< key_compare \ + BOOST_MOVE_I K \ + BOOST_MOVE_I iterator \ + >::type \ + try_emplace(const_iterator hint BOOST_MOVE_I BOOST_FWD_REF(K) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ + { \ + return dtl::force_copy \ + (m_flat_tree.try_emplace(dtl::force_copy \ + (hint) BOOST_MOVE_I boost::forward(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 @@ -1363,12 +1445,12 @@ class flat_map //! Returns: Returns the number of erased elements. template inline BOOST_CONTAINER_DOC1ST - (size_type - , typename dtl::enable_if_c< - dtl::is_transparent::value && //transparent - !dtl::is_convertible::value && //not convertible to iterator - !dtl::is_convertible::value //not convertible to const_iterator - BOOST_MOVE_I size_type>::type) + (size_type + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I size_type>::type) erase(BOOST_FWD_REF(K) x) { return m_flat_tree.erase_unique(x); } diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index aab3f69..9944350 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -800,42 +800,6 @@ class map { return this->base_t::emplace_hint_unique(p, boost::forward(x)); } -/* - //! 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. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - inline iterator insert(const_iterator p, BOOST_RV_REF(nonconst_value_type) 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. - //! p is a hint pointing to where the insert should start to search. - //! - //! Returns: An iterator pointing to the element with key equivalent - //! to the key of x. - //! - //! Complexity: Logarithmic in general, but amortized constant if t - //! is inserted right before p. - inline iterator insert(const_iterator p, BOOST_RV_REF(movable_value_type) 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. - //! - //! Returns: An iterator pointing to the element with key equivalent to the key of x. - //! - //! Complexity: Logarithmic. - inline iterator insert(const_iterator p, const nonconst_value_type& x) - { return this->try_emplace(p, x.first, x.second); } - - -*/ //! Requires: first, last are not iterators into *this. //! //! Effects: inserts each element from the range [first,last) if and only @@ -978,6 +942,54 @@ class map inline 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; } + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! 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 search time plus linear insertion time in case the key is not present. + template + inline BOOST_CONTAINER_DOC1ST + (std::pair + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I std::pair + >::type) + try_emplace(BOOST_FWD_REF(K) k, BOOST_FWD_REF(Args)... args) + { return this->base_t::try_emplace(const_iterator(), boost::forward(k), boost::forward(args)...); } + + //! Precondition: This overload is available only if key_compare::is_transparent exists. + //! + //! 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. Linear insertion time in case no equivalent key is present. + template + inline BOOST_CONTAINER_DOC1ST + ( iterator + , typename dtl::enable_if_transparent< key_compare + BOOST_MOVE_I K + BOOST_MOVE_I iterator + >::type) //transparent + try_emplace(const_iterator hint, BOOST_FWD_REF(K) k, BOOST_FWD_REF(Args)... args) + { return this->base_t::try_emplace(hint, boost::forward(k), boost::forward(args)...).first; } + #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_CONTAINER_MAP_EMPLACE_CODE(N) \ @@ -1004,6 +1016,24 @@ class map BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ inline 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; }\ + \ + template \ + typename dtl::enable_if_c< \ + dtl::is_transparent::value && \ + !dtl::is_convertible::value && \ + !dtl::is_convertible::value \ + BOOST_MOVE_I std::pair \ + >::type \ + try_emplace(BOOST_FWD_REF(K) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ + { return this->base_t::try_emplace(const_iterator() BOOST_MOVE_I boost::forward(k) BOOST_MOVE_I##N BOOST_MOVE_FWD##N); } \ + \ + template \ + typename dtl::enable_if_transparent< key_compare \ + BOOST_MOVE_I K \ + BOOST_MOVE_I iterator \ + >::type \ + try_emplace(const_iterator hint BOOST_MOVE_I BOOST_FWD_REF(K) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N) \ + { return this->base_t::try_emplace(hint BOOST_MOVE_I boost::forward(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/flat_map_test.cpp b/test/flat_map_test.cpp index fcfcbfb..ec6d104 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -274,142 +274,6 @@ struct get_real_stored_allocator > typedef typename flat_multimap::impl_stored_allocator_type type; }; -bool test_heterogeneous_lookups() -{ - BOOST_CONTAINER_STATIC_ASSERT((dtl::is_transparent::value)); - { - typedef flat_map map_t; - typedef flat_multimap mmap_t; - typedef map_t::value_type value_type; - - map_t map1; - mmap_t 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; - - 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); - - //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; - - //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; - - //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; - - //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 flat_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; -} - // An ordered sequence of std:pair is also ordered by std::pair::first. struct with_lookup_by_first { @@ -486,7 +350,15 @@ int main() return 1; } - if (!test_heterogeneous_lookups()) + if (!test::test_heterogeneous_lookup + < flat_map + , flat_multimap + >()) + return 1; + + if (!test::test_heterogeneous_insert + < flat_map + >()) return 1; if (!test_heterogeneous_lookup_by_partial_key()) diff --git a/test/map_test.cpp b/test/map_test.cpp index c0fac00..76db5ad 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -192,6 +192,33 @@ bool node_type_test() if(dst.size() != 5) return false; } + { + typedef map map_t; + typedef multimap mmap_t; + + map_t map1; + mmap_t mmap1; + + //extract + map1.clear(); + map1.try_emplace(1, 'a'); + mmap1.clear(); + mmap1.emplace(1, 'a'); + mmap1.emplace(1, 'b'); + + if (!map1.extract(1)) + return false; + if (map1.extract(1)) + return false; + + if (!mmap1.extract(1)) + return false; + if (!mmap1.extract(1)) + return false; + if (mmap1.extract(1)) + return false; + } + return true; } @@ -259,161 +286,6 @@ void test_merge_from_different_comparison() map1.merge(map2); } -bool test_heterogeneous_lookups() -{ - { - typedef map map_t; - typedef multimap mmap_t; - typedef map_t::value_type value_type; - - map_t map1; - mmap_t 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; - - 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); - - //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; - - //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; - - //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; - - //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; - - //extract - map1.clear(); - map1.insert(value_type(1, 'a')); - mmap1.clear(); - mmap1.insert(value_type(1, 'a')); - mmap1.insert(value_type(1, 'b')); - - const test::non_copymovable_int extract_me(1); - - if (!map1.extract(extract_me)) - return false; - if (map1.extract(extract_me)) - return false; - - if (!mmap1.extract(extract_me)) - return false; - if (!mmap1.extract(extract_me)) - return false; - if (mmap1.extract(extract_me)) - 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; -} - bool constructor_template_auto_deduction_test() { @@ -518,6 +390,7 @@ bool constructor_template_auto_deduction_test() int main () { + using namespace boost::container::test; //Recursive container instantiation { map map_; @@ -678,7 +551,15 @@ int main () test::test_merge_from_different_comparison(); - if(!test::test_heterogeneous_lookups()) + if (!test::test_heterogeneous_lookup + < map + , multimap + >()) + return 1; + + if (!test::test_heterogeneous_insert + < map + >()) return 1; //////////////////////////////////// diff --git a/test/map_test.hpp b/test/map_test.hpp index cdfd1cb..d2f3ec8 100644 --- a/test/map_test.hpp +++ b/test/map_test.hpp @@ -1542,6 +1542,165 @@ bool instantiate_constructors() return true; } + +template +bool test_heterogeneous_lookup() +{ + { + typedef IntMapType map_t; + typedef IntMultimapType mmap_t; + typedef typename map_t::value_type value_type; + + map_t map1; + const map_t &cmap1 = map1; + + 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; + + mmap_t mmap1; + const mmap_t &cmmap1 = mmap1; + + 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); + + //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; + + //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; + + //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; + + //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; + } + + return true; +} + +template +bool test_heterogeneous_insert() +{ + { + typedef MovableIntMapType map_t; + + map_t map1; + const map_t &cmap1 = map1; + + //insert_or_assign + if(!map1.insert_or_assign(1, 'e').second) + return false; + if (cmap1.find(1)->second != 'e') + return false; + if(map1.insert_or_assign(1, 'b').second) + return false; + if (cmap1.find(1)->second != 'b') + return false; + + //insert_or_assign with hint + if(map1.find(2) != map1.end()) + return false; + typename map_t::iterator i = map1.insert_or_assign(map1.begin(), 2, 'f'); + if(i != map1.insert_or_assign(map1.end(), 2, 'g')) + return false; + if (cmap1.find(2)->second != 'g') + return false; + + //try_emplace + map1.clear(); + if(!map1.try_emplace(1, 'a').second) + return false; + if (cmap1.find(1)->second != 'a') + return false; + if( map1.try_emplace(1, 'b').second) + return false; + if (cmap1.find(1)->second != 'a') + return false; + + //try_emplace with hint + i = map1.try_emplace(map1.end(), 2, 'c'); + if (cmap1.find(2)->second != 'c') + return false; + if (i != map1.try_emplace(map1.begin(), 2, 'd')) + return false; + if (cmap1.find(2)->second != 'c') + return false; + } + return true; +} + } //namespace test{ } //namespace container { } //namespace boost{