On Thu, 12 Feb 2026 at 18:02, Nathan Myers <[email protected]> wrote:
>
> Changes in v4:
>  - Fix numerous errors revealed by actual testing.
>
> Changes in v3:
>  - Skip calls to _M_check_rehashed as redundant when erasing.
>  - Fix Changelog: correct PR#, note extra changes.
>
> Changes in v2:
>  - Use concept __heterogeneous_hash_key for unordered containers.
>
> Implement the debug versions of new overloads from P2077.
>
> libstdc++-v3/ChangeLog:
>         PR libstdc++/117404
>         * include/debug/map.h (extract, erase): Define overloads.
>         * include/debug/multimap.h: Same.
>         * include/debug/multiset.h: Same.
>         * include/debug/set.h: Same.
>         * include/debug/unordered_map: Same (2x).
>         * include/debug/unordered_set: Same (2x), rename some locals.
> ---
>  libstdc++-v3/include/debug/map.h         | 30 ++++++++++++
>  libstdc++-v3/include/debug/multimap.h    | 27 +++++++++++
>  libstdc++-v3/include/debug/multiset.h    | 27 +++++++++++
>  libstdc++-v3/include/debug/set.h         | 30 ++++++++++++
>  libstdc++-v3/include/debug/unordered_map | 49 +++++++++++++++++++
>  libstdc++-v3/include/debug/unordered_set | 60 +++++++++++++++++++++---
>  6 files changed, 217 insertions(+), 6 deletions(-)
>
> diff --git a/libstdc++-v3/include/debug/map.h 
> b/libstdc++-v3/include/debug/map.h
> index 0fc7afae385..6e18b67e7b2 100644
> --- a/libstdc++-v3/include/debug/map.h
> +++ b/libstdc++-v3/include/debug/map.h
> @@ -476,6 +476,16 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<map> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = find(__key);
> +         return __position != end() ? extract(__position) : node_type{};

I'd have preferred to use the same structure as the existing
extract(const Key&) overload:

if (__position == end())
  return extract(__position);
return {};

Writing the same thing two different ways in functions that are almost
identical just makes people wonder if there's something significant
about the difference.

But nevermind, OK for trunk, thanks.



