[libcxx-commits] [libcxx] [libc++] Implement P2077R3 Heterogeneous erasure overloads for associative containers (PR #78277)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jan 16 05:50:07 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Mital Ashok (MitalAshok)

<details>
<summary>Changes</summary>

Implements [P2077R3](https://wg21.link/P2077R3).

Note that given a non-const or non-lvalue argument `k`, `m.extract(k)`/`m.erase(k)` converts to a const lvalue, similarly to what would have happened if the functions took by `const _K2&` instead of `_K2&&`. This is intentional since the comparator / hasher+key_equal shouldn't modify the argument. The exact wording is here: https://wg21.link/associative.reqmts.general#<!-- -->123


---

Patch is 110.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/78277.diff


57 Files Affected:

- (modified) libcxx/docs/ReleaseNotes/18.rst (+1) 
- (modified) libcxx/docs/Status/Cxx23Papers.csv (+2-2) 
- (modified) libcxx/include/__hash_table (+4-4) 
- (modified) libcxx/include/__tree (+4-4) 
- (modified) libcxx/include/map (+36-4) 
- (modified) libcxx/include/set (+34-2) 
- (modified) libcxx/include/unordered_map (+34-2) 
- (modified) libcxx/include/unordered_set (+37-5) 
- (modified) libcxx/include/version (+1-1) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran.pass.cpp (+58) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/erase_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran.pass.cpp (+61) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/map/map.modifiers/extract_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran.pass.cpp (+58) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/erase_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran.pass.cpp (+61) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/multimap/multimap.modifiers/extract_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran.pass.cpp (+58) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/multiset/erase_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran.pass.cpp (+61) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/multiset/extract_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/set/erase_tran.pass.cpp (+58) 
- (added) libcxx/test/std/containers/associative/set/erase_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/erase_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/erase_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/erase_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/set/erase_tran5.pass.cpp (+52) 
- (added) libcxx/test/std/containers/associative/set/extract_tran.pass.cpp (+61) 
- (added) libcxx/test/std/containers/associative/set/extract_tran1.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/extract_tran2.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/extract_tran3.compile.fail.cpp (+40) 
- (added) libcxx/test/std/containers/associative/set/extract_tran4.pass.cpp (+49) 
- (added) libcxx/test/std/containers/associative/set/extract_tran5.pass.cpp (+52) 


``````````diff
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 62a1fec627d0ca..8db818ef490203 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -60,6 +60,7 @@ Implemented Papers
 - P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``)
 - P1759R6 - Native handles and file streams
 - P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``
+- P2077R3 - Heterogeneous erasure overloads for associative containers
 
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index ebab3ef735b617..5e091f6151399b 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -30,7 +30,7 @@
 "`P1147R1 <https://wg21.link/P1147R1>`__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0"
 "`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0"
 "`P1675R2 <https://wg21.link/P1675R2>`__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","",""
-"`P2077R3 <https://wg21.link/P2077R3>`__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","",""
+"`P2077R3 <https://wg21.link/P2077R3>`__","LWG","Heterogeneous erasure overloads for associative containers","October 2021","|Complete|","18.0"
 "`P2251R1 <https://wg21.link/P2251R1>`__","LWG","Require ``span`` & ``basic_string_view`` to be Trivially Copyable","October 2021","|Complete|","14.0"
 "`P2301R1 <https://wg21.link/P2301R1>`__","LWG","Add a ``pmr`` alias for ``std::stacktrace``","October 2021","",""
 "`P2321R2 <https://wg21.link/P2321R2>`__","LWG","``zip``","October 2021","|In Progress|","","|ranges|"
@@ -59,7 +59,7 @@
 "`P1467R9 <https://wg21.link/P1467R9>`__","LWG","Extended ``floating-point`` types and standard names","July 2022","",""
 "`P1642R11 <https://wg21.link/P1642R11>`__","LWG","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","July 2022","",""
 "`P1899R3 <https://wg21.link/P1899R3>`__","LWG","``stride_view``","July 2022","","","|ranges|"
-"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","","|Complete|","18.0"
+"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","|Complete|","18.0",""
 "`P2165R4 <https://wg21.link/P2165R4>`__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","",""
 "`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|"
 "`P2286R8 <https://wg21.link/P2286R8>`__","LWG","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|"
diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table
index 4ca49fe42606c7..0d7c38f9d056f5 100644
--- a/libcxx/include/__hash_table
+++ b/libcxx/include/__hash_table
@@ -836,8 +836,8 @@ public:
   template <class _Table>
   _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Table& __source);
 
-  template <class _NodeHandle>
-  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const& __key);
+  template <class _NodeHandle, class _Key>
+  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_find_and_extract(const _Key& __key);
   template <class _NodeHandle>
   _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator __it);
 #endif
@@ -1579,9 +1579,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_insert_unique(const_iter
 }
 
 template <class _Tp, class _Hash, class _Equal, class _Alloc>
-template <class _NodeHandle>
+template <class _NodeHandle, class _Key>
 _LIBCPP_HIDE_FROM_ABI _NodeHandle
