https://gcc.gnu.org/g:73676cfb201e988bc086a8aeb63223f66f7b6252

commit r15-5214-g73676cfb201e988bc086a8aeb63223f66f7b6252
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Thu Oct 31 19:53:55 2024 +0000

    libstdc++: Refactor Hashtable erasure
    
    This reworks the internal member functions for erasure from
    unordered containers, similarly to the earlier commit doing it for
    insertion.
    
    Instead of multiple overloads of _M_erase which are selected via tag
    dispatching, the erase(const key_type&) member can use 'if constexpr' to
    choose an appropriate implementation (returning after erasing a single
    element for unique keys, or continuing to erase all equivalent elements
    for non-unique keys).
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/hashtable.h (_Hashtable::_M_erase): Remove
            overloads for erasing by key, moving logic to ...
            (_Hashtable::erase): ... here.
    
    Reviewed-by: François Dumont <fdum...@gcc.gnu.org>

Diff:
---
 libstdc++-v3/include/bits/hashtable.h | 113 ++++++++++++----------------------
 1 file changed, 39 insertions(+), 74 deletions(-)

diff --git a/libstdc++-v3/include/bits/hashtable.h 
b/libstdc++-v3/include/bits/hashtable.h
index eeffa15e5259..23484f711cc5 100644
--- a/libstdc++-v3/include/bits/hashtable.h
+++ b/libstdc++-v3/include/bits/hashtable.h
@@ -955,12 +955,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        iterator
        _M_emplace_multi(const_iterator, _Args&&... __args);
 
-      size_type
-      _M_erase(true_type __uks, const key_type&);
-
-      size_type
-      _M_erase(false_type __uks, const key_type&);
-
       iterator
       _M_erase(size_type __bkt, __node_base_ptr __prev_n, __node_ptr __n);
 
@@ -1002,8 +996,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return erase(const_iterator(__it)); }
 
       size_type
-      erase(const key_type& __k)
-      { return _M_erase(__unique_keys{}, __k); }
+      erase(const key_type& __k);
 
       iterator
       erase(const_iterator, const_iterator);
@@ -2372,6 +2365,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __result;
     }
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
   template<typename _Key, typename _Value, typename _Alloc,
           typename _ExtractKey, typename _Equal,
           typename _Hash, typename _RangeHash, typename _Unused,
@@ -2379,7 +2374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     auto
     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
               _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
-    _M_erase(true_type /* __uks */, const key_type& __k)
+    erase(const key_type& __k)
     -> size_type
     {
       __node_base_ptr __prev_n;
@@ -2409,77 +2404,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
        }
 
-      _M_erase(__bkt, __prev_n, __n);
-      return 1;
-    }
-
-  template<typename _Key, typename _Value, typename _Alloc,
-          typename _ExtractKey, typename _Equal,
-          typename _Hash, typename _RangeHash, typename _Unused,
-          typename _RehashPolicy, typename _Traits>
-    auto
-    _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
-              _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
-    _M_erase(false_type /* __uks */, const key_type& __k)
-    -> size_type
-    {
-      std::size_t __bkt;
-      __node_base_ptr __prev_n;
-      __node_ptr __n;
-      if (size() <= __small_size_threshold())
+      if constexpr (__unique_keys::value)
        {
-         __prev_n = _M_find_before_node(__k);
-         if (!__prev_n)
-           return 0;
-
-         // We found a matching node, erase it.
-         __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
-         __bkt = _M_bucket_index(*__n);
+         _M_erase(__bkt, __prev_n, __n);
+         return 1;
        }
       else
        {
-         __hash_code __code = this->_M_hash_code(__k);
-         __bkt = _M_bucket_index(__code);
-
-         // Look for the node before the first matching node.
-         __prev_n = _M_find_before_node(__bkt, __k, __code);
-         if (!__prev_n)
-           return 0;
-
-         __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
-       }
-
-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
-      // 526. Is it undefined if a function in the standard changes
-      // in parameters?
-      // We use one loop to find all matching nodes and another to deallocate
-      // them so that the key stays valid during the first loop. It might be
-      // invalidated indirectly when destroying nodes.
-      __node_ptr __n_last = __n->_M_next();
-      while (__n_last && this->_M_node_equals(*__n, *__n_last))
-       __n_last = __n_last->_M_next();
-
-      std::size_t __n_last_bkt = __n_last ? _M_bucket_index(*__n_last) : __bkt;
-
-      // Deallocate nodes.
-      size_type __result = 0;
-      do
-       {
-         __node_ptr __p = __n->_M_next();
-         this->_M_deallocate_node(__n);
-         __n = __p;
-         ++__result;
+         // _GLIBCXX_RESOLVE_LIB_DEFECTS
+         // 526. Is it undefined if a function in the standard changes
+         // in parameters?
+         // We use one loop to find all matching nodes and another to
+         // deallocate them so that the key stays valid during the first loop.
+         // It might be invalidated indirectly when destroying nodes.
+         __node_ptr __n_last = __n->_M_next();
+         while (__n_last && this->_M_node_equals(*__n, *__n_last))
+           __n_last = __n_last->_M_next();
+
+         std::size_t __n_last_bkt
+           = __n_last ? _M_bucket_index(*__n_last) : __bkt;
+
+         // Deallocate nodes.
+         size_type __result = 0;
+         do
+           {
+             __node_ptr __p = __n->_M_next();
+             this->_M_deallocate_node(__n);
+             __n = __p;
+             ++__result;
+           }
+         while (__n != __n_last);
+
+         _M_element_count -= __result;
+         if (__prev_n == _M_buckets[__bkt])
+           _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt);
+         else if (__n_last_bkt != __bkt)
+           _M_buckets[__n_last_bkt] = __prev_n;
+         __prev_n->_M_nxt = __n_last;
+         return __result;
        }
-      while (__n != __n_last);
-
-      _M_element_count -= __result;
-      if (__prev_n == _M_buckets[__bkt])
-       _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt);
-      else if (__n_last_bkt != __bkt)
-       _M_buckets[__n_last_bkt] = __prev_n;
-      __prev_n->_M_nxt = __n_last;
-      return __result;
     }
+#pragma GCC diagnostic pop
 
   template<typename _Key, typename _Value, typename _Alloc,
           typename _ExtractKey, typename _Equal,

Reply via email to