From 854a5aa3c3c9564477b134d2dd470a53c1cd7f48 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 21 Dec 2021 09:13:38 -0800 Subject: [PATCH 1/5] Add transparent test support for multimap's `erase()` --- test/unordered/transparent_tests.cpp | 65 +++++++++++++++++++++------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 9cf3eda6..64f0f88f 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -554,7 +554,7 @@ typedef boost::unordered_map c; transparent_unordered_map map; @@ -563,7 +563,8 @@ transparent_unordered_map::iterator erase_overload_compile_test() return map.erase(c); } -transparent_unordered_map::const_iterator erase_const_overload_compile_test() +transparent_unordered_map::const_iterator +map_erase_const_overload_compile_test() { convertible_to_const_iterator c; transparent_unordered_map map; @@ -572,6 +573,29 @@ transparent_unordered_map::const_iterator erase_const_overload_compile_test() return map.erase(c); } +typedef boost::unordered_multimap + transparent_unordered_multimap; + +transparent_unordered_multimap::iterator multimap_erase_overload_compile_test() +{ + convertible_to_iterator c; + transparent_unordered_multimap map; + transparent_unordered_multimap::iterator pos = map.begin(); + pos = c; + return map.erase(c); +} + +transparent_unordered_multimap::const_iterator +multimap_erase_const_overload_compile_test() +{ + convertible_to_const_iterator c; + transparent_unordered_multimap map; + transparent_unordered_multimap::const_iterator pos = map.begin(); + pos = c; + return map.erase(c); +} + template void test_transparent_erase() { count_reset(); @@ -585,18 +609,20 @@ template void test_transparent_erase() BOOST_TEST_EQ(num_erased, 0); BOOST_TEST_EQ(key::count_, 0); - map[key(0)] = 1337; - map[key(1)] = 1338; - map[key(2)] = 1339; + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); - BOOST_TEST_EQ(map.size(), 3); BOOST_TEST(map.find(0) != map.end()); - int const expected_key_count = static_cast(2 * map.size()); - BOOST_TEST_EQ(key::count_, expected_key_count); + int const expected_key_count = key::count_; + int const expected_num_erased = static_cast(map.size() - 2); num_erased = map.erase(0); - BOOST_TEST_EQ(num_erased, 1); + BOOST_TEST_EQ(num_erased, expected_num_erased); BOOST_TEST_EQ(map.size(), 2); BOOST_TEST(map.find(0) == map.end()); @@ -620,20 +646,23 @@ template void test_non_transparent_erase() BOOST_TEST_EQ(num_erased, 0); BOOST_TEST_EQ(key::count_, 1); - map[key(0)] = 1337; - map[key(1)] = 1338; - map[key(2)] = 1339; + map.insert(std::make_pair(0, 1337)); + map.insert(std::make_pair(1, 1338)); + map.insert(std::make_pair(2, 1339)); + map.insert(std::make_pair(0, 1340)); + map.insert(std::make_pair(0, 1341)); + map.insert(std::make_pair(0, 1342)); + + int const expected_num_erased = static_cast(map.size() - 2); - BOOST_TEST_EQ(map.size(), 3); BOOST_TEST(map.find(0) != map.end()); - int key_count = 2 + static_cast(2 * map.size()); - BOOST_TEST_EQ(key::count_, key_count); + int key_count = key::count_; num_erased = map.erase(0); ++key_count; BOOST_TEST_EQ(key::count_, key_count); - BOOST_TEST_EQ(num_erased, 1); + BOOST_TEST_EQ(num_erased, expected_num_erased); BOOST_TEST_EQ(map.size(), 2); BOOST_TEST(map.find(0) == map.end()); @@ -811,6 +840,7 @@ void test_unordered_multimap() test_transparent_find(); test_transparent_equal_range(); + test_transparent_erase(); } { @@ -821,6 +851,7 @@ void test_unordered_multimap() test_non_transparent_find(); test_non_transparent_equal_range(); + test_non_transparent_erase(); } { @@ -831,6 +862,7 @@ void test_unordered_multimap() test_non_transparent_find(); test_non_transparent_equal_range(); + test_non_transparent_erase(); } { @@ -841,6 +873,7 @@ void test_unordered_multimap() test_non_transparent_find(); test_non_transparent_equal_range(); + test_non_transparent_erase(); } } From 85cb09ae6de04a9a09b4d93bc88d9be588793db4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 21 Dec 2021 09:20:40 -0800 Subject: [PATCH 2/5] Add `erase_key_equiv_impl()` member function --- include/boost/unordered/detail/implementation.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index e1cfc2e7..23c4314a 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -3800,14 +3800,16 @@ namespace boost { // // no throw - std::size_t erase_key_equiv(const_key_type& k) + template + std::size_t erase_key_equiv_impl(KeyEqual const& key_eq, Key const& k) { if (!this->size_) return 0; - std::size_t key_hash = this->hash(k); + std::size_t key_hash = policy::apply_hash(this->hash_function(), k); std::size_t bucket_index = this->hash_to_bucket(key_hash); - link_pointer prev = this->find_previous_node(k, bucket_index); + link_pointer prev = + this->find_previous_node_impl(key_eq, k, bucket_index); if (!prev) return 0; @@ -3825,6 +3827,11 @@ namespace boost { return deleted_count; } + std::size_t erase_key_equiv(const_key_type& k) + { + return this->erase_key_equiv_impl(this->key_eq(), k); + } + link_pointer erase_nodes_equiv(node_pointer i, node_pointer j) { std::size_t bucket_index = this->node_bucket(i); From ff4d25d45404a8c7983133193909dd2ede761ce7 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 21 Dec 2021 09:21:51 -0800 Subject: [PATCH 3/5] Add `transparent_non_iterable` type trait for usage in `erase()` / `extract()` SFINAE --- include/boost/unordered/detail/implementation.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 23c4314a..935cbb30 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -718,6 +719,19 @@ namespace boost { is_transparent::value && is_transparent::value; }; + template struct transparent_non_iterable + { + typedef typename UnorderedMap::hasher hash; + typedef typename UnorderedMap::key_equal key_equal; + typedef typename UnorderedMap::iterator iterator; + typedef typename UnorderedMap::const_iterator const_iterator; + + static bool const value = + are_transparent::value && + !boost::is_convertible::value && + !boost::is_convertible::value; + }; + //////////////////////////////////////////////////////////////////////////// // Explicitly call a destructor From 1c6c085127170fe2ad7ac4c285938873ba7d0e20 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 21 Dec 2021 09:26:27 -0800 Subject: [PATCH 4/5] Update `unordered_map` to use singular type trait for `erase()` / `extract()` SFINAE --- include/boost/unordered/unordered_map.hpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 82cb7f80..2271ef7a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -432,9 +431,7 @@ namespace boost { template typename boost::enable_if_c< - detail::are_transparent::value && - !boost::is_convertible::value && - !boost::is_convertible::value, + detail::transparent_non_iterable::value, node_type>::type extract(BOOST_FWD_REF(Key) k) { @@ -724,9 +721,7 @@ namespace boost { template typename boost::enable_if_c< - detail::are_transparent::value && - !boost::is_convertible::value && - !boost::is_convertible::value, + detail::transparent_non_iterable::value, size_type>::type erase(BOOST_FWD_REF(Key) k) { From 57054f7451b402fbb273b3ad410d02e41124d7a0 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 21 Dec 2021 09:26:48 -0800 Subject: [PATCH 5/5] Implement heterogeneous `erase()` for multimap --- include/boost/unordered/unordered_map.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 2271ef7a..00830621 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1399,6 +1399,16 @@ namespace boost { size_type erase(const key_type&); iterator erase(const_iterator, const_iterator); + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + size_type>::type + erase(BOOST_FWD_REF(Key) k) + { + return table_.erase_key_equiv_impl( + this->key_eq(), boost::forward(k)); + } + BOOST_UNORDERED_DEPRECATED("Use erase instead") void quick_erase(const_iterator it) { erase(it); } BOOST_UNORDERED_DEPRECATED("Use erase instead")