-__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_extract(key_type const& __key) {
+__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_find_and_extract(const _Key& __key) {
   iterator __i = find(__key);
   if (__i == end())
     return _NodeHandle();
diff --git a/libcxx/include/__tree b/libcxx/include/__tree
index 2dcc3c614d3660..84cda01df51494 100644
--- a/libcxx/include/__tree
+++ b/libcxx/include/__tree
@@ -1168,8 +1168,8 @@ public:
   template <class _Tree>
   _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Tree& __source);
 
-  template <class _NodeHandle>
-  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const&);
+  template <class _NodeHandle, class _Key>
+  _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_find_and_extract(const _Key&);
   template <class _NodeHandle>
   _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(const_iterator);
 #endif
@@ -1963,8 +1963,8 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __
 }
 
 template <class _Tp, class _Compare, class _Allocator>
-template <class _NodeHandle>
-_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(key_type const& __key) {
+template <class _NodeHandle, class _Key>
+_LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_find_and_extract(const _Key& __key) {
   iterator __it = find(__key);
   if (__it == end())
     return _NodeHandle();
diff --git a/libcxx/include/map b/libcxx/include/map
index f122f2ebb15b52..5b3515c228e0b5 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -149,6 +149,8 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
@@ -170,8 +172,10 @@ public:
         iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);        // C++17
 
     iterator  erase(const_iterator position);
-    iterator  erase(iterator position); // C++14
+    iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -428,12 +432,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     iterator insert(node_type&& nh);                                                  // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
-    iterator  erase(iterator position); // C++14
+    iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -1309,6 +1317,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) {
     return __tree_.erase(__f.__i_, __l.__i_);
   }
@@ -1326,11 +1340,17 @@ public:
     return __tree_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(map<key_type, mapped_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -1900,6 +1920,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __tree_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) {
     return __tree_.erase(__f.__i_, __l.__i_);
   }
@@ -1916,11 +1942,17 @@ public:
     return __tree_.template __node_handle_insert_multi<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(multimap<key_type, mapped_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
diff --git a/libcxx/include/set b/libcxx/include/set
index 55ba8f8208be1b..832ed876253c86 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -125,12 +125,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
     iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -370,12 +374,16 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     iterator insert(node_type&& nh);                                                  // C++17
     iterator insert(const_iterator hint, node_type&& nh);                             // C++17
 
     iterator  erase(const_iterator position);
     iterator  erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);          // C++23
     iterator  erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -764,6 +772,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
   _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
 
@@ -779,11 +793,17 @@ public:
     return __tree_.template __node_handle_insert_unique<node_type>(__hint, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(set<key_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
@@ -1222,6 +1242,12 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __tree_.erase(__p); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __tree_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __tree_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __f, const_iterator __l) { return __tree_.erase(__f, __l); }
   _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __tree_.clear(); }
 
@@ -1237,11 +1263,17 @@ public:
     return __tree_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __tree_.template __node_handle_extract<node_type>(__key);
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __tree_.template __node_handle_extract<node_type>(__it);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<_Compare, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __tree_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
   template <class _Compare2>
   _LIBCPP_HIDE_FROM_ABI void merge(multiset<key_type, _Compare2, allocator_type>& __source) {
     _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(
diff --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index 4be25fc1cdd8fe..42889a06ed019a 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -139,6 +139,8 @@ public:
 
     node_type extract(const_iterator position);                                       // C++17
     node_type extract(const key_type& x);                                             // C++17
+    template <class K>
+        node_type extract(K&& x);                                                     // C++23
     insert_return_type insert(node_type&& nh);                                        // C++17
     iterator           insert(const_iterator hint, node_type&& nh);                   // C++17
 
@@ -162,6 +164,8 @@ public:
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -425,12 +429,16 @@ public:
 
     node_type extract(const_iterator position);                // C++17
     node_type extract(const key_type& x);                      // C++17
+    template <class K>
+        node_type extract(K&& x);                              // C++23
     iterator insert(node_type&& nh);                           // C++17
     iterator insert(const_iterator hint, node_type&& nh);      // C++17
 
     iterator erase(const_iterator position);
     iterator erase(iterator position);  // C++14
     size_type erase(const key_type& k);
+    template <class K>
+        size_type erase(K&& x);         // C++23
     iterator erase(const_iterator first, const_iterator last);
     void clear() noexcept;
 
@@ -1322,6 +1330,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_unique(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_unique(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
     return __table_.erase(__first.__i_, __last.__i_);
   }
@@ -1339,11 +1353,17 @@ public:
     return __table_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh));
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) {
-    return __table_.template __node_handle_extract<node_type>(__key);
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
   }
   _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) {
     return __table_.template __node_handle_extract<node_type>(__it.__i_);
   }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI node_type extract(_K2&& __key) {
+    return __table_.template __node_handle_find_and_extract<node_type>(__key);
+  }
+#endif
 
   template <class _H2, class _P2>
   _LIBCPP_HIDE_FROM_ABI void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>& __source) {
@@ -2073,6 +2093,12 @@ public:
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __p) { return __table_.erase(__p.__i_); }
   _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __k) { return __table_.__erase_multi(__k); }
+#if _LIBCPP_STD_VER >= 23
+  template <typename _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value && !(is_convertible_v<_K2&&, iterator> || is_convertible_v<_K2&&, const_iterator>), int> = 0>
+  _LIBCPP_HIDE_FROM_ABI size_type erase(_K2&& __k) {
+    return __table_.__erase_multi(__k);
+  }
+#endif
   _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, con...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/78277


More information about the libcxx-commits mailing list