From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id C4BE93858C60; Thu, 7 Oct 2021 16:52:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C4BE93858C60 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-4233] libstdc++: Avoid debug checks in uniform container erasure functions X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 5c1838c01652a403498e27024cb0e5ea66376353 X-Git-Newrev: 561078480ffb5adb68577276c6b23e4ee7b39272 Message-Id: <20211007165243.C4BE93858C60@sourceware.org> Date: Thu, 7 Oct 2021 16:52:43 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Oct 2021 16:52:43 -0000 https://gcc.gnu.org/g:561078480ffb5adb68577276c6b23e4ee7b39272 commit r12-4233-g561078480ffb5adb68577276c6b23e4ee7b39272 Author: Jonathan Wakely Date: Thu Oct 7 14:40:26 2021 +0100 libstdc++: Avoid debug checks in uniform container erasure functions In commit r12-4083 I tried to make the std::erase and std::erase_if function avoid the unnecessary overhead of safe iterators. It didn't work, for two reasons. Firstly, for the RB tree containers the __niter_base function is a no-op (because the iterators aren't random access) so the safe iterators were still used. Secondly, for the cases where __niter_base did remove the safe iterator layer, there was still unnecessary overhead to create a new safe iterator and link it to the container. This solves the problem by simply binding a reference to the non-debug version of the conainer. For normal mode this is a no-op, and for debug mode it binds a reference to the debug container's base class. That means the rest of the function operates directly on the non-debug container, and avoids all checking. For std::basic_string there's no need to unwrap anything, because we use std::basic_string directly in debug mode anyway. libstdc++-v3/ChangeLog: * include/bits/erase_if.h (__erase_nodes_if): Remove redundant __niter_base calls. * include/std/string (erase, erase_if): Likewise. * include/std/deque (erase, erase_if): Access non-debug container directly. * include/std/map (erase, erase_if): Likewise. * include/std/set (erase, erase_if): Likewise. * include/std/unordered_map (erase, erase_if): Likewise. * include/std/unordered_set (erase, erase_if): Likewise. * include/std/vector (erase, erase_if): Likewise. * include/experimental/deque (erase, erase_if): Likewise. * include/experimental/map (erase, erase_if): Likewise. * include/experimental/set (erase, erase_if): Likewise. * include/experimental/unordered_map (erase, erase_if): Likewise. * include/experimental/unordered_set (erase, erase_if): Likewise. * include/experimental/vector (erase, erase_if): Likewise. Diff: --- libstdc++-v3/include/bits/erase_if.h | 3 +-- libstdc++-v3/include/experimental/deque | 8 +++---- libstdc++-v3/include/experimental/map | 10 +++++++-- libstdc++-v3/include/experimental/set | 10 +++++++-- libstdc++-v3/include/experimental/unordered_map | 12 +++++++++-- libstdc++-v3/include/experimental/unordered_set | 11 ++++++++-- libstdc++-v3/include/experimental/vector | 8 +++---- libstdc++-v3/include/std/deque | 28 ++++++++++++------------- libstdc++-v3/include/std/map | 10 +++++++-- libstdc++-v3/include/std/set | 10 +++++++-- libstdc++-v3/include/std/string | 18 +++++++--------- libstdc++-v3/include/std/unordered_map | 12 +++++++++-- libstdc++-v3/include/std/unordered_set | 11 ++++++++-- libstdc++-v3/include/std/vector | 26 +++++++++++------------ 14 files changed, 114 insertions(+), 63 deletions(-) diff --git a/libstdc++-v3/include/bits/erase_if.h b/libstdc++-v3/include/bits/erase_if.h index 7716e1a953c..8d1d23168fa 100644 --- a/libstdc++-v3/include/bits/erase_if.h +++ b/libstdc++-v3/include/bits/erase_if.h @@ -51,8 +51,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __erase_nodes_if(_Container& __cont, _Predicate __pred) { typename _Container::size_type __num = 0; - for (auto __iter = std::__niter_base(__cont.begin()), - __last = std::__niter_base(__cont.end()); + for (auto __iter = __cont.begin(), __last = __cont.end(); __iter != __last;) { if (__pred(*__iter)) diff --git a/libstdc++-v3/include/experimental/deque b/libstdc++-v3/include/experimental/deque index a76fb659bbf..710833ebcad 100644 --- a/libstdc++-v3/include/experimental/deque +++ b/libstdc++-v3/include/experimental/deque @@ -50,16 +50,16 @@ inline namespace fundamentals_v2 inline void erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred) { - __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred), - __cont.end()); + _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __c = __cont; + __c.erase(std::remove_if(__c.begin(), __c.end(), __pred), __c.end()); } template inline void erase(deque<_Tp, _Alloc>& __cont, const _Up& __value) { - __cont.erase(std::remove(__cont.begin(), __cont.end(), __value), - __cont.end()); + _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __c = __cont; + __c.erase(std::remove(__c.begin(), __c.end(), __value), __c.end()); } namespace pmr { diff --git a/libstdc++-v3/include/experimental/map b/libstdc++-v3/include/experimental/map index 0c0f42222f5..ef69fadf944 100644 --- a/libstdc++-v3/include/experimental/map +++ b/libstdc++-v3/include/experimental/map @@ -50,13 +50,19 @@ inline namespace fundamentals_v2 typename _Predicate> inline void erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __c = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } template inline void erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __c = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } namespace pmr { template> diff --git a/libstdc++-v3/include/experimental/set b/libstdc++-v3/include/experimental/set index c3f5433e995..7a5986aec0e 100644 --- a/libstdc++-v3/include/experimental/set +++ b/libstdc++-v3/include/experimental/set @@ -50,13 +50,19 @@ inline namespace fundamentals_v2 typename _Predicate> inline void erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __c = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } template inline void erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __c = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } namespace pmr { template> diff --git a/libstdc++-v3/include/experimental/unordered_map b/libstdc++-v3/include/experimental/unordered_map index 0b915ab13e5..eba989713fa 100644 --- a/libstdc++-v3/include/experimental/unordered_map +++ b/libstdc++-v3/include/experimental/unordered_map @@ -51,14 +51,22 @@ inline namespace fundamentals_v2 inline void erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __c + = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } template inline void erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __c + = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } namespace pmr { template, diff --git a/libstdc++-v3/include/experimental/unordered_set b/libstdc++-v3/include/experimental/unordered_set index 87db4464401..bc5cc11419e 100644 --- a/libstdc++-v3/include/experimental/unordered_set +++ b/libstdc++-v3/include/experimental/unordered_set @@ -51,14 +51,21 @@ inline namespace fundamentals_v2 inline void erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>& __c = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } template inline void erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { std::__detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __c + = __cont; + std::__detail::__erase_nodes_if(__c, __pred); + } namespace pmr { template, diff --git a/libstdc++-v3/include/experimental/vector b/libstdc++-v3/include/experimental/vector index a14aedf3364..c45a500ef5e 100644 --- a/libstdc++-v3/include/experimental/vector +++ b/libstdc++-v3/include/experimental/vector @@ -52,16 +52,16 @@ inline namespace fundamentals_v2 inline void erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred) { - __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred), - __cont.end()); + _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __c = __cont; + __c.erase(std::remove_if(__c.begin(), __c.end(), __pred), __c.end()); } template inline void erase(vector<_Tp, _Alloc>& __cont, const _Up& __value) { - __cont.erase(std::remove(__cont.begin(), __cont.end(), __value), - __cont.end()); + _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __c = __cont; + __c.erase(std::remove(__c.begin(), __c.end(), __value), __c.end()); } namespace pmr { diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque index b2a7cee483a..71993e757a5 100644 --- a/libstdc++-v3/include/std/deque +++ b/libstdc++-v3/include/std/deque @@ -95,28 +95,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline typename deque<_Tp, _Alloc>::size_type erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred) { + _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __c = __cont; using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__end), - __ops::__pred_iter(std::ref(__pred)))); - __cont.erase(std::__niter_wrap(__end, __removed), __end); - return __osz - __cont.size(); + const auto __osz = __c.size(); + const auto __end = __c.end(); + auto __removed = std::__remove_if(__c.begin(), __end, + __ops::__pred_iter(std::ref(__pred))); + __c.erase(__removed, __end); + return __osz - __c.size(); } template inline typename deque<_Tp, _Alloc>::size_type erase(deque<_Tp, _Alloc>& __cont, const _Up& __value) { + _GLIBCXX_STD_C::deque<_Tp, _Alloc>& __c = __cont; using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__end), - __ops::__iter_equals_val(__value))); - __cont.erase(std::__niter_wrap(__end, __removed), __end); - return __osz - __cont.size(); + const auto __osz = __c.size(); + const auto __end = __c.end(); + auto __removed = std::__remove_if(__c.begin(), __end, + __ops::__iter_equals_val(__value)); + __c.erase(__removed, __end); + return __osz - __c.size(); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map index 44bd44b5922..29265580995 100644 --- a/libstdc++-v3/include/std/map +++ b/libstdc++-v3/include/std/map @@ -95,13 +95,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename _Predicate> inline typename map<_Key, _Tp, _Compare, _Alloc>::size_type erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __c = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } template inline typename multimap<_Key, _Tp, _Compare, _Alloc>::size_type erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __c = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++20 diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set index f1e1864937a..24e6e633624 100644 --- a/libstdc++-v3/include/std/set +++ b/libstdc++-v3/include/std/set @@ -91,13 +91,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename _Predicate> inline typename set<_Key, _Compare, _Alloc>::size_type erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __c = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } template inline typename multiset<_Key, _Compare, _Alloc>::size_type erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __c = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++20 diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string index 7f994147a33..95412b6f7a3 100644 --- a/libstdc++-v3/include/std/string +++ b/libstdc++-v3/include/std/string @@ -124,12 +124,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred) { using namespace __gnu_cxx; - using _It = typename basic_string<_CharT, _Traits, _Alloc>::iterator; const auto __osz = __cont.size(); - _It __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__cont.end()), - __ops::__pred_iter(std::ref(__pred)))); - __cont.erase(__removed, __cont.end()); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + __ops::__pred_iter(std::ref(__pred))); + __cont.erase(__removed, __end); return __osz - __cont.size(); } @@ -138,12 +137,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value) { using namespace __gnu_cxx; - using _It = typename basic_string<_CharT, _Traits, _Alloc>::iterator; const auto __osz = __cont.size(); - _It __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__cont.end()), - __ops::__iter_equals_val(__value))); - __cont.erase(__removed, __cont.end()); + const auto __end = __cont.end(); + auto __removed = std::__remove_if(__cont.begin(), __end, + __ops::__iter_equals_val(__value)); + __cont.erase(__removed, __end); return __osz - __cont.size(); } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/unordered_map b/libstdc++-v3/include/std/unordered_map index e6715069362..774c21fc28b 100644 --- a/libstdc++-v3/include/std/unordered_map +++ b/libstdc++-v3/include/std/unordered_map @@ -83,7 +83,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline typename unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>::size_type erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __c + = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } template @@ -91,7 +95,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION size_type erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __c + = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++20 diff --git a/libstdc++-v3/include/std/unordered_set b/libstdc++-v3/include/std/unordered_set index 1ad93d0031b..3859eeaebd0 100644 --- a/libstdc++-v3/include/std/unordered_set +++ b/libstdc++-v3/include/std/unordered_set @@ -83,14 +83,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline typename unordered_set<_Key, _Hash, _CPred, _Alloc>::size_type erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>& __c = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } template inline typename unordered_multiset<_Key, _Hash, _CPred, _Alloc>::size_type erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont, _Predicate __pred) - { return __detail::__erase_nodes_if(__cont, __pred); } + { + _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __c + = __cont; + return __detail::__erase_nodes_if(__c, __pred); + } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // C++20 diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 3b275e249fc..835fa8aeb69 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -105,28 +105,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline typename vector<_Tp, _Alloc>::size_type erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred) { + _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __c = __cont; using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__end), + const auto __osz = __c.size(); + const auto __end = __c.end(); + auto __removed(std::__remove_if(__c.begin(), __end, __ops::__pred_iter(std::ref(__pred)))); - __cont.erase(std::__niter_wrap(__end, __removed), __end); - return __osz - __cont.size(); + __c.erase(__removed, __end); + return __osz - __c.size(); } template inline typename vector<_Tp, _Alloc>::size_type erase(vector<_Tp, _Alloc>& __cont, const _Up& __value) { + _GLIBCXX_STD_C::vector<_Tp, _Alloc>& __c = __cont; using namespace __gnu_cxx; - const auto __osz = __cont.size(); - const auto __end = __cont.end(); - auto __removed(std::__remove_if(std::__niter_base(__cont.begin()), - std::__niter_base(__end), - __ops::__iter_equals_val(__value))); - __cont.erase(std::__niter_wrap(__end, __removed), __end); - return __osz - __cont.size(); + const auto __osz = __c.size(); + const auto __end = __c.end(); + auto __removed = std::__remove_if(__c.begin(), __end, + __ops::__iter_equals_val(__value)); + __c.erase(__removed, __end); + return __osz - __c.size(); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std