https://gcc.gnu.org/g:3287a5c617458ab1b79d69d93d755006842f00ad
commit r16-6889-g3287a5c617458ab1b79d69d93d755006842f00ad Author: François Dumont <[email protected]> Date: Wed Dec 10 19:12:58 2025 +0100 libstdc++: Fix std::erase_if behavior for std::__debug containers Complete fix of std::erase_if/std::erase for all std::__debug containers and __gnu_debug::basic_string. Make sure that iterators erased by this function will be properly detected as such by the debug container and so considered as invalid. Doing so introduce a new std::__detail::__erase_if function dealing, similarly to std::__detail::__erase_node_if, with non-node containers. libstdc++-v3/ChangeLog: * include/bits/erase_if.h (__detail::__erase_if): New. * include/debug/deque (std::erase_if<>(__debug::deque<>&, _Pred)): Use latter. * include/debug/inplace_vector (std::erase_if<>(__debug::inplace_vector<>&, _Pred)): Likewise. * include/debug/vector (std::erase_if<>(__debug::vector<>&, _Pred)): Likewise. * include/std/deque: Include erase_if.h. (std::erase_if<>(std::vector<>&, _Pred)): Adapt to use __detail::__erase_if. * include/std/inplace_vector (std::erase_if<>(std::inplace_vector<>&, _Pred)): Likewise. * include/std/string (std::erase_if<>(std::basic_string<>&, _Pred)): Likewise. * include/std/vector (std::erase_if<>(std::vector<>&, _Pred)): Likewise. * include/debug/forward_list (std::erase_if<>(__debug::forward_list<>&, _Pred)): New. (std::erase<>(__debug::forward_list<>&, const _Up&)): New. * include/debug/list (std::erase_if<>(__debug::list<>&, _Pred)): New. (std::erase<>(__debug::list<>&, const _Up&)): New. * include/debug/map (std::erase_if<>(__debug::map<>&, _Pred)): New. (std::erase_if<>(__debug::multimap<>&, _Pred)): New. * include/debug/set (std::erase_if<>(__debug::set<>&, _Pred)): New. (std::erase_if<>(__debug::multiset<>&, _Pred)): New. * include/debug/string (std::erase_if<>(__gnu_debug::basic_string<>&, _Pred)): New. (std::erase<>(__gnu_debug::basic_string<>&, const _Up&)): New. * include/debug/unordered_map (std::erase_if<>(__debug::unordered_map<>&, _Pred)): New. (std::erase_if<>(__debug::unordered_multimap<>&, _Pred)): New. * include/debug/unordered_set (std::erase_if<>(__debug::unordered_set<>&, _Pred)): New. (std::erase_if<>(__debug::unordered_multiset<>&, _Pred)): New. * include/std/forward_list (std::erase_if<>(std::forward_list<>&, _Pred)): Adapt to work exclusively for normal implementation. (std::erase<>(std::forward_list<>&, const _Up&)): Likewise. * include/std/list (std::erase_if<>(std::list<>&, _Pred)): Likewise. (std::erase<>(std::list<>&, const _Up&)): Likewise. * include/std/map (std::erase_if<>(std::map<>&, _Pred)): Likewise. (std::erase_if<>(std::multimap<>&, _Pred)): Likewise. Guard functions using __cpp_lib_erase_if. * include/std/set (std::erase_if<>(std::set<>&, _Pred)): Likewise. (std::erase_if<>(std::multiset<>&, _Pred)): Likewise. Guard functions using __cpp_lib_erase_if. * include/std/unordered_map (std::erase_if<>(std::unordered_map<>&, _Pred)): Likewise. (std::erase_if<>(std::unordered_multimap<>&, _Pred)): Likewise. Guard functions using __cpp_lib_erase_if. * include/std/unordered_set (std::erase_if<>(std::unordered_set<>&, _Pred)): Likewise. (std::erase_if<>(std::unordered_multiset<>&, _Pred)): Likewise. Guard functions using __cpp_lib_erase_if. * testsuite/21_strings/basic_string/debug/erase.cc: New test case. * testsuite/23_containers/forward_list/debug/erase.cc: New test case. * testsuite/23_containers/forward_list/debug/invalidation/erase.cc: New test case. * testsuite/23_containers/list/debug/erase.cc: New test case. * testsuite/23_containers/list/debug/invalidation/erase.cc: New test case. * testsuite/23_containers/map/debug/erase_if.cc: New test case. * testsuite/23_containers/map/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/multimap/debug/erase_if.cc: New test case. * testsuite/23_containers/multimap/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/multiset/debug/erase_if.cc: New test case. * testsuite/23_containers/multiset/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/set/debug/erase_if.cc: New test case. * testsuite/23_containers/set/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/unordered_map/debug/erase_if.cc: New test case. * testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/unordered_multimap/debug/erase_if.cc: New test case. * testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/unordered_multiset/debug/erase_if.cc: New test case. * testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc: New test case. * testsuite/23_containers/unordered_set/debug/erase_if.cc: New test case. * testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc: New test case. Diff: --- libstdc++-v3/include/bits/erase_if.h | 22 ++++++++++++++ libstdc++-v3/include/debug/deque | 16 ++-------- libstdc++-v3/include/debug/forward_list | 21 +++++++++++++ libstdc++-v3/include/debug/inplace_vector | 15 ++-------- libstdc++-v3/include/debug/list | 21 +++++++++++++ libstdc++-v3/include/debug/map | 21 +++++++++++++ libstdc++-v3/include/debug/set | 19 ++++++++++++ libstdc++-v3/include/debug/string | 20 +++++++++++++ libstdc++-v3/include/debug/unordered_map | 20 +++++++++++++ libstdc++-v3/include/debug/unordered_set | 20 +++++++++++++ libstdc++-v3/include/debug/vector | 14 +-------- libstdc++-v3/include/std/deque | 15 ++-------- libstdc++-v3/include/std/forward_list | 8 ++--- libstdc++-v3/include/std/inplace_vector | 13 ++------- libstdc++-v3/include/std/list | 8 ++--- libstdc++-v3/include/std/map | 25 +++++++--------- libstdc++-v3/include/std/set | 24 +++++++-------- libstdc++-v3/include/std/string | 11 ++----- libstdc++-v3/include/std/unordered_map | 29 ++++++++---------- libstdc++-v3/include/std/unordered_set | 26 +++++++---------- libstdc++-v3/include/std/vector | 15 ++-------- .../21_strings/basic_string/debug/erase.cc | 25 ++++++++++++++++ .../23_containers/forward_list/debug/erase.cc | 26 +++++++++++++++++ .../forward_list/debug/invalidation/erase.cc | 27 +++++++++++++++++ .../testsuite/23_containers/list/debug/erase.cc | 29 ++++++++++++++++++ .../23_containers/list/debug/invalidation/erase.cc | 30 +++++++++++++++++++ .../testsuite/23_containers/map/debug/erase_if.cc | 33 +++++++++++++++++++++ .../map/debug/invalidation/erase_if.cc | 34 ++++++++++++++++++++++ .../23_containers/multimap/debug/erase_if.cc | 33 +++++++++++++++++++++ .../multimap/debug/invalidation/erase_if.cc | 34 ++++++++++++++++++++++ .../23_containers/multiset/debug/erase_if.cc | 31 ++++++++++++++++++++ .../multiset/debug/invalidation/erase_if.cc | 32 ++++++++++++++++++++ .../testsuite/23_containers/set/debug/erase_if.cc | 31 ++++++++++++++++++++ .../set/debug/invalidation/erase_if.cc | 32 ++++++++++++++++++++ .../23_containers/unordered_map/debug/erase_if.cc | 33 +++++++++++++++++++++ .../unordered_map/debug/invalidation/erase_if.cc | 34 ++++++++++++++++++++++ .../unordered_multimap/debug/erase_if.cc | 33 +++++++++++++++++++++ .../debug/invalidation/erase_if.cc | 34 ++++++++++++++++++++++ .../unordered_multiset/debug/erase_if.cc | 31 ++++++++++++++++++++ .../debug/invalidation/erase_if.cc | 32 ++++++++++++++++++++ .../23_containers/unordered_set/debug/erase_if.cc | 31 ++++++++++++++++++++ .../unordered_set/debug/invalidation/erase_if.cc | 32 ++++++++++++++++++++ 42 files changed, 886 insertions(+), 154 deletions(-) diff --git a/libstdc++-v3/include/bits/erase_if.h b/libstdc++-v3/include/bits/erase_if.h index a445a53bcfbf..d5a5278d1282 100644 --- a/libstdc++-v3/include/bits/erase_if.h +++ b/libstdc++-v3/include/bits/erase_if.h @@ -35,6 +35,7 @@ #endif #include <bits/c++config.h> +#include <bits/stl_algobase.h> // Used by C++17 containers and Library Fundamentals v2 headers. #if __cplusplus >= 201402L @@ -44,6 +45,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __detail { + template<typename _Container, typename _UnsafeContainer, + typename _Predicate> + _GLIBCXX20_CONSTEXPR + typename _Container::size_type + __erase_if(_Container& __cont, _UnsafeContainer& __ucont, + _Predicate __pred) + { + const auto __osz = __ucont.size(); + const auto __end = __ucont.end(); + auto __removed = std::__remove_if(__ucont.begin(), __end, + std::move(__pred)); + if (__removed != __end) + { + __cont.erase(__niter_wrap(__cont.cbegin(), __removed), + __cont.cend()); + return __osz - __ucont.size(); + } + + return 0; + } + template<typename _Container, typename _UnsafeContainer, typename _Predicate> typename _Container::size_type diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque index b3e72eb30163..9fba4ffc4997 100644 --- a/libstdc++-v3/include/debug/deque +++ b/libstdc++-v3/include/debug/deque @@ -778,19 +778,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline typename __debug::deque<_Tp, _Alloc>::size_type erase_if(__debug::deque<_Tp, _Alloc>& __cont, _Predicate __pred) { - _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __unsafe_cont = __cont; - const auto __osz = __cont.size(); - const auto __end = __unsafe_cont.end(); - auto __removed = std::__remove_if(__unsafe_cont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); - return __osz - __cont.size(); - } - - return 0; + return __detail::__erase_if(__cont, __cont._M_base(), std::move(__pred)); } template<typename _Tp, typename _Alloc, typename _Up = _Tp> @@ -798,7 +786,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION erase(__debug::deque<_Tp, _Alloc>& __cont, const _Up& __value) { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } _GLIBCXX_END_NAMESPACE_VERSION -#endif // __cpp_lib_erase_if +#endif // __glibcxx_erase_if } // namespace std #endif diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index 1fe3a4f2830b..7d615978000e 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -981,6 +981,27 @@ namespace __debug { __lx.swap(__ly); } } // namespace __debug + +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Tp, typename _Alloc, typename _Predicate> + inline typename __debug::forward_list<_Tp, _Alloc>::size_type + erase_if(__debug::forward_list<_Tp, _Alloc>& __cont, _Predicate __pred) + { return __cont.remove_if(__pred); } + + template<typename _Tp, typename _Alloc, + typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> + inline typename __debug::forward_list<_Tp, _Alloc>::size_type + erase(__debug::forward_list<_Tp, _Alloc>& __cont, const _Up& __value) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4135. helper lambda of std::erase for list should specify return type + return std::erase_if(__cont, [&](const auto& __elem) -> bool { + return __elem == __value; + }); + } +_GLIBCXX_END_NAMESPACE_VERSION +#endif // __glibcxx_erase_if } // namespace std namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/inplace_vector b/libstdc++-v3/include/debug/inplace_vector index c7e301efc621..750b0a7343ca 100644 --- a/libstdc++-v3/include/debug/inplace_vector +++ b/libstdc++-v3/include/debug/inplace_vector @@ -566,13 +566,13 @@ namespace __debug noexcept( noexcept(__x.swap(__y)) ) { __x.swap(__y); } - private: constexpr _Base& _M_base() noexcept { return *this; } constexpr const _Base& _M_base() const noexcept { return *this; } + private: constexpr void _M_invalidate_after_nth(difference_type __n) noexcept { @@ -663,17 +663,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if constexpr (_Nm != 0) { - _GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __ucont = __cont; - const auto __osz = __cont.size(); - const auto __end = __ucont.end(); - auto __removed = std::__remove_if(__ucont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__niter_wrap(__cont.cbegin(), __removed), - __cont.cend()); - return __osz - __cont.size(); - } + return __detail::__erase_if(__cont, __cont._M_base(), + std::move(__pred)); } return 0; diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list index 48ec1966d97e..d06e9e4c2f84 100644 --- a/libstdc++-v3/include/debug/list +++ b/libstdc++-v3/include/debug/list @@ -1031,6 +1031,27 @@ namespace __debug { __lhs.swap(__rhs); } } // namespace __debug + +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Tp, typename _Alloc, typename _Predicate> + inline typename __debug::list<_Tp, _Alloc>::size_type + erase_if(__debug::list<_Tp, _Alloc>& __cont, _Predicate __pred) + { return __cont.remove_if(__pred); } + + template<typename _Tp, typename _Alloc, + typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> + inline typename __debug::list<_Tp, _Alloc>::size_type + erase(__debug::list<_Tp, _Alloc>& __cont, const _Up& __value) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4135. helper lambda of std::erase for list should specify return type + return std::erase_if(__cont, [&](const auto& __elem) -> bool { + return __elem == __value; + }); + } +_GLIBCXX_END_NAMESPACE_VERSION +#endif // __glibcxx_erase_if } // namespace std namespace __gnu_debug diff --git a/libstdc++-v3/include/debug/map b/libstdc++-v3/include/debug/map index 360325f03ad2..b07c17f2320e 100644 --- a/libstdc++-v3/include/debug/map +++ b/libstdc++-v3/include/debug/map @@ -45,4 +45,25 @@ namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug { #include <debug/map.h> #include <debug/multimap.h> +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Key, typename _Tp, typename _Compare, typename _Alloc, + typename _Predicate> + inline typename __debug::map<_Key, _Tp, _Compare, _Alloc>::size_type + erase_if(__debug::map<_Key, _Tp, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } + + template<typename _Key, typename _Tp, typename _Compare, typename _Alloc, + typename _Predicate> + inline typename __debug::multimap<_Key, _Tp, _Compare, _Alloc>::size_type + erase_if(__debug::multimap<_Key, _Tp, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_erase_if + #endif diff --git a/libstdc++-v3/include/debug/set b/libstdc++-v3/include/debug/set index 6645032c349c..508c0cd05fd2 100644 --- a/libstdc++-v3/include/debug/set +++ b/libstdc++-v3/include/debug/set @@ -43,4 +43,23 @@ namespace std _GLIBCXX_VISIBILITY(default) { namespace __debug { #include <debug/set.h> #include <debug/multiset.h> +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Key, typename _Compare, typename _Alloc, + typename _Predicate> + inline typename __debug::set<_Key, _Compare, _Alloc>::size_type + erase_if(__debug::set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } + + template<typename _Key, typename _Compare, typename _Alloc, + typename _Predicate> + inline typename __debug::multiset<_Key, _Compare, _Alloc>::size_type + erase_if(__debug::multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_erase_if + #endif diff --git a/libstdc++-v3/include/debug/string b/libstdc++-v3/include/debug/string index 6d30d7d036ac..d5ee1d9e1938 100644 --- a/libstdc++-v3/include/debug/string +++ b/libstdc++-v3/include/debug/string @@ -1331,6 +1331,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : __is_fast_hash<hash<std::basic_string<_CharT>>> { }; +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED + template<typename _CharT, typename _Traits, typename _Alloc, + typename _Predicate> + constexpr typename __gnu_debug::basic_string<_CharT, + _Traits, _Alloc>::size_type + erase_if(__gnu_debug::basic_string<_CharT, _Traits, _Alloc>& __cont, + _Predicate __pred) + { + return __detail::__erase_if(__cont, __cont._M_base(), std::move(__pred)); + } + + template<typename _CharT, typename _Traits, typename _Alloc, + typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)> + constexpr typename __gnu_debug::basic_string<_CharT, + _Traits, _Alloc>::size_type + erase(__gnu_debug::basic_string<_CharT, _Traits, _Alloc>& __cont, + const _Up& __value) + { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); } +#endif // __glibcxx_erase_if + _GLIBCXX_END_NAMESPACE_VERSION } #endif /* C++11 */ diff --git a/libstdc++-v3/include/debug/unordered_map b/libstdc++-v3/include/debug/unordered_map index 8e286b733362..4bde18c917b2 100644 --- a/libstdc++-v3/include/debug/unordered_map +++ b/libstdc++-v3/include/debug/unordered_map @@ -1748,6 +1748,26 @@ namespace __debug #endif } // namespace __debug + +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Key, typename _Tp, typename _Hash, typename _CPred, + typename _Alloc, typename _Predicate> + inline typename __debug::unordered_map<_Key, _Tp, _Hash, + _CPred, _Alloc>::size_type + erase_if(__debug::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } + + template<typename _Key, typename _Tp, typename _Hash, typename _CPred, + typename _Alloc, typename _Predicate> + inline typename __debug::unordered_multimap<_Key, _Tp, _Hash, + _CPred, _Alloc>::size_type + erase_if(__debug::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } +_GLIBCXX_END_NAMESPACE_VERSION +#endif // __glibcxx_erase_if } // namespace std #endif // C++11 diff --git a/libstdc++-v3/include/debug/unordered_set b/libstdc++-v3/include/debug/unordered_set index 8951604f03bf..de999a76890e 100644 --- a/libstdc++-v3/include/debug/unordered_set +++ b/libstdc++-v3/include/debug/unordered_set @@ -1597,6 +1597,26 @@ namespace __debug #endif } // namespace __debug + +#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED +_GLIBCXX_BEGIN_NAMESPACE_VERSION + template<typename _Key, typename _Hash, typename _CPred, typename _Alloc, + typename _Predicate> + inline typename __debug::unordered_set<_Key, _Hash, + _CPred, _Alloc>::size_type + erase_if(__debug::unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } + + template<typename _Key, typename _Hash, typename _CPred, typename _Alloc, + typename _Predicate> + inline typename __debug::unordered_multiset<_Key, _Hash, + _CPred, _Alloc>::size_type + erase_if(__debug::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __pred); } +_GLIBCXX_END_NAMESPACE_VERSION +#endif // __glibcxx_erase_if } // namespace std #endif // C++11 diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector index e652260860a2..61e5ff78a7a4 100644 --- a/libstdc++-v3/include/debug/vector +++ b/libstdc++-v3/include/debug/vector @@ -1043,19 +1043,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr typename __debug::vector<_Tp, _Alloc>::size_type erase_if(__debug::vector<_Tp, _Alloc>& __cont, _Predicate __pred) { - _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __unsafe_cont = __cont; - const auto __osz = __cont.size(); - const auto __end = __unsafe_cont.end(); - auto __removed = std::__remove_if(__unsafe_cont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__niter_wrap(__cont.begin(), __removed), - __cont.end()); - return __osz - __cont.size(); - } - - return 0; + return __detail::__erase_if(__cont, __cont._M_base(), std::move(__pred)); } template<typename _Tp, typename _Alloc, typename _Up = _Tp> diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque index ea426196ca54..3899b68e7367 100644 --- a/libstdc++-v3/include/std/deque +++ b/libstdc++-v3/include/std/deque @@ -68,6 +68,7 @@ #include <bits/stl_uninitialized.h> #include <bits/stl_deque.h> #include <bits/range_access.h> +#include <bits/erase_if.h> #include <bits/deque.tcc> #define __glibcxx_want_algorithm_default_value_type @@ -103,19 +104,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type erase_if(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, _Predicate __pred) - { - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed = std::__remove_if(__cont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__removed, __end); - return __osz - __cont.size(); - } - - return 0; - } + { return __detail::__erase_if(__cont, __cont, std::move(__pred)); } template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> diff --git a/libstdc++-v3/include/std/forward_list b/libstdc++-v3/include/std/forward_list index 413fcaf3b4c4..ff0c58455cf5 100644 --- a/libstdc++-v3/include/std/forward_list +++ b/libstdc++-v3/include/std/forward_list @@ -75,14 +75,14 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> - inline typename forward_list<_Tp, _Alloc>::size_type - erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred) + inline typename _GLIBCXX_STD_C::forward_list<_Tp, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::forward_list<_Tp, _Alloc>& __cont, _Predicate __pred) { return __cont.remove_if(__pred); } template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> - inline typename forward_list<_Tp, _Alloc>::size_type - erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value) + inline typename _GLIBCXX_STD_C::forward_list<_Tp, _Alloc>::size_type + erase(_GLIBCXX_STD_C::forward_list<_Tp, _Alloc>& __cont, const _Up& __value) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4135. helper lambda of std::erase for list should specify return type diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector index df95c1e5c021..c22a9e1f9b40 100644 --- a/libstdc++-v3/include/std/inplace_vector +++ b/libstdc++-v3/include/std/inplace_vector @@ -46,6 +46,7 @@ #include <bits/stl_construct.h> #include <bits/stl_uninitialized.h> #include <bits/stl_algo.h> // rotate +#include <bits/erase_if.h> namespace std _GLIBCXX_VISIBILITY(default) { @@ -1339,17 +1340,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER _Predicate __pred) { if constexpr (_Nm != 0) - { - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed = std::__remove_if(__cont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__removed, __end); - return __osz - __cont.size(); - } - } + return __detail::__erase_if(__cont, __cont, std::move(__pred)); return 0; } diff --git a/libstdc++-v3/include/std/list b/libstdc++-v3/include/std/list index 3feff4d7b8b0..a3e7c81680a9 100644 --- a/libstdc++-v3/include/std/list +++ b/libstdc++-v3/include/std/list @@ -99,14 +99,14 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> - inline typename list<_Tp, _Alloc>::size_type - erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred) + inline typename _GLIBCXX_STD_C::list<_Tp, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::list<_Tp, _Alloc>& __cont, _Predicate __pred) { return __cont.remove_if(__pred); } template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> - inline typename list<_Tp, _Alloc>::size_type - erase(list<_Tp, _Alloc>& __cont, const _Up& __value) + inline typename _GLIBCXX_STD_C::list<_Tp, _Alloc>::size_type + erase(_GLIBCXX_STD_C::list<_Tp, _Alloc>& __cont, const _Up& __value) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4135. helper lambda of std::erase for list should specify return type diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map index b4d39959f0d1..88e549411afd 100644 --- a/libstdc++-v3/include/std/map +++ b/libstdc++-v3/include/std/map @@ -101,29 +101,26 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Key, typename _Tp, typename _Compare, typename _Alloc, typename _Predicate> - inline typename map<_Key, _Tp, _Compare, _Alloc>::size_type - erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + inline typename _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } template<typename _Key, typename _Tp, typename _Compare, typename _Alloc, typename _Predicate> - inline typename multimap<_Key, _Tp, _Compare, _Alloc>::size_type - erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + inline typename _GLIBCXX_STD_C::multimap<_Key, _Tp, + _Compare, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_MAP */ diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set index 95b9e26a99fb..af6d3814b4b1 100644 --- a/libstdc++-v3/include/std/set +++ b/libstdc++-v3/include/std/set @@ -95,29 +95,25 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Key, typename _Compare, typename _Alloc, typename _Predicate> - inline typename set<_Key, _Compare, _Alloc>::size_type - erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + inline typename _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } template<typename _Key, typename _Compare, typename _Alloc, typename _Predicate> - inline typename multiset<_Key, _Compare, _Alloc>::size_type - erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + inline typename _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __cont, + _Predicate __pred) + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif /* _GLIBCXX_SET */ diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string index 3748e64964f9..c2b37391fc7a 100644 --- a/libstdc++-v3/include/std/string +++ b/libstdc++-v3/include/std/string @@ -54,6 +54,7 @@ #include <bits/stdexcept_throw.h> #include <bits/stl_algobase.h> #include <bits/range_access.h> +#include <bits/erase_if.h> #include <bits/basic_string.h> #include <bits/basic_string.tcc> #if (_GLIBCXX_HOSTED && __cpp_exceptions && __cplusplus > 202302L \ @@ -108,15 +109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename _Predicate> constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred) - { - using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed = std::__remove_if(__cont.begin(), __end, - std::move(__pred)); - __cont.erase(__removed, __end); - return __osz - __cont.size(); - } + { return __detail::__erase_if(__cont, __cont, std::move(__pred)); } template<typename _CharT, typename _Traits, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)> diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map index c49c5c6835f5..9166f569ab1d 100644 --- a/libstdc++-v3/include/std/unordered_map +++ b/libstdc++-v3/include/std/unordered_map @@ -80,35 +80,30 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Key, typename _Tp, typename _Hash, typename _CPred, typename _Alloc, typename _Predicate> - inline typename unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>::size_type - erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, + inline typename _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, + _CPred, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, + _CPred, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& - __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } template<typename _Key, typename _Tp, typename _Hash, typename _CPred, typename _Alloc, typename _Predicate> - inline typename unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>:: - size_type - erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, + inline typename _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, + _CPred, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, + _CPred, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& - __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif // C++11 diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/include/std/unordered_set index 512d542a0b58..157f72ce32df 100644 --- a/libstdc++-v3/include/std/unordered_set +++ b/libstdc++-v3/include/std/unordered_set @@ -78,34 +78,28 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++17 -#if __cplusplus > 201703L +#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Key, typename _Hash, typename _CPred, typename _Alloc, typename _Predicate> - inline typename unordered_set<_Key, _Hash, _CPred, _Alloc>::size_type - erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont, + inline typename _GLIBCXX_STD_C::unordered_set<_Key, _Hash, + _CPred, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>& - __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } template<typename _Key, typename _Hash, typename _CPred, typename _Alloc, typename _Predicate> - inline typename unordered_multiset<_Key, _Hash, _CPred, _Alloc>::size_type - erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont, + inline typename _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, + _CPred, _Alloc>::size_type + erase_if(_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { - _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& - __ucont = __cont; - return __detail::__erase_nodes_if(__cont, __ucont, __pred); - } + { return __detail::__erase_nodes_if(__cont, __cont, __pred); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif // C++20 +#endif // __cpp_lib_erase_if #endif // C++11 diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 61c750f94ff2..343483e95191 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -68,6 +68,7 @@ #include <bits/stl_vector.h> #include <bits/stl_bvector.h> #include <bits/range_access.h> +#include <bits/erase_if.h> #ifndef _GLIBCXX_EXPORT_TEMPLATE # include <bits/vector.tcc> @@ -114,19 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp, typename _Alloc, typename _Predicate> constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type erase_if(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, _Predicate __pred) - { - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed = std::__remove_if(__cont.begin(), __end, - std::move(__pred)); - if (__removed != __end) - { - __cont.erase(__removed, __end); - return __osz - __cont.size(); - } - - return 0; - } + { return __detail::__erase_if(__cont, __cont, std::move(__pred)); } template<typename _Tp, typename _Alloc, typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)> diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc b/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc new file mode 100644 index 000000000000..b381ad157382 --- /dev/null +++ b/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc @@ -0,0 +1,25 @@ +// { dg-do run { target c++20 } } + +#include <debug/string> +#include <testsuite_hooks.h> + +using __gnu_debug::string; + +void test01() +{ + string str("abcdefghijklmnopqrstuvwxyz"); + + auto before = str.begin(); + auto last = str.end() - 1; + + VERIFY( std::erase(str, 'd') == 1 ); + + VERIFY(before._M_singular()); + VERIFY(last._M_singular()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc new file mode 100644 index 000000000000..061dfcbd9e31 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc @@ -0,0 +1,26 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <forward_list> +#include <testsuite_hooks.h> + +void test01() +{ + std::forward_list<int> fl({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + + auto before = ++fl.begin(); + auto match = std::next(fl.begin(), 6); + auto last = std::next(fl.begin(), 9); + + VERIFY( std::erase(fl, 6) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc new file mode 100644 index 000000000000..15194173cc34 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc @@ -0,0 +1,27 @@ +// { dg-do run { target c++20 } } + +#include <debug/forward_list> +#include <testsuite_hooks.h> + +using __gnu_debug::forward_list; + +void test01() +{ + forward_list<int> fl({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + + auto before = ++fl.begin(); + auto match = std::next(fl.begin(), 6); + auto last = std::next(fl.begin(), 9); + + VERIFY( std::erase(fl, 6) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc b/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc new file mode 100644 index 000000000000..d6210daf3446 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc @@ -0,0 +1,29 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <list> +#include <testsuite_hooks.h> + +void test01() +{ + std::list<int> l; + + for (int i = 0; i != 10; ++i) + l.push_back(i); + + auto before = ++l.begin(); + auto match = std::next(l.begin(), 6); + auto last = --l.end(); + + VERIFY( std::erase(l, 6) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc b/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc new file mode 100644 index 000000000000..57137fd08d62 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc @@ -0,0 +1,30 @@ +// { dg-do run { target c++20 } } + +#include <debug/list> +#include <testsuite_hooks.h> + +using __gnu_debug::list; + +void test01() +{ + list<int> l; + + for (int i = 0; i != 10; ++i) + l.push_back(i); + + auto before = ++l.begin(); + auto match = std::next(l.begin(), 6); + auto last = --l.end(); + + VERIFY( std::erase(l, 6) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc new file mode 100644 index 000000000000..dfdfc1340fac --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc @@ -0,0 +1,33 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +void test01() +{ + std::map<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = ++m.begin(); + auto match = std::next(m.begin(), 6); + auto last = std::next(m.begin(), 9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..ee080c31160f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc @@ -0,0 +1,34 @@ +// { dg-do run { target c++20 } } + +#include <debug/map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +using __gnu_debug::map; + +void test01() +{ + map<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = ++m.begin(); + auto match = std::next(m.begin(), 6); + auto last = std::next(m.begin(), 9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc new file mode 100644 index 000000000000..30b6b65e703c --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc @@ -0,0 +1,33 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +void test01() +{ + std::multimap<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = ++m.begin(); + auto match = std::next(m.begin(), 6); + auto last = std::next(m.begin(), 9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..c9f740ea4e6f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc @@ -0,0 +1,34 @@ +// { dg-do run { target c++20 } } + +#include <debug/map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +using __gnu_debug::multimap; + +void test01() +{ + multimap<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = ++m.begin(); + auto match = std::next(m.begin(), 6); + auto last = std::next(m.begin(), 9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc new file mode 100644 index 000000000000..e54eaa797f87 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc @@ -0,0 +1,31 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +void test01() +{ + std::multiset<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = ++s.begin(); + auto match = std::next(s.begin(), 6); + auto last = std::next(s.begin(), 9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..c85b76fc506d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc @@ -0,0 +1,32 @@ +// { dg-do run { target c++20 } } + +#include <debug/set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +using __gnu_debug::multiset; + +void test01() +{ + multiset<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = ++s.begin(); + auto match = std::next(s.begin(), 6); + auto last = std::next(s.begin(), 9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc new file mode 100644 index 000000000000..e8c64628a658 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc @@ -0,0 +1,31 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +void test01() +{ + std::set<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = ++s.begin(); + auto match = std::next(s.begin(), 6); + auto last = std::next(s.begin(), 9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..99dde9bfcf29 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc @@ -0,0 +1,32 @@ +// { dg-do run { target c++20 } } + +#include <debug/set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +using __gnu_debug::set; + +void test01() +{ + set<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = ++s.begin(); + auto match = std::next(s.begin(), 6); + auto last = std::next(s.begin(), 9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc new file mode 100644 index 000000000000..e7ac643c8ec5 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc @@ -0,0 +1,33 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +void test01() +{ + std::unordered_map<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = m.find(1); + auto match = m.find(6); + auto last = m.find(9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..303692838ac4 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc @@ -0,0 +1,34 @@ +// { dg-do run { target c++20 } } + +#include <debug/unordered_map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +using __gnu_debug::unordered_map; + +void test01() +{ + unordered_map<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = m.find(1); + auto match = m.find(6); + auto last = m.find(9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc new file mode 100644 index 000000000000..e8d98c96e6b6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc @@ -0,0 +1,33 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <unordered_map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +void test01() +{ + std::unordered_multimap<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = m.find(1); + auto match = m.find(6); + auto last = m.find(9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..375393365051 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc @@ -0,0 +1,34 @@ +// { dg-do run { target c++20 } } + +#include <debug/unordered_map> +#include <testsuite_hooks.h> + +auto is_six_pair = [](const std::pair<const int, int>& p) +{ + return p.first == 6; +}; + +using __gnu_debug::unordered_multimap; + +void test01() +{ + unordered_multimap<int, int> m; + for (int i = 0; i != 10; ++i) + m.insert({ i, i }); + + auto before = m.find(1); + auto match = m.find(6); + auto last = m.find(9); + + VERIFY( std::erase_if(m, is_six_pair) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc new file mode 100644 index 000000000000..8969a9dad5f1 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc @@ -0,0 +1,31 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +void test01() +{ + std::unordered_multiset<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = s.find(1); + auto match = s.find(6); + auto last = s.find(9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..f5ec00e2c1a6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc @@ -0,0 +1,32 @@ +// { dg-do run { target c++20 } } + +#include <debug/unordered_set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +using __gnu_debug::unordered_multiset; + +void test01() +{ + unordered_multiset<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = s.find(1); + auto match = s.find(6); + auto last = s.find(9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc new file mode 100644 index 000000000000..c725b94558ab --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc @@ -0,0 +1,31 @@ +// { dg-do run { target c++20 } } +// { dg-require-debug-mode "" } + +#include <unordered_set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +void test01() +{ + std::unordered_set<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = s.find(1); + auto match = s.find(6); + auto last = s.find(9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc new file mode 100644 index 000000000000..61c1cffca222 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc @@ -0,0 +1,32 @@ +// { dg-do run { target c++20 } } + +#include <debug/unordered_set> +#include <testsuite_hooks.h> + +auto is_six = [](int p) +{ return p == 6; }; + +using __gnu_debug::unordered_set; + +void test01() +{ + unordered_set<int> s; + for (int i = 0; i != 10; ++i) + s.insert(i); + + auto before = s.find(1); + auto match = s.find(6); + auto last = s.find(9); + + VERIFY( std::erase_if(s, is_six) == 1 ); + + VERIFY(before._M_dereferenceable()); + VERIFY(match._M_singular()); + VERIFY(last._M_dereferenceable()); +} + +int main() +{ + test01(); + return 0; +}