> +       }
> +# endif
> +
>        insert_return_type
>        insert(node_type&& __nh)
>        {
> @@ -538,6 +548,26 @@ namespace __debug
>           }
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      // Note that for some types _Kt this may erase more than
> +      // one element, such as if _Kt::operator< checks only part
> +      // of the key.
> +      template <__heterogeneous_tree_key<map> _Kt>
> +       size_type
> +       erase(_Kt&& __x)
> +       {
> +         auto __victims = _Base::equal_range(__x);
> +         size_type __count = 0;
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             this->_M_invalidate_if(_Equal(__victim));
> +             _Base::erase(__victim++);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +# endif
> +
>  #if __cplusplus >= 201103L
>        iterator
>        erase(const_iterator __first, const_iterator __last)
> diff --git a/libstdc++-v3/include/debug/multimap.h 
> b/libstdc++-v3/include/debug/multimap.h
> index 4137186c527..b6458bff2d5 100644
> --- a/libstdc++-v3/include/debug/multimap.h
> +++ b/libstdc++-v3/include/debug/multimap.h
> @@ -360,6 +360,16 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<multimap> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = find(__key);
> +         return __position != end() ? extract(__position) : node_type{};
> +       }
> +# endif
> +
>        iterator
>        insert(node_type&& __nh)
>        { return { _Base::insert(std::move(__nh)), this }; }
> @@ -420,6 +430,23 @@ namespace __debug
>         return __count;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<multimap> _Kt>
> +       size_type
> +       erase(_Kt&& __x)
> +       {
> +         auto __victims = _Base::equal_range(__x);
> +         size_type __count = 0;
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             this->_M_invalidate_if(_Equal(__victim));
> +             _Base::erase(__victim++);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +# endif
> +
>  #if __cplusplus >= 201103L
>        iterator
>        erase(const_iterator __first, const_iterator __last)
> diff --git a/libstdc++-v3/include/debug/multiset.h 
> b/libstdc++-v3/include/debug/multiset.h
> index 6fa499228f5..31d70ba124f 100644
> --- a/libstdc++-v3/include/debug/multiset.h
> +++ b/libstdc++-v3/include/debug/multiset.h
> @@ -331,6 +331,16 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<multiset> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = find(__key);
> +         return __position != end() ? extract(__position) : node_type{};
> +       }
> +#endif
> +
>        iterator
>        insert(node_type&& __nh)
>        { return { _Base::insert(std::move(__nh)), this }; }
> @@ -387,6 +397,23 @@ namespace __debug
>         return __count;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<multiset> _Kt>
> +       size_type
> +       erase(_Kt&& __x)
> +       {
> +         auto __victims = _Base::equal_range(__x);
> +         size_type __count = 0;
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             this->_M_invalidate_if(_Equal(__victim));
> +             _Base::erase(__victim++);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +# endif
> +
>  #if __cplusplus >= 201103L
>        _GLIBCXX_ABI_TAG_CXX11
>        iterator
> diff --git a/libstdc++-v3/include/debug/set.h 
> b/libstdc++-v3/include/debug/set.h
> index 99701d4a6d7..ec92f6f6448 100644
> --- a/libstdc++-v3/include/debug/set.h
> +++ b/libstdc++-v3/include/debug/set.h
> @@ -340,6 +340,16 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_tree_key<set> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = find(__key);
> +         return __position != end() ? extract(__position) : node_type{};
> +       }
> +#endif
> +
>        insert_return_type
>        insert(node_type&& __nh)
>        {
> @@ -398,6 +408,26 @@ namespace __debug
>           }
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      // Note that for some types _Kt this may erase more than
> +      // one element, such as if _Kt::operator< checks only part
> +      // of the key.
> +      template <__heterogeneous_tree_key<set> _Kt>
> +       size_type
> +       erase(_Kt&& __x)
> +       {
> +         auto __victims = _Base::equal_range(__x);
> +         size_type __count = 0;
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             this->_M_invalidate_if(_Equal(__victim));
> +             _Base::erase(__victim++);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +#endif
> +
>  #if __cplusplus >= 201103L
>        _GLIBCXX_ABI_TAG_CXX11
>        iterator
> diff --git a/libstdc++-v3/include/debug/unordered_map 
> b/libstdc++-v3/include/debug/unordered_map
> index 4bde18c917b..1383f9b8c99 100644
> --- a/libstdc++-v3/include/debug/unordered_map
> +++ b/libstdc++-v3/include/debug/unordered_map
> @@ -581,6 +581,17 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_map> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = _Base::find(__key);
> +         return __position != _Base::end() ?
> +           _M_extract(__position) : node_type{};
> +       }
> +#endif
> +
>        insert_return_type
>        insert(node_type&& __nh)
>        {
> @@ -713,6 +724,16 @@ namespace __debug
>         return __ret;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_map> _Kt>
> +       size_type
> +       erase(_Kt&& __key)
> +       {
> +         auto __victim = _Base::find(__key);
> +         return __victim != _Base::end() ? _M_erase(__victim), 1 : 0;
> +       }
> +#endif
> +
>        iterator
>        erase(const_iterator __it)
>        {
> @@ -1381,6 +1402,17 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_multimap> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = _Base::find(__key);
> +         return __position != _Base::end() ?
> +           _M_extract(__position) : node_type{};
> +       }
> +#endif
> +
>        iterator
>        insert(node_type&& __nh)
>        { return { _Base::insert(std::move(__nh)), this }; }
> @@ -1510,6 +1542,23 @@ namespace __debug
>         return __ret;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_multimap> _Kt>
> +       size_type
> +       erase(_Kt&& __key)
> +       {
> +         size_type __count(0);
> +         auto __victims = _Base::equal_range(__key);
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             _M_invalidate(__victim);
> +             __victim = _Base::erase(__victim);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +#endif
> +
>        iterator
>        erase(const_iterator __it)
>        {
> diff --git a/libstdc++-v3/include/debug/unordered_set 
> b/libstdc++-v3/include/debug/unordered_set
> index de999a76890..95b751ace2f 100644
> --- a/libstdc++-v3/include/debug/unordered_set
> +++ b/libstdc++-v3/include/debug/unordered_set
> @@ -468,6 +468,17 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_set> _Kt>
> +       node_type
> +       extract(_Kt&& __key)
> +       {
> +         const auto __position = _Base::find(__key);
> +         return __position != _Base::end() ?
> +           _M_extract(__position) : node_type{};
> +       }
> +#endif
> +
>        insert_return_type
>        insert(node_type&& __nh)
>        {
> @@ -598,6 +609,16 @@ namespace __debug
>         return __ret;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_set> _Kt>
> +       size_type
> +       erase(_Kt&& __key)
> +       {
> +         auto __victim = _Base::find(__key);
> +         return __victim != _Base::end() ? _M_erase(__victim), 1 : 0;
> +       }
> +#endif
> +
>        iterator
>        erase(const_iterator __it)
>        {
> @@ -1202,6 +1223,17 @@ namespace __debug
>         return {};
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_multiset> _Kt>
> +       node_type
> +       extract(const _Kt& __key)
> +       {
> +         const auto __position = _Base::find(__key);
> +         return __position != _Base::end() ?
> +           _M_extract(__position) : node_type{};
> +       }
> +#endif
> +
>        iterator
>        insert(node_type&& __nh)
>        { return { _Base::insert(std::move(__nh)), this }; }
> @@ -1318,18 +1350,34 @@ namespace __debug
>        size_type
>        erase(const key_type& __key)
>        {
> -       size_type __ret(0);
> -       auto __pair = _Base::equal_range(__key);
> -       for (auto __victim = __pair.first; __victim != __pair.second;)
> +       size_type __count(0);
> +       auto __victims = _Base::equal_range(__key);
> +       for (auto __victim = __victims.first; __victim != __victims.second;)
>           {
>             _M_invalidate(__victim);
>             __victim = _Base::erase(__victim);
> -           ++__ret;
> +           ++__count;
>           }
> -
> -       return __ret;
> +       return __count;
>        }
>
> +# ifdef __glibcxx_associative_heterogeneous_erasure
> +      template <__heterogeneous_hash_key<unordered_multiset> _Kt>
> +       size_type
> +       erase(_Kt&& __key)
> +       {
> +         size_type __count(0);
> +         auto __victims = _Base::equal_range(__key);
> +         for (auto __victim = __victims.first; __victim != __victims.second;)
> +           {
> +             _M_invalidate(__victim);
> +             __victim = _Base::erase(__victim);
> +             ++__count;
> +           }
> +         return __count;
> +       }
> +#endif
> +
>        iterator
>        erase(const_iterator __it)
>        {
> --
> 2.52.0
>

Reply via email to