From ee1515189bd7545e0089752a515b4647c2a57230 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 14 Nov 2022 15:16:06 -0800 Subject: [PATCH 01/24] Add transparent tests for unordered_map's try_emplace() --- test/unordered/transparent_tests.cpp | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 9852fa84..8d74fc2a 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1478,6 +1478,83 @@ template void test_map_non_transparent_extract() #endif } +template void test_map_transparent_try_emplace() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + 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 key_count = key::count_; + + std::pair r = map.try_emplace(0, 7331); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_NOT(r.second); + BOOST_TEST_EQ(key::count_, key_count); + + r = map.try_emplace(4, 7331); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + + iterator p = map.try_emplace(map.cbegin(), 0, 7331); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(key::count_, key_count); + + p = map.try_emplace(map.begin(), 5, 7331); + BOOST_TEST(p == map.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_try_emplace() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + 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 key_count = key::count_; + + std::pair r = map.try_emplace(0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_NOT(r.second); + + key_count = key::count_; + r = map.try_emplace(4, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + + key_count = key::count_; + iterator p = map.try_emplace(map.cbegin(), 0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p == map.find(0)); + + key_count = key::count_; + p = map.try_emplace(map.begin(), 5, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p == map.find(5)); +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1646,6 +1723,7 @@ void test_unordered_map() test_map_transparent_equal_range(); test_map_transparent_erase(); test_map_transparent_extract(); + test_map_transparent_try_emplace(); } { @@ -1658,6 +1736,7 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); } { @@ -1671,6 +1750,7 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); } { @@ -1684,6 +1764,7 @@ void test_unordered_map() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_try_emplace(); } } From bf2b5217892f87f7ad117dcec491d38a7a9507dd Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 14 Nov 2022 15:17:32 -0800 Subject: [PATCH 02/24] Add transparent try_emplace() --- .../boost/unordered/unordered_flat_map.hpp | 23 +++++ include/boost/unordered/unordered_map.hpp | 95 +++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index ce09af90..0d38f145 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -337,6 +337,17 @@ namespace boost { return table_.try_emplace(std::move(key), std::forward(args)...); } + template + BOOST_FORCEINLINE typename std::enable_if< + boost::unordered::detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(K&& key, Args&&... args) + { + return table_.try_emplace( + std::forward(key), std::forward(args)...); + } + template BOOST_FORCEINLINE iterator try_emplace( const_iterator, key_type const& key, Args&&... args) @@ -352,6 +363,18 @@ namespace boost { .first; } + template + BOOST_FORCEINLINE typename std::enable_if< + boost::unordered::detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator, K&& key, Args&&... args) + { + return table_ + .try_emplace(std::forward(key), std::forward(args)...) + .first; + } + BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); } BOOST_FORCEINLINE void erase(const_iterator pos) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 9d80d743..3e07ed5e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -486,6 +486,16 @@ namespace boost { boost::move(k), boost::forward(args)...); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(Key&& k, Args&&... args) + { + return table_.try_emplace_unique( + boost::forward(k), boost::forward(args)...); + } + template iterator try_emplace( const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args) @@ -502,6 +512,16 @@ namespace boost { hint, boost::move(k), boost::forward(args)...); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, Key&& k, Args&&... args) + { + return table_.try_emplace_hint_unique( + hint, boost::forward(k), boost::forward(args)...); + } + #else // In order to make this a template, this handles both: @@ -582,6 +602,43 @@ namespace boost { boost::forward(a1), boost::forward(a2))); } + // try_emplace(Key&&, Args&&...) + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_unique( + boost::forward(k), boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace( + BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_unique(boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0, + BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_unique(boost::forward(k), + boost::unordered::detail::create_emplace_args(boost::forward(a0), + boost::forward(a1), boost::forward(a2))); + } + // try_emplace(const_iterator hint, key const&, Args&&...) template @@ -640,6 +697,44 @@ namespace boost { boost::forward(a1), boost::forward(a2))); } + // try_emplace(const_iterator hint, Key&&, Args&&...) + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace( + const_iterator hint, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args( + boost::forward(a0), boost::forward(a1))); + } + + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k, + BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k), + boost::unordered::detail::create_emplace_args(boost::forward(a0), + boost::forward(a1), boost::forward(a2))); + } + #define BOOST_UNORDERED_TRY_EMPLACE(z, n, _) \ \ template \ From 1ede59e662c1a7bcc2626bbdc587a69cc5eb57dd Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 09:52:03 -0800 Subject: [PATCH 03/24] Improve naming in are_transparent --- include/boost/unordered/detail/type_traits.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/detail/type_traits.hpp b/include/boost/unordered/detail/type_traits.hpp index 3fe2f404..fd37a8e4 100644 --- a/include/boost/unordered/detail/type_traits.hpp +++ b/include/boost/unordered/detail/type_traits.hpp @@ -53,10 +53,10 @@ namespace boost { { }; - template struct are_transparent + template struct are_transparent { static bool const value = - is_transparent::value && is_transparent::value; + is_transparent::value && is_transparent::value; }; template struct transparent_non_iterable From 7709950111857fcdd94a237d65aeb5bd6bddb8f9 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 09:52:37 -0800 Subject: [PATCH 04/24] Add transparent insert_or_assign() tests --- test/unordered/transparent_tests.cpp | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 8d74fc2a..9de531ae 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1555,6 +1555,87 @@ template void test_map_non_transparent_try_emplace() BOOST_TEST(p == map.find(5)); } +template void test_map_transparent_insert_or_assign() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + 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 key_count = key::count_; + + std::pair r = map.insert_or_assign(0, 7331); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_EQ(r.first->second, 7331); + BOOST_TEST_NOT(r.second); + BOOST_TEST_EQ(key::count_, key_count); + + r = map.insert_or_assign(4, 7331); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + + iterator p = map.insert_or_assign(map.cbegin(), 0, 1111); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(p->second, 1111); + BOOST_TEST_EQ(key::count_, key_count); + + p = map.insert_or_assign(map.begin(), 5, 7331); + BOOST_TEST(p == map.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_insert_or_assign() +{ + count_reset(); + + typedef typename UnorderedMap::iterator iterator; + + UnorderedMap map; + + 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 key_count = key::count_; + + std::pair r = map.insert_or_assign(0, 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(r.first == map.find(0)); + BOOST_TEST_EQ(r.first->second, 7331); + BOOST_TEST_NOT(r.second); + + key_count = key::count_; + r = map.insert_or_assign(4, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(r.first == map.find(4)); + BOOST_TEST(r.second); + + key_count = key::count_; + iterator p = map.insert_or_assign(map.cbegin(), 0, 1111); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p == map.find(0)); + BOOST_TEST_EQ(p->second, 1111); + + key_count = key::count_; + p = map.insert_or_assign(map.begin(), 5, 7331); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p == map.find(5)); +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1724,6 +1805,7 @@ void test_unordered_map() test_map_transparent_erase(); test_map_transparent_extract(); test_map_transparent_try_emplace(); + test_map_transparent_insert_or_assign(); } { @@ -1737,6 +1819,7 @@ void test_unordered_map() test_map_non_transparent_erase(); test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); } { @@ -1751,6 +1834,7 @@ void test_unordered_map() test_map_non_transparent_erase(); test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); } { @@ -1765,6 +1849,7 @@ void test_unordered_map() test_map_non_transparent_erase(); test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); + test_map_non_transparent_insert_or_assign(); } } From 01d508b6affd1977f36cad192a6baa603082bd27 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 09:53:02 -0800 Subject: [PATCH 05/24] Improve naming in insert_or_assign() --- .../boost/unordered/unordered_flat_map.hpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 0d38f145..4c9a845b 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -278,24 +278,25 @@ namespace boost { template std::pair insert_or_assign(key_type const& key, M&& obj) { - auto iter_bool_pair = table_.try_emplace(key, std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + auto ibp = table_.try_emplace(key, std::forward(obj)); + if (ibp.second) { + return ibp; } - iter_bool_pair.first->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; } template std::pair insert_or_assign(key_type&& key, M&& obj) { - auto iter_bool_pair = + auto ibp = table_.try_emplace(std::move(key), std::forward(obj)); - if (iter_bool_pair.second) { - return iter_bool_pair; + if (ibp.second) { + return ibp; } - iter_bool_pair.first->second = std::forward(obj); - return iter_bool_pair; + ibp.first->second = std::forward(obj); + return ibp; + } } template From 0a879c10632248363232bc5cc1c71104ae274da0 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 09:53:18 -0800 Subject: [PATCH 06/24] Implement transparent insert_or_assign() --- .../boost/unordered/unordered_flat_map.hpp | 26 +++++++++++++++++-- include/boost/unordered/unordered_map.hpp | 22 ++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 4c9a845b..16312a9e 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -289,14 +289,26 @@ namespace boost { template std::pair insert_or_assign(key_type&& key, M&& obj) { - auto ibp = - table_.try_emplace(std::move(key), std::forward(obj)); + auto ibp = table_.try_emplace(std::move(key), std::forward(obj)); if (ibp.second) { return ibp; } ibp.first->second = std::forward(obj); return ibp; } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + std::pair >::type + insert_or_assign(K&& k, M&& obj) + { + auto ibp = table_.try_emplace(std::forward(k), std::forward(obj)); + if (ibp.second) { + return ibp; + } + ibp.first->second = std::forward(obj); + return ibp; } template @@ -312,6 +324,16 @@ namespace boost { .first; } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + iterator>::type + insert_or_assign(const_iterator, K&& k, M&& obj) + { + return this->insert_or_assign(std::forward(k), std::forward(obj)) + .first; + } + template BOOST_FORCEINLINE std::pair emplace(Args&&... args) { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 3e07ed5e..6d81a3f8 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -801,6 +801,16 @@ namespace boost { boost::move(k), boost::forward(obj)); } + template + typename boost::enable_if_c< + detail::are_transparent::value, + std::pair >::type + insert_or_assign(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + return table_.insert_or_assign_unique( + boost::forward(k), boost::forward(obj)); + } + template iterator insert_or_assign( const_iterator, key_type const& k, BOOST_FWD_REF(M) obj) @@ -817,6 +827,18 @@ namespace boost { .first; } + template + typename boost::enable_if_c< + detail::are_transparent::value, iterator>::type + insert_or_assign( + const_iterator, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) + { + return table_ + .insert_or_assign_unique( + boost::forward(k), boost::forward(obj)) + .first; + } + iterator erase(iterator); iterator erase(const_iterator); size_type erase(const key_type&); From b85e17085fc5c695102b7a24643893af3678acff Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 15:38:02 -0800 Subject: [PATCH 07/24] Add tests for transparent subscript operator --- test/unordered/transparent_tests.cpp | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 9de531ae..03c8d2f8 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1636,6 +1636,51 @@ template void test_map_non_transparent_insert_or_assign() BOOST_TEST(p == map.find(5)); } +template void test_map_transparent_subscript() +{ + count_reset(); + + UnorderedMap map; + + map[0] = 1337; + map[1] = 1338; + map[2] = 1339; + map[0] = 1340; + map[0] = 1341; + map[0] = 1342; + + int key_count = key::count_; + + map[0] = 7331; + BOOST_ASSERT(BOOST_TEST_EQ(key::count_, key_count)); + + map[4] = 7331; + BOOST_TEST_EQ(key::count_, key_count + 1); +} + +template void test_map_non_transparent_subscript() +{ + count_reset(); + + UnorderedMap map; + + map[0] = 1337; + map[1] = 1338; + map[2] = 1339; + map[0] = 1340; + map[0] = 1341; + map[0] = 1342; + + int key_count = key::count_; + + map[0] = 7331; + BOOST_ASSERT(BOOST_TEST_EQ(key::count_, key_count + 1)); + + key_count = key::count_; + map[4] = 7331; + BOOST_TEST_EQ(key::count_, key_count + 2); +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1806,6 +1851,7 @@ void test_unordered_map() test_map_transparent_extract(); test_map_transparent_try_emplace(); test_map_transparent_insert_or_assign(); + test_map_transparent_subscript(); } { @@ -1820,6 +1866,7 @@ void test_unordered_map() test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); } { @@ -1835,6 +1882,7 @@ void test_unordered_map() test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); } { @@ -1850,6 +1898,7 @@ void test_unordered_map() test_map_non_transparent_extract(); test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); + test_map_non_transparent_subscript(); } } From dfbff823a9397dfeb8dcee42c1175b28e8cb6f93 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 15 Nov 2022 15:39:15 -0800 Subject: [PATCH 08/24] Add transparent subscript --- include/boost/unordered/unordered_flat_map.hpp | 9 +++++++++ include/boost/unordered/unordered_map.hpp | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 16312a9e..d7f4e6e7 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -483,6 +483,15 @@ namespace boost { return table_.try_emplace(std::move(key)).first->second; } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type&>::type + operator[](K&& key) + { + return table_.try_emplace(std::forward(key)).first->second; + } + BOOST_FORCEINLINE size_type count(key_type const& key) const { auto pos = table_.find(key); diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 6d81a3f8..315da4cc 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -973,6 +973,10 @@ namespace boost { mapped_type& operator[](const key_type&); mapped_type& operator[](BOOST_RV_REF(key_type)); + template + typename boost::enable_if_c::value, + mapped_type&>::type + operator[](BOOST_FWD_REF(Key) k); mapped_type& at(const key_type&); mapped_type const& at(const key_type&) const; @@ -2215,6 +2219,15 @@ namespace boost { return table_.try_emplace_unique(boost::move(k)).first->second; } + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type&>::type + unordered_map::operator[](BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_unique(boost::forward(k)).first->second; + } + template typename unordered_map::mapped_type& unordered_map::at(const key_type& k) From 1f4244ec275f52fd8cf275099fdd232e9c256a2b Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 16 Nov 2022 13:30:35 -0800 Subject: [PATCH 09/24] Add tests for transparent at() --- test/unordered/transparent_tests.cpp | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index 03c8d2f8..effe08b5 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1681,6 +1681,67 @@ template void test_map_non_transparent_subscript() BOOST_TEST_EQ(key::count_, key_count + 2); } +template void test_map_transparent_at() +{ + count_reset(); + + UnorderedMap map; + + 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 key_count = key::count_; + + map.at(0) = 7331; + BOOST_TEST_EQ(key::count_, key_count); + + BOOST_TEST_THROWS(map.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count); + + UnorderedMap const& m = map; + BOOST_TEST_EQ(m.at(0), 7331); + BOOST_TEST_EQ(key::count_, key_count); + + BOOST_TEST_THROWS(m.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count); +} + +template void test_map_non_transparent_at() +{ + count_reset(); + + UnorderedMap map; + + 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 key_count = key::count_; + + map.at(0) = 7331; + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + BOOST_TEST_THROWS(map.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + UnorderedMap const& m = map; + BOOST_TEST_EQ(m.at(0), 7331); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + BOOST_TEST_THROWS(m.at(4), std::out_of_range); + BOOST_TEST_EQ(key::count_, key_count + 1); +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1852,6 +1913,7 @@ void test_unordered_map() test_map_transparent_try_emplace(); test_map_transparent_insert_or_assign(); test_map_transparent_subscript(); + test_map_transparent_at(); } { @@ -1867,6 +1929,7 @@ void test_unordered_map() test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); + test_map_non_transparent_at(); } { @@ -1883,6 +1946,7 @@ void test_unordered_map() test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); + test_map_non_transparent_at(); } { @@ -1899,6 +1963,7 @@ void test_unordered_map() test_map_non_transparent_try_emplace(); test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); + test_map_non_transparent_at(); } } From 0e980577b0345bb516a436a5d913b8ed23083939 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 16 Nov 2022 14:00:22 -0800 Subject: [PATCH 10/24] Add transparent at() --- .../boost/unordered/unordered_flat_map.hpp | 28 +++++++++++ include/boost/unordered/unordered_map.hpp | 46 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index d7f4e6e7..16d4f3bd 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -473,6 +473,34 @@ namespace boost { std::out_of_range("key was not found in unordered_flat_map")); } + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type&>::type + at(K&& key) + { + auto pos = table_.find(std::forward(key)); + if (pos != table_.end()) { + return pos->second; + } + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); + } + + template + typename std::enable_if< + boost::unordered::detail::are_transparent::value, + mapped_type const&>::type + at(K&& key) const + { + auto pos = table_.find(std::forward(key)); + if (pos != table_.end()) { + return pos->second; + } + boost::throw_exception( + std::out_of_range("key was not found in unordered_flat_map")); + } + BOOST_FORCEINLINE mapped_type& operator[](key_type const& key) { return table_.try_emplace(key).first->second; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 315da4cc..849adefa 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -973,13 +973,23 @@ namespace boost { mapped_type& operator[](const key_type&); mapped_type& operator[](BOOST_RV_REF(key_type)); + template typename boost::enable_if_c::value, mapped_type&>::type operator[](BOOST_FWD_REF(Key) k); + mapped_type& at(const key_type&); mapped_type const& at(const key_type&) const; + template + typename boost::enable_if_c::value, + mapped_type&>::type at(BOOST_FWD_REF(Key) k); + + template + typename boost::enable_if_c::value, + mapped_type const&>::type at(BOOST_FWD_REF(Key) k) const; + // bucket interface size_type bucket_count() const BOOST_NOEXCEPT @@ -2260,6 +2270,42 @@ namespace boost { std::out_of_range("Unable to find key in unordered_map.")); } + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type&>::type + unordered_map::at(BOOST_FWD_REF(Key) k) + { + typedef typename table::node_pointer node_pointer; + + if (table_.size_) { + node_pointer p = table_.find_node(boost::forward(k)); + if (p) + return p->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + + template + template + typename boost::enable_if_c::value, + typename unordered_map::mapped_type const&>::type + unordered_map::at(BOOST_FWD_REF(Key) k) const + { + typedef typename table::node_pointer node_pointer; + + if (table_.size_) { + node_pointer p = table_.find_node(boost::forward(k)); + if (p) + return p->value().second; + } + + boost::throw_exception( + std::out_of_range("Unable to find key in unordered_map.")); + } + template typename unordered_map::size_type unordered_map::bucket_size(size_type n) const From 8b1dcd3da3ad6dd8014b9801c7f7d0a5f324a5c9 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 17 Nov 2022 11:38:57 -0800 Subject: [PATCH 11/24] Add tests for transparent bucket() --- test/unordered/transparent_tests.cpp | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index effe08b5..aaa9b78f 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1742,6 +1742,48 @@ template void test_map_non_transparent_at() BOOST_TEST_EQ(key::count_, key_count + 1); } +template void test_map_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedMap map; + + 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 key_count = key::count_; + map.bucket(0); + map.bucket(4); + BOOST_TEST_EQ(key::count_, key_count); +#endif +} + +template void test_map_non_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedMap map; + + 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 key_count = key::count_; + map.bucket(0); + map.bucket(4); + BOOST_TEST_EQ(key::count_, key_count + 2); +#endif +} + #ifndef BOOST_UNORDERED_FOA_TESTS transparent_unordered_set::node_type set_extract_overload_compile_test() { @@ -1890,6 +1932,48 @@ template void test_set_non_transparent_extract() #endif } +template void test_set_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + set.bucket(0); + set.bucket(4); + BOOST_TEST_EQ(key::count_, key_count); +#endif +} + +template void test_set_non_transparent_bucket() +{ +#ifndef BOOST_UNORDERED_FOA_TESTS + count_reset(); + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + set.bucket(0); + set.bucket(4); + BOOST_TEST_EQ(key::count_, key_count + 2); +#endif +} + template struct map_type { #ifdef BOOST_UNORDERED_FOA_TESTS @@ -1914,6 +1998,7 @@ void test_unordered_map() test_map_transparent_insert_or_assign(); test_map_transparent_subscript(); test_map_transparent_at(); + test_map_transparent_bucket(); } { @@ -1930,6 +2015,7 @@ void test_unordered_map() test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } { @@ -1947,6 +2033,7 @@ void test_unordered_map() test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } { @@ -1964,6 +2051,7 @@ void test_unordered_map() test_map_non_transparent_insert_or_assign(); test_map_non_transparent_subscript(); test_map_non_transparent_at(); + test_map_non_transparent_bucket(); } } @@ -1980,6 +2068,7 @@ void test_unordered_multimap() test_map_transparent_equal_range(); test_map_transparent_erase(); test_map_transparent_extract(); + test_map_transparent_bucket(); } { @@ -1993,6 +2082,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } { @@ -2006,6 +2096,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } { @@ -2019,6 +2110,7 @@ void test_unordered_multimap() test_map_non_transparent_equal_range(); test_map_non_transparent_erase(); test_map_non_transparent_extract(); + test_map_non_transparent_bucket(); } } #endif @@ -2043,6 +2135,7 @@ void test_unordered_set() test_set_transparent_erase(); test_set_transparent_equal_range(); test_set_transparent_extract(); + test_set_transparent_bucket(); } { @@ -2055,6 +2148,7 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -2067,6 +2161,7 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -2079,6 +2174,7 @@ void test_unordered_set() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } } @@ -2095,6 +2191,7 @@ void test_unordered_multiset() test_set_transparent_erase(); test_set_transparent_equal_range(); test_set_transparent_extract(); + test_set_transparent_bucket(); } { @@ -2107,6 +2204,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -2120,6 +2218,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } { @@ -2133,6 +2232,7 @@ void test_unordered_multiset() test_set_non_transparent_erase(); test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); + test_set_non_transparent_bucket(); } } #endif From 6c60524fb7878545760a5f16471fe82fbe4d316a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Thu, 17 Nov 2022 11:39:06 -0800 Subject: [PATCH 12/24] Implement transparent bucket() --- include/boost/unordered/unordered_map.hpp | 23 +++++++++++++++++++---- include/boost/unordered/unordered_set.hpp | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 849adefa..6d05471c 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -802,8 +802,7 @@ namespace boost { } template - typename boost::enable_if_c< - detail::are_transparent::value, + typename boost::enable_if_c::value, std::pair >::type insert_or_assign(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) { @@ -828,8 +827,8 @@ namespace boost { } template - typename boost::enable_if_c< - detail::are_transparent::value, iterator>::type + typename boost::enable_if_c::value, + iterator>::type insert_or_assign( const_iterator, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj) { @@ -1009,6 +1008,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return table_.begin(n); @@ -1715,6 +1722,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index a054ed64..9542b492 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -571,6 +571,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); @@ -1212,6 +1220,14 @@ namespace boost { return table_.hash_to_bucket(table_.hash(k)); } + template + typename boost::enable_if_c::value, + size_type>::type + bucket(BOOST_FWD_REF(Key) k) const + { + return table_.hash_to_bucket(table_.hash(boost::forward(k))); + } + local_iterator begin(size_type n) { return local_iterator(table_.begin(n)); From 7572de875c56fc8e5f7eab67188f24672986e95c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 22 Nov 2022 15:38:41 -0800 Subject: [PATCH 13/24] Add transparent insert tests for set containers --- test/unordered/transparent_tests.cpp | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/unordered/transparent_tests.cpp b/test/unordered/transparent_tests.cpp index aaa9b78f..8d1f781b 100644 --- a/test/unordered/transparent_tests.cpp +++ b/test/unordered/transparent_tests.cpp @@ -1974,6 +1974,92 @@ template void test_set_non_transparent_bucket() #endif } +template void test_set_transparent_insert() +{ + count_reset(); + + typedef typename UnorderedSet::iterator iterator; + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + + std::pair p = set.insert(0); + BOOST_TEST(p.first == set.find(0)); + BOOST_TEST_NOT(p.second); + BOOST_TEST_EQ(key::count_, key_count); + + key_count = key::count_; + p = set.insert(4); + BOOST_TEST(p.first == set.find(4)); + BOOST_TEST(p.second); + BOOST_TEST_EQ(key::count_, key_count + 1); + + key_count = key::count_; + iterator pos = set.insert(set.begin(), 0); + BOOST_TEST(pos == set.find(0)); + BOOST_TEST_EQ(key::count_, key_count); + + key_count = key::count_; + pos = set.insert(set.begin(), 5); + BOOST_TEST(pos == set.find(5)); + BOOST_TEST_EQ(key::count_, key_count + 1); + + // check for collisions with insert(iterator, iterator) + // note: this precludes Key from being convertible to an iterator which isn't + // explicitly stated by p2363r3 + // + set.insert(set.begin(), set.end()); +} + +template void test_set_non_transparent_insert() +{ + count_reset(); + + typedef typename UnorderedSet::iterator iterator; + + UnorderedSet set; + + set.insert(0); + set.insert(1); + set.insert(2); + set.insert(0); + set.insert(0); + set.insert(0); + + int key_count = key::count_; + + std::pair p = set.insert(0); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(p.first == set.find(0)); + BOOST_TEST_NOT(p.second); + + key_count = key::count_; + p = set.insert(4); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(p.first == set.find(4)); + BOOST_TEST(p.second); + + key_count = key::count_; + iterator pos = set.insert(set.begin(), 0); + BOOST_TEST_EQ(key::count_, key_count + 1); + BOOST_TEST(pos == set.find(0)); + + key_count = key::count_; + pos = set.insert(set.begin(), 5); + BOOST_TEST_EQ(key::count_, key_count + 2); + BOOST_TEST(pos == set.find(5)); + + set.insert(set.begin(), set.end()); +} + template struct map_type { #ifdef BOOST_UNORDERED_FOA_TESTS @@ -2136,6 +2222,7 @@ void test_unordered_set() test_set_transparent_equal_range(); test_set_transparent_extract(); test_set_transparent_bucket(); + test_set_transparent_insert(); } { @@ -2149,6 +2236,7 @@ void test_unordered_set() test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } { @@ -2162,6 +2250,7 @@ void test_unordered_set() test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } { @@ -2175,6 +2264,7 @@ void test_unordered_set() test_set_non_transparent_equal_range(); test_set_non_transparent_extract(); test_set_non_transparent_bucket(); + test_set_non_transparent_insert(); } } From 7d77f1d4788dc9d82572e734548674167c31919c Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 13 Dec 2022 12:33:07 -0800 Subject: [PATCH 14/24] Add transparent insert() overloads to unordered_[flat]_set --- .../boost/unordered/detail/implementation.hpp | 25 ++++++++++++++++--- .../boost/unordered/unordered_flat_set.hpp | 18 +++++++++++++ include/boost/unordered/unordered_set.hpp | 18 +++++++++++++ 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index d953b313..13351171 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -1477,7 +1477,22 @@ namespace boost { } #endif - } + + template + inline typename boost::allocator_pointer::type + construct_node_from_key(T*, Alloc& alloc, BOOST_FWD_REF(Key) k) + { + return construct_node(alloc, boost::forward(k)); + } + + template + inline typename boost::allocator_pointer::type + construct_node_from_key( + std::pair*, Alloc& alloc, BOOST_FWD_REF(Key) k) + { + return construct_node_pair(alloc, boost::forward(k)); + } + } // namespace func } } } @@ -2640,8 +2655,10 @@ namespace boost { } else { node_allocator_type alloc = node_alloc(); - node_tmp tmp( - detail::func::construct_node_pair(alloc, boost::forward(k)), + value_type* dispatch = BOOST_NULLPTR; + + node_tmp tmp(detail::func::construct_node_from_key( + dispatch, alloc, boost::forward(k)), alloc); if (size_ + 1 > max_load_) { @@ -2660,7 +2677,7 @@ namespace boost { template iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k) { - if (hint.p && this->key_eq()(hint->first, k)) { + if (hint.p && this->key_eq()(extractor::extract(*hint), k)) { return iterator(hint.p, hint.itb); } else { return try_emplace_unique(k).first; diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index 29c53596..1599ba55 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -231,6 +231,15 @@ namespace boost { return table_.insert(std::move(value)); } + template + BOOST_FORCEINLINE typename std::enable_if< + detail::transparent_non_iterable::value, + std::pair >::type + insert(K&& k) + { + return table_.try_emplace(std::forward(k)); + } + BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value) { return table_.insert(value).first; @@ -241,6 +250,15 @@ namespace boost { return table_.insert(std::move(value)).first; } + template + BOOST_FORCEINLINE typename std::enable_if< + detail::transparent_non_iterable::value, + iterator>::type + insert(const_iterator, K&& k) + { + return table_.try_emplace(std::forward(k)).first; + } + template void insert(InputIterator first, InputIterator last) { diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 9542b492..1bd4ba3d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -390,6 +390,15 @@ namespace boost { return this->emplace(boost::move(x)); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + std::pair >::type + insert(BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_unique(boost::forward(k)); + } + iterator insert(const_iterator hint, value_type const& x) { return this->emplace_hint(hint, x); @@ -400,6 +409,15 @@ namespace boost { return this->emplace_hint(hint, boost::move(x)); } + template + typename boost::enable_if_c< + detail::transparent_non_iterable::value, + iterator>::type + insert(const_iterator hint, BOOST_FWD_REF(Key) k) + { + return table_.try_emplace_hint_unique(hint, boost::forward(k)); + } + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) From 3fb516367fdf1d8b6822d655c0184269edfc89f9 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 16 Dec 2022 15:47:40 -0800 Subject: [PATCH 15/24] Add transparent try_emplace() docs to unordered_map --- doc/unordered/unordered_map.adoc | 83 ++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/doc/unordered/unordered_map.adoc b/doc/unordered/unordered_map.adoc index 40e1ba84..7861148b 100644 --- a/doc/unordered/unordered_map.adoc +++ b/doc/unordered/unordered_map.adoc @@ -113,10 +113,14 @@ namespace boost { std::pair xref:#unordered_map_try_emplace[try_emplace](const key_type& k, Args&&... args); template std::pair xref:#unordered_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_map_transparent_try_emplace[try_emplace](K&& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_map_transparent_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); template std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); template @@ -1030,6 +1034,45 @@ Since existing `std::pair` implementations don't support `std::piecewise_constru --- +==== Transparent try_emplace +```c++ +template + std::pair try_emplace(K&& k, Args&&... args) +``` + +Inserts a new node into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +[horizontal] +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] except the `value_type` is constructed using: + ++ +-- +```c++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) +``` + +instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + +Pointers and references to elements are never invalidated. + +If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. + +Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. +-- + +--- + ==== try_emplace with Hint ```c++ template @@ -1044,6 +1087,46 @@ If there is an existing element with key `k` this function does nothing. `hint` is a suggestion to where the element should be inserted. +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_hint] except the `value_type` is constructed using: + ++ +-- +```c++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) +``` + +instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor. + +The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + +Pointers and references to elements are never invalidated. + +If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. + +Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. +-- + +==== Transparent try_emplace with Hint +```c++ +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +``` + +Inserts a new node into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +`hint` is a suggestion to where the element should be inserted. + +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + + [horizontal] Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. From 61aedca94065c2778a583f9bc169a883bdd1ed7d Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 11:08:20 +0100 Subject: [PATCH 16/24] documented P2363 overloads for unordered_map --- doc/unordered/unordered_map.adoc | 175 +++++++++++-------------------- 1 file changed, 63 insertions(+), 112 deletions(-) diff --git a/doc/unordered/unordered_map.adoc b/doc/unordered/unordered_map.adoc index 7861148b..2cc08369 100644 --- a/doc/unordered/unordered_map.adoc +++ b/doc/unordered/unordered_map.adoc @@ -114,32 +114,36 @@ namespace boost { template std::pair xref:#unordered_map_try_emplace[try_emplace](key_type&& k, Args&&... args); template - std::pair xref:#unordered_map_transparent_try_emplace[try_emplace](K&& k, Args&&... args); + std::pair xref:#unordered_map_try_emplace[try_emplace](K&& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); template iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); template - iterator xref:#unordered_map_transparent_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); + iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); template std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); template std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); template iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); template iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); node_type xref:#unordered_map_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_map_extract_by_key[extract](const key_type& k); - template node_type xref:#unordered_map_transparent_extract_by_key[extract](K&& k); + template node_type xref:#unordered_map_extract_by_key[extract](K&& k); insert_return_type xref:#unordered_map_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_map_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_map_erase_by_position[erase](iterator position); iterator xref:#unordered_map_erase_by_position[erase](const_iterator position); size_type xref:#unordered_map_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_map_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_map_erase_by_key[erase](K&& k); iterator xref:#unordered_map_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_map_quick_erase[quick_erase](const_iterator position); void xref:#unordered_map_erase_return_void[erase_return_void](const_iterator position); @@ -191,14 +195,18 @@ namespace boost { // element access mapped_type& xref:#unordered_map_operator[operator[+]+](const key_type& k); mapped_type& xref:#unordered_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_map_operator[operator[+]+](K&& k); mapped_type& xref:#unordered_map_at[at](const key_type& k); const mapped_type& xref:#unordered_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_map_at[at](const K& k); + template const mapped_type& xref:#unordered_map_at[at](const K& k) const; // bucket interface size_type xref:#unordered_map_bucket_count[bucket_count]() const noexcept; size_type xref:#unordered_map_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_map_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_map_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_map_bucket[bucket](const K& k) const; local_iterator xref:#unordered_map_begin_2[begin](size_type n); const_local_iterator xref:#unordered_map_begin_2[begin](size_type n) const; local_iterator xref:#unordered_map_end_2[end](size_type n); @@ -1001,41 +1009,6 @@ template std::pair try_emplace(const key_type& k, Args&&... args); template std::pair try_emplace(key_type&& k, Args&&... args); -``` - -Inserts a new node into the container if there is no existing element with key `k` contained within it. - -If there is an existing element with key `k` this function does nothing. - -[horizontal] -Returns:;; The bool component of the return type is true if an insert took place. + -+ -If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. -Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] except the `value_type` is constructed using: + -+ --- -```c++ -value_type(std::piecewise_construct, - std::forward_as_tuple(boost::forward(k)), - std::forward_as_tuple(boost::forward(args)...)) -``` - -instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor. - -Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. - -Pointers and references to elements are never invalidated. - -If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. - -Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. --- - ---- - -==== Transparent try_emplace -```c++ template std::pair try_emplace(K&& k, Args&&... args) ``` @@ -1044,8 +1017,6 @@ Inserts a new node into the container if there is no existing element with key ` If there is an existing element with key `k` this function does nothing. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The bool component of the return type is true if an insert took place. + + @@ -1055,9 +1026,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] excep + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor. @@ -1066,6 +1043,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr Pointers and references to elements are never invalidated. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. @@ -1079,41 +1058,6 @@ template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); -``` - -Inserts a new node into the container if there is no existing element with key `k` contained within it. - -If there is an existing element with key `k` this function does nothing. - -`hint` is a suggestion to where the element should be inserted. - -[horizontal] -Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. -Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_hint] except the `value_type` is constructed using: + -+ --- -```c++ -value_type(std::piecewise_construct, - std::forward_as_tuple(boost::forward(k)), - std::forward_as_tuple(boost::forward(args)...)) -``` - -instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor. - -The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. - -Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. - -Pointers and references to elements are never invalidated. - -If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. - -Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. --- - -==== Transparent try_emplace with Hint -```c++ template iterator try_emplace(const_iterator hint, K&& k, Args&&... args); ``` @@ -1124,9 +1068,6 @@ If there is an existing element with key `k` this function does nothing. `hint` is a suggestion to where the element should be inserted. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - - [horizontal] Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. @@ -1134,9 +1075,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_h + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor. @@ -1147,6 +1094,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr Pointers and references to elements are never invalidated. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics. Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`. @@ -1160,6 +1109,8 @@ template std::pair insert_or_assign(const key_type& k, M&& obj); template std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -1168,9 +1119,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` [horizontal] @@ -1180,7 +1137,9 @@ If an insert took place, then the iterator points to the newly inserted element. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1190,6 +1149,8 @@ template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -1198,9 +1159,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` `hint` is a suggestion to where the element should be inserted. @@ -1212,7 +1179,9 @@ Notes:;; The standard is fairly vague on the meaning of the hint. But the only p + Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1232,30 +1201,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Key ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. - ---- - -==== Transparent Extract by Key -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1334,28 +1290,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1573,6 +1516,7 @@ Notes:;; The `template ` overloads only participate in overload reso ```c++ mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); ``` [horizontal] @@ -1581,7 +1525,9 @@ Returns:;; A reference to `x.second` where `x` is the element already in the con Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + + -Pointers and references to elements are never invalidated. +Pointers and references to elements are never invalidated. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1589,11 +1535,14 @@ Pointers and references to elements are never invalidated. ```c++ mapped_type& at(const key_type& k); const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; ``` [horizontal] Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1633,11 +1582,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 59d0accce0dbc2f472bbf8182ff44a6ae2a18680 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 11:15:33 +0100 Subject: [PATCH 17/24] documented P2363 overloads for unordered/unordered_multimap --- doc/unordered/unordered_multimap.adoc | 41 ++++++--------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/doc/unordered/unordered_multimap.adoc b/doc/unordered/unordered_multimap.adoc index 9237d747..bc80967f 100644 --- a/doc/unordered/unordered_multimap.adoc +++ b/doc/unordered/unordered_multimap.adoc @@ -111,14 +111,14 @@ namespace boost { node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multimap_extract_by_key[extract](const key_type& k); - template node_type xref:#unordered_multimap_transparent_extract_by_key[extract](K&& k); + template node_type xref:#unordered_multimap_extract_by_key[extract](K&& k); iterator xref:#unordered_multimap_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_multimap_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_multimap_erase_by_position[erase](iterator position); iterator xref:#unordered_multimap_erase_by_position[erase](const_iterator position); size_type xref:#unordered_multimap_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_multimap_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_multimap_erase_by_key[erase](K&& k); iterator xref:#unordered_multimap_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_multimap_quick_erase[quick_erase](const_iterator position); void xref:#unordered_multimap_erase_return_void[erase_return_void](const_iterator position); @@ -172,6 +172,7 @@ namespace boost { size_type xref:#unordered_multimap_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_multimap_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_multimap_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multimap_bucket[bucket](const K& k) const; local_iterator xref:#unordered_multimap_begin_2[begin](size_type n); const_local_iterator xref:#unordered_multimap_begin_2[begin](size_type n) const; local_iterator xref:#unordered_multimap_end_2[end](size_type n); @@ -964,30 +965,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Key ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. - ---- - -==== Transparent Extract by Key -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1060,28 +1048,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1330,11 +1305,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +templat size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 24d844983185189f4070664dd2299cca47a28b8d Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 11:47:28 +0100 Subject: [PATCH 18/24] documented P2363 overloads for unordered_set --- doc/unordered/unordered_set.adoc | 87 ++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/doc/unordered/unordered_set.adoc b/doc/unordered/unordered_set.adoc index f8fdd117..d5b1fb9c 100644 --- a/doc/unordered/unordered_set.adoc +++ b/doc/unordered/unordered_set.adoc @@ -100,21 +100,23 @@ namespace boost { template iterator xref:#unordered_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); std::pair xref:#unordered_set_copy_insert[insert](const value_type& obj); std::pair xref:#unordered_set_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_set_transparent_insert[insert](K&& k); iterator xref:#unordered_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last); void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list); node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_set_extract_by_value[extract](const key_type& k); - template node_type xref:#unordered_set_transparent_extract_by_value[extract](K&& k); + template node_type xref:#unordered_set_extract_by_value[extract](K&& k); insert_return_type xref:#unordered_set_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_set_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_set_erase_by_position[erase](iterator position); iterator xref:#unordered_set_erase_by_position[erase](const_iterator position); size_type xref:#unordered_set_erase_by_value[erase](const key_type& k); - template size_type xref:#unordered_set_transparent_erase_by_value[erase](K&& k); + template size_type xref:#unordered_set_erase_by_value[erase](K&& k); iterator xref:#unordered_set_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_set_quick_erase[quick_erase](const_iterator position); void xref:#unordered_set_erase_return_void[erase_return_void](const_iterator position); @@ -168,6 +170,7 @@ namespace boost { size_type xref:#unordered_set_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_set_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_set_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_set_bucket[bucket](const K& k) const; local_iterator xref:#unordered_set_begin_2[begin](size_type n); const_local_iterator xref:#unordered_set_begin_2[begin](size_type n) const; local_iterator xref:#unordered_set_end_2[end](size_type n); @@ -847,6 +850,27 @@ Pointers and references to elements are never invalidated. --- +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Copy Insert with Hint ```c++ iterator insert(const_iterator hint, const value_type& obj); @@ -888,6 +912,29 @@ Pointers and references to elements are never invalidated. --- +==== Transparent Insert with Hint +```c++ +template iterator insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Insert Iterator Range ```c++ template void insert(InputIterator first, InputIterator last); @@ -936,30 +983,17 @@ Notes:;; In C++17 a node extracted using this method can be inserted into a comp ==== Extract by Value ```c++ node_type extract(const key_type& k); -``` - -Removes an element with key equivalent to `k`. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. - ---- - -==== Transparent Extract by Value -```c++ template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. +Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1038,28 +1072,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Value ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Value -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1309,11 +1330,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 0e9523a0a49360020fbefb6ded10d34ec17ae24f Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 11:57:41 +0100 Subject: [PATCH 19/24] documented P2363 overloads for unordered_multiset --- doc/unordered/unordered_multiset.adoc | 43 +++++++-------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/doc/unordered/unordered_multiset.adoc b/doc/unordered/unordered_multiset.adoc index ebaec9a5..2495e570 100644 --- a/doc/unordered/unordered_multiset.adoc +++ b/doc/unordered/unordered_multiset.adoc @@ -107,14 +107,14 @@ namespace boost { node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position); node_type xref:#unordered_multiset_extract_by_value[extract](const key_type& k); - template node_type xref:#unordered_multiset_transparent_extract_by_value[extract](K&& k); + template node_type xref:#unordered_multiset_extract_by_value[extract](K&& k); iterator xref:#unordered_multiset_insert_with_node_handle[insert](node_type&& nh); iterator xref:#unordered_multiset_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); iterator xref:#unordered_multiset_erase_by_position[erase](iterator position); iterator xref:#unordered_multiset_erase_by_position[erase](const_iterator position); size_type xref:#unordered_multiset_erase_by_value[erase](const key_type& k); - template size_type xref:#unordered_multiset_transparent_erase_by_value[erase](K&& x); + template size_type xref:#unordered_multiset_erase_by_value[erase](K&& x); iterator xref:#unordered_multiset_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_multiset_quick_erase[quick_erase](const_iterator position); void xref:#unordered_multiset_erase_return_void[erase_return_void](const_iterator position); @@ -168,6 +168,7 @@ namespace boost { size_type xref:#unordered_multiset_max_bucket_count[max_bucket_count]() const noexcept; size_type xref:#unordered_multiset_bucket_size[bucket_size](size_type n) const; size_type xref:#unordered_multiset_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multiset_bucket[bucket](const K& k) const; local_iterator xref:#unordered_multiset_begin_2[begin](size_type n); const_local_iterator xref:#unordered_multiset_begin_2[begin](size_type n) const; local_iterator xref:#unordered_multiset_end_2[end](size_type n); @@ -922,6 +923,7 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u ==== Extract by Value ```c++ node_type extract(const key_type& k); +template node_type extract(K&& k); ``` Removes an element with key equivalent to `k`. @@ -929,23 +931,9 @@ Removes an element with key equivalent to `k`. [horizontal] Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. - ---- - -==== Transparent Extract by Value -```c++ -template node_type extract(K&& k); -``` - -Removes an element with key equivalent to `k`. - -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - -[horizontal] -Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.[horizontal] -Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1018,28 +1006,15 @@ Notes:;; In older versions this could be inefficient because it had to search th ==== Erase by Value ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Value -```c++ template size_type erase(K&& x); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1288,11 +1263,13 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; ``` [horizontal] Returns:;; The index of the bucket which would contain an element with key `k`. Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From c646f3e3ca533bd8d6a8289352cbc295cceb0e57 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 12:16:52 +0100 Subject: [PATCH 20/24] documented P2363 overloads for unordered_flat_map --- doc/unordered/unordered_flat_map.adoc | 80 +++++++++++++++++++++------ 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/doc/unordered/unordered_flat_map.adoc b/doc/unordered/unordered_flat_map.adoc index 27af35cd..e1b27499 100644 --- a/doc/unordered/unordered_flat_map.adoc +++ b/doc/unordered/unordered_flat_map.adoc @@ -134,23 +134,31 @@ namespace boost { std::pair xref:#unordered_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args); template std::pair xref:#unordered_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_flat_map_try_emplace[try_emplace](K&& k, Args&&... args); template iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); template iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); template std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); template std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); template iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); template iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); void xref:#unordered_flat_map_erase_by_position[erase](iterator position); void xref:#unordered_flat_map_erase_by_position[erase](const_iterator position); size_type xref:#unordered_flat_map_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_flat_map_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_flat_map_erase_by_key[erase](K&& k); iterator xref:#unordered_flat_map_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_flat_map_swap[swap](unordered_flat_map& other) noexcept(boost::allocator_traits::is_always_equal::value || @@ -189,8 +197,11 @@ namespace boost { // element access mapped_type& xref:#unordered_flat_map_operator[operator[+]+](const key_type& k); mapped_type& xref:#unordered_flat_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_flat_map_operator[operator[+]+](K&& k); mapped_type& xref:#unordered_flat_map_at[at](const key_type& k); const mapped_type& xref:#unordered_flat_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_flat_map_at[at](const K& k); + template const mapped_type& xref:#unordered_flat_map_at[at](const K& k) const; // bucket interface size_type xref:#unordered_flat_map_bucket_count[bucket_count]() const noexcept; @@ -860,6 +871,8 @@ template std::pair try_emplace(const key_type& k, Args&&... args); template std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args); ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -876,15 +889,23 @@ if there is an element with an equivalent key; otherwise, the construction is of + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + -- --- @@ -895,6 +916,8 @@ template iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); ``` Inserts a new node into the container if there is no existing element with key `k` contained within it. @@ -911,15 +934,23 @@ if there is an element with an equivalent key; otherwise, the construction is of + -- ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(args)...)) ``` unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor. Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +The `template ` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + -- --- @@ -930,6 +961,8 @@ template std::pair insert_or_assign(const key_type& k, M&& obj); template std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -938,9 +971,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` [horizontal] @@ -948,7 +987,9 @@ Returns:;; The `bool` component of the return type is `true` if an insert took p + If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + +Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -958,6 +999,8 @@ template iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); ``` Inserts a new element into the container or updates an existing one by assigning to the contained value. @@ -966,9 +1009,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for If there is no such element, it is added to the container as: ```c++ +// first two overloads value_type(std::piecewise_construct, std::forward_as_tuple(boost::forward(k)), std::forward_as_tuple(boost::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::forward(obj))) ``` `hint` is a suggestion to where the element should be inserted. This implementation ignores it. @@ -976,7 +1025,9 @@ value_type(std::piecewise_construct, [horizontal] Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -998,28 +1049,15 @@ Throws:;; Nothing. ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1172,13 +1210,16 @@ Notes:;; The `template ` overloads only participate in overload reso ```c++ mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); ``` [horizontal] Effects:;; If the container does not already contain an element with a key equivalent to `k`, inserts the value `std::pair(k, mapped_type())`. Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. -Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- @@ -1186,11 +1227,14 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse ```c++ mapped_type& at(const key_type& k); const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; ``` [horizontal] Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 0391b6dafc90d664f174c9e2cdfb16ffebed3bc7 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 12:29:44 +0100 Subject: [PATCH 21/24] documented P2363 overloads for unordered_flat_set --- doc/unordered/unordered_flat_set.adoc | 63 +++++++++++++++++++-------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/doc/unordered/unordered_flat_set.adoc b/doc/unordered/unordered_flat_set.adoc index cd22733a..c0902792 100644 --- a/doc/unordered/unordered_flat_set.adoc +++ b/doc/unordered/unordered_flat_set.adoc @@ -116,15 +116,17 @@ namespace boost { template iterator xref:#unordered_flat_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); std::pair xref:#unordered_flat_set_copy_insert[insert](const value_type& obj); std::pair xref:#unordered_flat_set_move_insert[insert](value_type&& obj); - iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); - iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template std::pair xref:#unordered_flat_set_transparent_insert[insert](K&& k); + iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, value_type&& obj); template void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list); void xref:#unordered_flat_set_erase_by_position[erase](iterator position); void xref:#unordered_flat_set_erase_by_position[erase](const_iterator position); size_type xref:#unordered_flat_set_erase_by_key[erase](const key_type& k); - template size_type xref:#unordered_flat_set_transparent_erase_by_key[erase](K&& k); + template size_type xref:#unordered_flat_set_erase_by_key[erase](K&& k); iterator xref:#unordered_flat_set_erase_range[erase](const_iterator first, const_iterator last); void xref:#unordered_flat_set_swap[swap](unordered_flat_set& other) noexcept(boost::allocator_traits::is_always_equal::value || @@ -736,6 +738,25 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse --- +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Copy Insert with Hint ```c++ iterator insert(const_iterator hint, const value_type& obj); @@ -773,6 +794,27 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse --- +==== Transparent Insert with Hint +```c++ +template std::pair insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + ==== Insert Iterator Range ```c++ template void insert(InputIterator first, InputIterator last); @@ -818,28 +860,15 @@ Throws:;; Nothing. ==== Erase by Key ```c++ size_type erase(const key_type& k); -``` - -Erase all elements with key equivalent to `k`. - -[horizontal] -Returns:;; The number of elements erased. -Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. - ---- - -==== Transparent Erase by Key -```c++ template size_type erase(K&& k); ``` Erase all elements with key equivalent to `k`. -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. - [horizontal] Returns:;; The number of elements erased. Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 644295db3aad8a5e6cdc88d16f537a6a807fa34a Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 18 Dec 2022 12:32:30 +0100 Subject: [PATCH 22/24] added release notes for feature/p2363 --- doc/unordered/changes.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index 3c3f15f6..5a038239 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -6,6 +6,11 @@ :github-pr-url: https://github.com/boostorg/unordered/pull :cpp: C++ +== Release 1.82.0 + +* Extended heterogeneous lookup to more member functions as specified in + https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html[P2363]. + == Release 1.81.0 - Major update * Added fast containers `boost::unordered_flat_map` and `boost::unordered_flat_set` From 1955e4f36ac95b660a8ebe7eb21194dd127f1fc1 Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 20 Dec 2022 11:35:15 +0100 Subject: [PATCH 23/24] fixed constraint notes in transparent insert with hint --- doc/unordered/unordered_flat_set.adoc | 4 ++-- doc/unordered/unordered_set.adoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/unordered/unordered_flat_set.adoc b/doc/unordered/unordered_flat_set.adoc index c0902792..7d3d69f8 100644 --- a/doc/unordered/unordered_flat_set.adoc +++ b/doc/unordered/unordered_flat_set.adoc @@ -119,7 +119,7 @@ namespace boost { template std::pair xref:#unordered_flat_set_transparent_insert[insert](K&& k); iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); - template iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); template void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list); @@ -811,7 +811,7 @@ If an insert took place, then the iterator points to the newly inserted element. Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + + -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- diff --git a/doc/unordered/unordered_set.adoc b/doc/unordered/unordered_set.adoc index d5b1fb9c..8530b4d4 100644 --- a/doc/unordered/unordered_set.adoc +++ b/doc/unordered/unordered_set.adoc @@ -931,7 +931,7 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr + Pointers and references to elements are never invalidated. + + -This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. --- From 955f94350be3f16e9801946e5d06054086ad6e1e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Tue, 20 Dec 2022 16:46:08 +0100 Subject: [PATCH 24/24] typo --- doc/unordered/unordered_multimap.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/unordered/unordered_multimap.adoc b/doc/unordered/unordered_multimap.adoc index bc80967f..ab5ccbbb 100644 --- a/doc/unordered/unordered_multimap.adoc +++ b/doc/unordered/unordered_multimap.adoc @@ -1305,7 +1305,7 @@ Returns:;; The number of elements in bucket `n`. ==== bucket ```c++ size_type bucket(const key_type& k) const; -templat size_type bucket(const K& k) const; +template size_type bucket(const K& k) const; ``` [horizontal]