public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, libstdc++] Uniform container erasure for c++20.
@ 2018-11-24 18:55 Ed Smith-Rowland
  2018-11-26 11:18 ` Jonathan Wakely
  0 siblings, 1 reply; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-24 18:55 UTC (permalink / raw)
  To: libstdc++, gcc-patches, Jonathan Wakely

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

All,

I's very late but uniform container erasure is, I think, the last little 
tidbit to graduate from fundamentals/v2 to std at the last meeting.  I 
think it would be a shame not to nudge this into gcc-9.  The routines 
are very short so I just copied them. Ditto the testcases (with 
adjustments).  The node erasure tool was moved from experimental to 
std/bits and adjustments made to affected *set/*map headers.

The experimental code has been in our tree since 2015.

This builds and tests clean on x86_64-linux.

Ed



[-- Attachment #2: patch_erasure --]
[-- Type: text/plain, Size: 34482 bytes --]

Index: include/Makefile.am
===================================================================
--- include/Makefile.am	(revision 266430)
+++ include/Makefile.am	(working copy)
@@ -106,6 +106,7 @@
 	${bits_srcdir}/cpp_type_traits.h \
 	${bits_srcdir}/deque.tcc \
 	${bits_srcdir}/enable_special_members.h \
+	${bits_srcdir}/erase_if.h \
 	${bits_srcdir}/forward_list.h \
 	${bits_srcdir}/forward_list.tcc \
 	${bits_srcdir}/fs_dir.h \
@@ -710,7 +711,6 @@
 experimental_bits_srcdir = ${glibcxx_srcdir}/include/experimental/bits
 experimental_bits_builddir = ./experimental/bits
 experimental_bits_headers = \
-	${experimental_bits_srcdir}/erase_if.h \
 	${experimental_bits_srcdir}/lfts_config.h \
 	${experimental_bits_srcdir}/net.h \
 	${experimental_bits_srcdir}/shared_ptr.h \
Index: include/Makefile.in
===================================================================
--- include/Makefile.in	(revision 266430)
+++ include/Makefile.in	(working copy)
@@ -449,6 +449,7 @@
 	${bits_srcdir}/cpp_type_traits.h \
 	${bits_srcdir}/deque.tcc \
 	${bits_srcdir}/enable_special_members.h \
+	${bits_srcdir}/erase_if.h \
 	${bits_srcdir}/forward_list.h \
 	${bits_srcdir}/forward_list.tcc \
 	${bits_srcdir}/fs_dir.h \
@@ -1052,7 +1053,6 @@
 experimental_bits_srcdir = ${glibcxx_srcdir}/include/experimental/bits
 experimental_bits_builddir = ./experimental/bits
 experimental_bits_headers = \
-	${experimental_bits_srcdir}/erase_if.h \
 	${experimental_bits_srcdir}/lfts_config.h \
 	${experimental_bits_srcdir}/net.h \
 	${experimental_bits_srcdir}/shared_ptr.h \
Index: include/bits/erase_if.h
===================================================================
--- include/bits/erase_if.h	(revision 266430)
+++ include/bits/erase_if.h	(working copy)
@@ -1,4 +1,4 @@
-// <experimental/bits/erase_if.h> -*- C++ -*-
+// <bits/erase_if.h> -*- C++ -*-
 
 // Copyright (C) 2015-2018 Free Software Foundation, Inc.
 //
@@ -22,27 +22,22 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-/** @file experimental/bits/erase_if.h
+/** @file bits/erase_if.h
  *  This is an internal header file, included by other library headers.
  *  Do not attempt to use it directly.
  */
 
-#ifndef _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
-#define _GLIBCXX_EXPERIMENTAL_ERASE_IF_H 1
+#ifndef _GLIBCXX_ERASE_IF_H
+#define _GLIBCXX_ERASE_IF_H 1
 
 #pragma GCC system_header
 
 #if __cplusplus >= 201402L
-#include <experimental/bits/lfts_config.h>
 
 namespace std
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-namespace experimental
-{
-inline namespace fundamentals_v2
-{
   namespace __detail
   {
     template<typename _Container, typename _Predicate>
@@ -59,8 +54,6 @@
 	}
       }
   } // namespace __detail
-} // inline namespace fundamentals_v2
-} // namespace experimental
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
@@ -67,4 +60,4 @@
 
 #endif // C++14
 
-#endif // _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
+#endif // _GLIBCXX_ERASE_IF_H
Index: include/experimental/bits/erase_if.h
===================================================================
--- include/experimental/bits/erase_if.h	(revision 266430)
+++ include/experimental/bits/erase_if.h	(nonexistent)
@@ -1,70 +0,0 @@
-// <experimental/bits/erase_if.h> -*- C++ -*-
-
-// Copyright (C) 2015-2018 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-// <http://www.gnu.org/licenses/>.
-
-/** @file experimental/bits/erase_if.h
- *  This is an internal header file, included by other library headers.
- *  Do not attempt to use it directly.
- */
-
-#ifndef _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
-#define _GLIBCXX_EXPERIMENTAL_ERASE_IF_H 1
-
-#pragma GCC system_header
-
-#if __cplusplus >= 201402L
-#include <experimental/bits/lfts_config.h>
-
-namespace std
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-namespace experimental
-{
-inline namespace fundamentals_v2
-{
-  namespace __detail
-  {
-    template<typename _Container, typename _Predicate>
-      void
-      __erase_nodes_if(_Container& __cont, _Predicate __pred)
-      {
-	for (auto __iter = __cont.begin(), __last = __cont.end();
-	     __iter != __last;)
-	{
-	  if (__pred(*__iter))
-	    __iter = __cont.erase(__iter);
-	  else
-	    ++__iter;
-	}
-      }
-  } // namespace __detail
-} // inline namespace fundamentals_v2
-} // namespace experimental
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
-#endif // C++14
-
-#endif // _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
Index: include/experimental/map
===================================================================
--- include/experimental/map	(revision 266430)
+++ include/experimental/map	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <map>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -49,13 +49,13 @@
 	   typename _Predicate>
     inline void
     erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
 	   typename _Predicate>
     inline void
     erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Tp, typename _Compare = less<_Key>>
Index: include/experimental/set
===================================================================
--- include/experimental/set	(revision 266430)
+++ include/experimental/set	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <set>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -49,13 +49,13 @@
 	   typename _Predicate>
     inline void
     erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Compare, typename _Alloc,
 	   typename _Predicate>
     inline void
     erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Compare = less<_Key>>
Index: include/experimental/unordered_map
===================================================================
--- include/experimental/unordered_map	(revision 266430)
+++ include/experimental/unordered_map	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <unordered_map>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -50,7 +50,7 @@
     inline void
     erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
 	   typename _Alloc, typename _Predicate>
@@ -57,7 +57,7 @@
     inline void
     erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Tp, typename _Hash = hash<_Key>,
Index: include/experimental/unordered_set
===================================================================
--- include/experimental/unordered_set	(revision 266430)
+++ include/experimental/unordered_set	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <unordered_set>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -50,7 +50,7 @@
     inline void
     erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
 	   typename _Predicate>
@@ -57,7 +57,7 @@
     inline void
     erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Hash = hash<_Key>,
Index: include/std/deque
===================================================================
--- include/std/deque	(revision 266430)
+++ include/std/deque	(working copy)
@@ -87,4 +87,27 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    void
+    erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    void
+    erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_DEQUE */
Index: include/std/forward_list
===================================================================
--- include/std/forward_list	(revision 266430)
+++ include/std/forward_list	(working copy)
@@ -60,6 +60,27 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void 
+    erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
+    { __cont.remove_if(__pred); }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      using __elem_type = typename forward_list<_Tp, _Alloc>::value_type;
+      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_FORWARD_LIST
Index: include/std/list
===================================================================
--- include/std/list	(revision 266430)
+++ include/std/list	(working copy)
@@ -84,4 +84,25 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
+    { __cont.remove_if(__pred); }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      using __elem_type = typename list<_Tp, _Alloc>::value_type;
+      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_LIST */
Index: include/std/map
===================================================================
--- include/std/map	(revision 266430)
+++ include/std/map	(working copy)
@@ -61,6 +61,7 @@
 #include <bits/stl_map.h>
 #include <bits/stl_multimap.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/map>
@@ -90,4 +91,23 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_MAP */
Index: include/std/set
===================================================================
--- include/std/set	(revision 266430)
+++ include/std/set	(working copy)
@@ -61,6 +61,7 @@
 #include <bits/stl_set.h>
 #include <bits/stl_multiset.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/set>
@@ -86,4 +87,23 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_SET */
Index: include/std/string
===================================================================
--- include/std/string	(revision 266430)
+++ include/std/string	(working copy)
@@ -51,6 +51,7 @@
 #include <bits/range_access.h>
 #include <bits/basic_string.h>
 #include <bits/basic_string.tcc>
+#include <algorithm> // For remove and remove_if
 
 #if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -72,4 +73,28 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _CharT, typename _Traits, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
+    inline void
+    erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_STRING */
Index: include/std/unordered_map
===================================================================
--- include/std/unordered_map	(revision 266430)
+++ include/std/unordered_map	(working copy)
@@ -46,6 +46,7 @@
 #include <bits/hashtable.h>
 #include <bits/unordered_map.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/unordered_map>
@@ -76,6 +77,28 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+	   typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+	   typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_UNORDERED_MAP
Index: include/std/unordered_set
===================================================================
--- include/std/unordered_set	(revision 266430)
+++ include/std/unordered_set	(working copy)
@@ -46,6 +46,7 @@
 #include <bits/hashtable.h>
 #include <bits/unordered_set.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/unordered_set>
@@ -76,6 +77,15 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_UNORDERED_SET
Index: include/std/vector
===================================================================
--- include/std/vector	(revision 266430)
+++ include/std/vector	(working copy)
@@ -90,4 +90,27 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_VECTOR */
Index: testsuite/21_strings/basic_string/erasure.cc
===================================================================
--- testsuite/21_strings/basic_string/erasure.cc	(nonexistent)
+++ testsuite/21_strings/basic_string/erasure.cc	(working copy)
@@ -0,0 +1,53 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <string>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_vowel = [](const char c)
+  {
+    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
+  };
+
+  std::string str("cute fluffy kittens");
+  std::erase_if(str, is_vowel);
+  VERIFY( str == "ct flffy kttns" );
+}
+
+void
+test02()
+{
+  std::string str = "cute fluffy kittens";
+  std::erase(str, 'f');
+  VERIFY( str == "cute luy kittens" );
+  std::erase(str, 'z');
+  VERIFY( str == "cute luy kittens" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/deque/erasure.cc
===================================================================
--- testsuite/23_containers/deque/erasure.cc	(nonexistent)
+++ testsuite/23_containers/deque/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(d, is_odd);
+  std::deque<int> t{ 10, 12, 14, 18 };
+  VERIFY( d == t );
+}
+
+void
+test02()
+{
+  std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase(d, 14);
+  std::deque<int> t{ 10, 11, 12, 15, 17, 18, 19 };
+  VERIFY( d == t );
+  std::erase(d, 20);
+  VERIFY( d == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/forward_list/erasure.cc
===================================================================
--- testsuite/23_containers/forward_list/erasure.cc	(nonexistent)
+++ testsuite/23_containers/forward_list/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(fl, is_odd);
+  std::forward_list<int> t{ 10, 12, 14, 18 };
+  VERIFY( fl == t );
+}
+
+void
+test02()
+{
+  std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase(fl, 14);
+  std::forward_list<int> t{ 10, 11, 12, 15, 17, 18, 19 };
+  VERIFY( fl == t );
+  std::erase(fl, 20);
+  VERIFY( fl == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/list/erasure.cc
===================================================================
--- testsuite/23_containers/list/erasure.cc	(nonexistent)
+++ testsuite/23_containers/list/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::list<int> l{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(l, is_odd);
+  std::list<int> t{ 10, 12, 14, 18 };
+  VERIFY( l == t );
+}
+
+void
+test02()
+{
+  std::list<int> l{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
+  std::erase(l, 0);
+  std::list<int> t{ 11, 22, 33, 44 };
+  VERIFY( l == t );
+  std::erase(l, 55);
+  VERIFY( l == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/map/erasure.cc
===================================================================
--- testsuite/23_containers/map/erasure.cc	(nonexistent)
+++ testsuite/23_containers/map/erasure.cc	(working copy)
@@ -0,0 +1,61 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <map>
+#include <testsuite_hooks.h>
+
+auto is_odd_pair = [](const std::pair<const int, std::string>& p)
+{
+  return p.first % 2 != 0;
+};
+
+void
+test01()
+{
+  std::map<int, std::string> m{ { 10, "A" }, { 11, "B" },
+				{ 12, "C" }, { 14, "D" },
+				{ 15, "E" }, { 17, "F" },
+				{ 18, "G" }, { 19, "H" } };
+  std::erase_if(m, is_odd_pair);
+  std::map<int, std::string> t{ { 10, "A" }, { 12, "C" },
+				{ 14, "D" }, { 18, "G" } };
+  VERIFY( m == t );
+}
+
+void
+test02()
+{
+  std::multimap<int, std::string> mm{ { 20, "S" }, { 21, "T" },
+				      { 22, "U" }, { 22, "V" },
+				      { 23, "W" }, { 23, "X" },
+				      { 24, "Y" }, { 25, "Z" } };
+  std::erase_if(mm, is_odd_pair);
+  std::multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
+				     { 22, "V" }, { 24, "Y" } };
+  VERIFY( mm == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/set/erasure.cc
===================================================================
--- testsuite/23_containers/set/erasure.cc	(nonexistent)
+++ testsuite/23_containers/set/erasure.cc	(working copy)
@@ -0,0 +1,50 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <set>
+#include <testsuite_hooks.h>
+
+auto is_odd = [](const int i) { return i % 2 != 0; };
+
+void
+test01()
+{
+  std::set<int> s{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(s, is_odd);
+  std::set<int> t{ 10, 12, 14, 18 };
+  VERIFY( s == t );
+}
+
+void
+test02()
+{
+  std::multiset<int> ms{ 20, 21, 22, 22, 23, 23, 24, 25 };
+  std::erase_if(ms, is_odd);
+  std::multiset<int> t{ 20, 22, 22, 24 };
+  VERIFY( ms == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/unordered_map/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_map/erasure.cc	(nonexistent)
+++ testsuite/23_containers/unordered_map/erasure.cc	(working copy)
@@ -0,0 +1,61 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_odd_pair = [](const std::pair<const int, std::string>& p)
+{
+  return p.first % 2 != 0;
+};
+
+void
+test01()
+{
+  std::unordered_map<int, std::string> um{ { 10, "A" }, { 11, "B" },
+					   { 12, "C" }, { 14, "D" },
+					   { 15, "E" }, { 17, "F" },
+					   { 18, "G" }, { 19, "H" } };
+  std::erase_if(um, is_odd_pair);
+  std::unordered_map<int, std::string> t{ { 10, "A" }, { 12, "C" },
+					  { 14, "D" }, { 18, "G" } };
+  VERIFY( um == t );
+}
+
+void
+test02()
+{
+  std::unordered_multimap<int, std::string> umm{ { 20, "S" }, { 21, "T" },
+						 { 22, "U" }, { 22, "V" },
+						 { 23, "W" }, { 23, "X" },
+						 { 24, "Y" }, { 25, "Z" } };
+  std::erase_if(umm, is_odd_pair);
+  std::unordered_multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
+					       { 22, "V" }, { 24, "Y" } };
+  VERIFY( umm == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/unordered_set/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_set/erasure.cc	(nonexistent)
+++ testsuite/23_containers/unordered_set/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::unordered_set<int> us{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(us, is_odd);
+  std::unordered_set<int> t{ 10, 12, 14, 18 };
+  VERIFY( us == t );
+}
+
+void
+test02()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::unordered_multiset<int> ums{ 20, 21, 22, 22, 23, 23, 24, 25 };
+  std::erase_if(ums, is_odd);
+  std::unordered_multiset<int> t{ 20, 22, 22, 24 };
+  VERIFY( ums == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/vector/erasure.cc
===================================================================
--- testsuite/23_containers/vector/erasure.cc	(nonexistent)
+++ testsuite/23_containers/vector/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::vector<int> v{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(v, is_odd);
+  std::vector<int> t{ 10, 12, 14, 18 };
+  VERIFY( v == t );
+}
+
+void
+test02()
+{
+  std::vector<int> v{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
+  std::erase(v, 0);
+  std::vector<int> t{ 11, 22, 33, 44 };
+  VERIFY( v == t );
+  std::erase(v, 55);
+  VERIFY( v == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}

[-- Attachment #3: CL_erasure --]
[-- Type: text/plain, Size: 1257 bytes --]


2018-11-24  Edward Smith-Rowland  <3dw4rd@verizon.net>

	* include/Makefile.am: Move erase_if.h.
	* include/Makefile.in: Move erase_if.h.
	* include/experimental/bits/erase_if.h: Move ...
	* include/bits/erase_if.h: ... here.
	* include/experimental/map: Move erase_if.h.
	* include/experimental/set: Move erase_if.h.
	* include/experimental/unordered_map: Move erase_if.h.
	* include/experimental/unordered_set: Move erase_if.h.
	* include/std/deque (erase_if, erase): New functions.
	* include/std/forward_list: Ditto.
	* include/std/list: Ditto.
	* include/std/map: Ditto.
	* include/std/set: Ditto.
	* include/std/string: Ditto.
	* include/std/unordered_map: Ditto.
	* include/std/unordered_set: Ditto.
	* include/std/vector: Ditto.
	* testsuite/21_strings/basic_string/erasure.cc: New test.
	* testsuite/23_containers/deque/erasure.cc: New test.
	* testsuite/23_containers/forward_list/erasure.cc: New test.
	* testsuite/23_containers/list/erasure.cc: New test.
	* testsuite/23_containers/map/erasure.cc: New test.
	* testsuite/23_containers/set/erasure.cc: New test.
	* testsuite/23_containers/unordered_map/erasure.cc: New test.
	* testsuite/23_containers/unordered_set/erasure.cc: New test.
	* testsuite/23_containers/vector/erasure.cc: New test.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-24 18:55 [PATCH, libstdc++] Uniform container erasure for c++20 Ed Smith-Rowland
@ 2018-11-26 11:18 ` Jonathan Wakely
  2018-11-28 17:12   ` Ed Smith-Rowland
  2018-11-29 17:06   ` Ed Smith-Rowland
  0 siblings, 2 replies; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-26 11:18 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: libstdc++, gcc-patches

On 24/11/18 13:54 -0500, Ed Smith-Rowland wrote:
>All,
>
>I's very late but uniform container erasure is, I think, the last 
>little tidbit to graduate from fundamentals/v2 to std at the last 
>meeting.  I think it would be a shame not to nudge this into gcc-9.  
>The routines are very short so I just copied them. Ditto the testcases 
>(with adjustments).  The node erasure tool was moved from experimental 
>to std/bits and adjustments made to affected *set/*map headers.
>
>The experimental code has been in our tree since 2015.
>
>This builds and tests clean on x86_64-linux.

OK for trunk as it only touches experimental C++2a and TS material.
Thanks.

I pointed out to the committee that the erase_if functions added to
C++20 completely overlook P0646R1 "Improving the Return Value of
Erase-Like Algorithms" and so fail to preserve the useful information
returned by the members of the linked list containers.

I expect that to get fixed as a defect. If you have time and
motivation, I think we should make that change proactively in
libstdc++. The Library Fundamentals versions can continue to return
void, but the ones in namespace std can return the number of elements
removed.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-26 11:18 ` Jonathan Wakely
@ 2018-11-28 17:12   ` Ed Smith-Rowland
  2018-11-29  0:25     ` Jonathan Wakely
  2018-11-29 17:06   ` Ed Smith-Rowland
  1 sibling, 1 reply; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-28 17:12 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2207 bytes --]

On 11/26/18 6:18 AM, Jonathan Wakely wrote:
> On 24/11/18 13:54 -0500, Ed Smith-Rowland wrote:
>> All,
>>
>> I's very late but uniform container erasure is, I think, the last 
>> little tidbit to graduate from fundamentals/v2 to std at the last 
>> meeting.  I think it would be a shame not to nudge this into gcc-9.  
>> The routines are very short so I just copied them. Ditto the 
>> testcases (with adjustments).  The node erasure tool was moved from 
>> experimental to std/bits and adjustments made to affected *set/*map 
>> headers.
>>
>> The experimental code has been in our tree since 2015.
>>
>> This builds and tests clean on x86_64-linux.
>
> OK for trunk as it only touches experimental C++2a and TS material.
> Thanks.
>
> I pointed out to the committee that the erase_if functions added to
> C++20 completely overlook P0646R1 "Improving the Return Value of
> Erase-Like Algorithms" and so fail to preserve the useful information
> returned by the members of the linked list containers.
>
> I expect that to get fixed as a defect. If you have time and
> motivation, I think we should make that change proactively in
> libstdc++. The Library Fundamentals versions can continue to return
> void, but the ones in namespace std can return the number of elements
> removed.
>
I committed essentially what I started with (attached) as a baseline.

I would like to change the return as you suggest in another patch.

It seems to me that the intent of UCE is to have the same API for all 
containers.

So all erase_if would have size_type returns, including vector, string, 
deque.  Not a problem as those are const time.

It looks like the node erasure tool needs to maintain a count of erased 
nodes.  (it can't use erase(KeyT k) that returns a count since it 
involves a predicate rather than key compare.  Too bad there aren't 
'size_t erase_if(Pred)' members.)  No biggie - the complexity isn't 
changed by keeping count.

Holy crap.  i just noticed that *set/*map don't have plain erase() only 
erase_if()!

I need to implement final: 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1209r0.html 
before I do anything.  Both for experimental and std.

Ed




[-- Attachment #2: CL_erasure --]
[-- Type: text/plain, Size: 1305 bytes --]


2018-11-28  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement uniform container erasure for C++20.
	* include/Makefile.am: Move erase_if.h.
	* include/Makefile.in: Move erase_if.h.
	* include/experimental/bits/erase_if.h: Move ...
	* include/bits/erase_if.h: ... here.
	* include/experimental/map: Move erase_if.h.
	* include/experimental/set: Move erase_if.h.
	* include/experimental/unordered_map: Move erase_if.h.
	* include/experimental/unordered_set: Move erase_if.h.
	* include/std/deque (erase_if, erase): New functions.
	* include/std/forward_list: Ditto.
	* include/std/list: Ditto.
	* include/std/map: Ditto.
	* include/std/set: Ditto.
	* include/std/string: Ditto.
	* include/std/unordered_map: Ditto.
	* include/std/unordered_set: Ditto.
	* include/std/vector: Ditto.
	* testsuite/21_strings/basic_string/erasure.cc: New test.
	* testsuite/23_containers/deque/erasure.cc: New test.
	* testsuite/23_containers/forward_list/erasure.cc: New test.
	* testsuite/23_containers/list/erasure.cc: New test.
	* testsuite/23_containers/map/erasure.cc: New test.
	* testsuite/23_containers/set/erasure.cc: New test.
	* testsuite/23_containers/unordered_map/erasure.cc: New test.
	* testsuite/23_containers/unordered_set/erasure.cc: New test.
	* testsuite/23_containers/vector/erasure.cc: New test.


[-- Attachment #3: patch_erasure --]
[-- Type: text/plain, Size: 34482 bytes --]

Index: include/Makefile.am
===================================================================
--- include/Makefile.am	(revision 266566)
+++ include/Makefile.am	(working copy)
@@ -106,6 +106,7 @@
 	${bits_srcdir}/cpp_type_traits.h \
 	${bits_srcdir}/deque.tcc \
 	${bits_srcdir}/enable_special_members.h \
+	${bits_srcdir}/erase_if.h \
 	${bits_srcdir}/forward_list.h \
 	${bits_srcdir}/forward_list.tcc \
 	${bits_srcdir}/fs_dir.h \
@@ -710,7 +711,6 @@
 experimental_bits_srcdir = ${glibcxx_srcdir}/include/experimental/bits
 experimental_bits_builddir = ./experimental/bits
 experimental_bits_headers = \
-	${experimental_bits_srcdir}/erase_if.h \
 	${experimental_bits_srcdir}/lfts_config.h \
 	${experimental_bits_srcdir}/net.h \
 	${experimental_bits_srcdir}/shared_ptr.h \
Index: include/Makefile.in
===================================================================
--- include/Makefile.in	(revision 266566)
+++ include/Makefile.in	(working copy)
@@ -449,6 +449,7 @@
 	${bits_srcdir}/cpp_type_traits.h \
 	${bits_srcdir}/deque.tcc \
 	${bits_srcdir}/enable_special_members.h \
+	${bits_srcdir}/erase_if.h \
 	${bits_srcdir}/forward_list.h \
 	${bits_srcdir}/forward_list.tcc \
 	${bits_srcdir}/fs_dir.h \
@@ -1052,7 +1053,6 @@
 experimental_bits_srcdir = ${glibcxx_srcdir}/include/experimental/bits
 experimental_bits_builddir = ./experimental/bits
 experimental_bits_headers = \
-	${experimental_bits_srcdir}/erase_if.h \
 	${experimental_bits_srcdir}/lfts_config.h \
 	${experimental_bits_srcdir}/net.h \
 	${experimental_bits_srcdir}/shared_ptr.h \
Index: include/bits/erase_if.h
===================================================================
--- include/bits/erase_if.h	(revision 266566)
+++ include/bits/erase_if.h	(working copy)
@@ -1,4 +1,4 @@
-// <experimental/bits/erase_if.h> -*- C++ -*-
+// <bits/erase_if.h> -*- C++ -*-
 
 // Copyright (C) 2015-2018 Free Software Foundation, Inc.
 //
@@ -22,27 +22,22 @@
 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 // <http://www.gnu.org/licenses/>.
 
-/** @file experimental/bits/erase_if.h
+/** @file bits/erase_if.h
  *  This is an internal header file, included by other library headers.
  *  Do not attempt to use it directly.
  */
 
-#ifndef _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
-#define _GLIBCXX_EXPERIMENTAL_ERASE_IF_H 1
+#ifndef _GLIBCXX_ERASE_IF_H
+#define _GLIBCXX_ERASE_IF_H 1
 
 #pragma GCC system_header
 
 #if __cplusplus >= 201402L
-#include <experimental/bits/lfts_config.h>
 
 namespace std
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-namespace experimental
-{
-inline namespace fundamentals_v2
-{
   namespace __detail
   {
     template<typename _Container, typename _Predicate>
@@ -59,8 +54,6 @@
 	}
       }
   } // namespace __detail
-} // inline namespace fundamentals_v2
-} // namespace experimental
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
@@ -67,4 +60,4 @@
 
 #endif // C++14
 
-#endif // _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
+#endif // _GLIBCXX_ERASE_IF_H
Index: include/experimental/bits/erase_if.h
===================================================================
--- include/experimental/bits/erase_if.h	(revision 266566)
+++ include/experimental/bits/erase_if.h	(nonexistent)
@@ -1,70 +0,0 @@
-// <experimental/bits/erase_if.h> -*- C++ -*-
-
-// Copyright (C) 2015-2018 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
-// <http://www.gnu.org/licenses/>.
-
-/** @file experimental/bits/erase_if.h
- *  This is an internal header file, included by other library headers.
- *  Do not attempt to use it directly.
- */
-
-#ifndef _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
-#define _GLIBCXX_EXPERIMENTAL_ERASE_IF_H 1
-
-#pragma GCC system_header
-
-#if __cplusplus >= 201402L
-#include <experimental/bits/lfts_config.h>
-
-namespace std
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-namespace experimental
-{
-inline namespace fundamentals_v2
-{
-  namespace __detail
-  {
-    template<typename _Container, typename _Predicate>
-      void
-      __erase_nodes_if(_Container& __cont, _Predicate __pred)
-      {
-	for (auto __iter = __cont.begin(), __last = __cont.end();
-	     __iter != __last;)
-	{
-	  if (__pred(*__iter))
-	    __iter = __cont.erase(__iter);
-	  else
-	    ++__iter;
-	}
-      }
-  } // namespace __detail
-} // inline namespace fundamentals_v2
-} // namespace experimental
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
-#endif // C++14
-
-#endif // _GLIBCXX_EXPERIMENTAL_ERASE_IF_H
Index: include/experimental/map
===================================================================
--- include/experimental/map	(revision 266566)
+++ include/experimental/map	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <map>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -49,13 +49,13 @@
 	   typename _Predicate>
     inline void
     erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
 	   typename _Predicate>
     inline void
     erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Tp, typename _Compare = less<_Key>>
Index: include/experimental/set
===================================================================
--- include/experimental/set	(revision 266566)
+++ include/experimental/set	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <set>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -49,13 +49,13 @@
 	   typename _Predicate>
     inline void
     erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Compare, typename _Alloc,
 	   typename _Predicate>
     inline void
     erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Compare = less<_Key>>
Index: include/experimental/unordered_map
===================================================================
--- include/experimental/unordered_map	(revision 266566)
+++ include/experimental/unordered_map	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <unordered_map>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -50,7 +50,7 @@
     inline void
     erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
 	   typename _Alloc, typename _Predicate>
@@ -57,7 +57,7 @@
     inline void
     erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Tp, typename _Hash = hash<_Key>,
Index: include/experimental/unordered_set
===================================================================
--- include/experimental/unordered_set	(revision 266566)
+++ include/experimental/unordered_set	(working copy)
@@ -34,7 +34,7 @@
 #if __cplusplus >= 201402L
 
 #include <unordered_set>
-#include <experimental/bits/erase_if.h>
+#include <bits/erase_if.h>
 #include <experimental/memory_resource>
 
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -50,7 +50,7 @@
     inline void
     erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
 	   typename _Predicate>
@@ -57,7 +57,7 @@
     inline void
     erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 
   namespace pmr {
     template<typename _Key, typename _Hash = hash<_Key>,
Index: include/std/deque
===================================================================
--- include/std/deque	(revision 266566)
+++ include/std/deque	(working copy)
@@ -87,4 +87,27 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    void
+    erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    void
+    erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_DEQUE */
Index: include/std/forward_list
===================================================================
--- include/std/forward_list	(revision 266566)
+++ include/std/forward_list	(working copy)
@@ -60,6 +60,27 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void 
+    erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
+    { __cont.remove_if(__pred); }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      using __elem_type = typename forward_list<_Tp, _Alloc>::value_type;
+      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_FORWARD_LIST
Index: include/std/list
===================================================================
--- include/std/list	(revision 266566)
+++ include/std/list	(working copy)
@@ -84,4 +84,25 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
+    { __cont.remove_if(__pred); }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      using __elem_type = typename list<_Tp, _Alloc>::value_type;
+      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_LIST */
Index: include/std/map
===================================================================
--- include/std/map	(revision 266566)
+++ include/std/map	(working copy)
@@ -61,6 +61,7 @@
 #include <bits/stl_map.h>
 #include <bits/stl_multimap.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/map>
@@ -90,4 +91,23 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_MAP */
Index: include/std/set
===================================================================
--- include/std/set	(revision 266566)
+++ include/std/set	(working copy)
@@ -61,6 +61,7 @@
 #include <bits/stl_set.h>
 #include <bits/stl_multiset.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/set>
@@ -86,4 +87,23 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Compare, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_SET */
Index: include/std/string
===================================================================
--- include/std/string	(revision 266566)
+++ include/std/string	(working copy)
@@ -51,6 +51,7 @@
 #include <bits/range_access.h>
 #include <bits/basic_string.h>
 #include <bits/basic_string.tcc>
+#include <algorithm> // For remove and remove_if
 
 #if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI
 namespace std _GLIBCXX_VISIBILITY(default)
@@ -72,4 +73,28 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _CharT, typename _Traits, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
+    inline void
+    erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_STRING */
Index: include/std/unordered_map
===================================================================
--- include/std/unordered_map	(revision 266566)
+++ include/std/unordered_map	(working copy)
@@ -46,6 +46,7 @@
 #include <bits/hashtable.h>
 #include <bits/unordered_map.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/unordered_map>
@@ -76,6 +77,28 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+	   typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+	   typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { __detail::__erase_nodes_if(__cont, __pred); }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_UNORDERED_MAP
Index: include/std/unordered_set
===================================================================
--- include/std/unordered_set	(revision 266566)
+++ include/std/unordered_set	(working copy)
@@ -46,6 +46,7 @@
 #include <bits/hashtable.h>
 #include <bits/unordered_set.h>
 #include <bits/range_access.h>
+#include <bits/erase_if.h>
 
 #ifdef _GLIBCXX_DEBUG
 # include <debug/unordered_set>
@@ -76,6 +77,15 @@
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++17
+
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif // C++11
 
 #endif // _GLIBCXX_UNORDERED_SET
Index: include/std/vector
===================================================================
--- include/std/vector	(revision 266566)
+++ include/std/vector	(working copy)
@@ -90,4 +90,27 @@
 } // namespace std
 #endif // C++17
 
+#if __cplusplus > 201703L
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename _Alloc, typename _Predicate>
+    inline void
+    erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred)
+    {
+      __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
+		   __cont.end());
+    }
+
+  template<typename _Tp, typename _Alloc, typename _Up>
+    inline void
+    erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
+    {
+      __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
+		   __cont.end());
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+
 #endif /* _GLIBCXX_VECTOR */
Index: testsuite/21_strings/basic_string/erasure.cc
===================================================================
--- testsuite/21_strings/basic_string/erasure.cc	(nonexistent)
+++ testsuite/21_strings/basic_string/erasure.cc	(working copy)
@@ -0,0 +1,53 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <string>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_vowel = [](const char c)
+  {
+    return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
+  };
+
+  std::string str("cute fluffy kittens");
+  std::erase_if(str, is_vowel);
+  VERIFY( str == "ct flffy kttns" );
+}
+
+void
+test02()
+{
+  std::string str = "cute fluffy kittens";
+  std::erase(str, 'f');
+  VERIFY( str == "cute luy kittens" );
+  std::erase(str, 'z');
+  VERIFY( str == "cute luy kittens" );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/deque/erasure.cc
===================================================================
--- testsuite/23_containers/deque/erasure.cc	(nonexistent)
+++ testsuite/23_containers/deque/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <deque>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(d, is_odd);
+  std::deque<int> t{ 10, 12, 14, 18 };
+  VERIFY( d == t );
+}
+
+void
+test02()
+{
+  std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase(d, 14);
+  std::deque<int> t{ 10, 11, 12, 15, 17, 18, 19 };
+  VERIFY( d == t );
+  std::erase(d, 20);
+  VERIFY( d == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/forward_list/erasure.cc
===================================================================
--- testsuite/23_containers/forward_list/erasure.cc	(nonexistent)
+++ testsuite/23_containers/forward_list/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(fl, is_odd);
+  std::forward_list<int> t{ 10, 12, 14, 18 };
+  VERIFY( fl == t );
+}
+
+void
+test02()
+{
+  std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase(fl, 14);
+  std::forward_list<int> t{ 10, 11, 12, 15, 17, 18, 19 };
+  VERIFY( fl == t );
+  std::erase(fl, 20);
+  VERIFY( fl == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/list/erasure.cc
===================================================================
--- testsuite/23_containers/list/erasure.cc	(nonexistent)
+++ testsuite/23_containers/list/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <list>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::list<int> l{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(l, is_odd);
+  std::list<int> t{ 10, 12, 14, 18 };
+  VERIFY( l == t );
+}
+
+void
+test02()
+{
+  std::list<int> l{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
+  std::erase(l, 0);
+  std::list<int> t{ 11, 22, 33, 44 };
+  VERIFY( l == t );
+  std::erase(l, 55);
+  VERIFY( l == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/map/erasure.cc
===================================================================
--- testsuite/23_containers/map/erasure.cc	(nonexistent)
+++ testsuite/23_containers/map/erasure.cc	(working copy)
@@ -0,0 +1,61 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <map>
+#include <testsuite_hooks.h>
+
+auto is_odd_pair = [](const std::pair<const int, std::string>& p)
+{
+  return p.first % 2 != 0;
+};
+
+void
+test01()
+{
+  std::map<int, std::string> m{ { 10, "A" }, { 11, "B" },
+				{ 12, "C" }, { 14, "D" },
+				{ 15, "E" }, { 17, "F" },
+				{ 18, "G" }, { 19, "H" } };
+  std::erase_if(m, is_odd_pair);
+  std::map<int, std::string> t{ { 10, "A" }, { 12, "C" },
+				{ 14, "D" }, { 18, "G" } };
+  VERIFY( m == t );
+}
+
+void
+test02()
+{
+  std::multimap<int, std::string> mm{ { 20, "S" }, { 21, "T" },
+				      { 22, "U" }, { 22, "V" },
+				      { 23, "W" }, { 23, "X" },
+				      { 24, "Y" }, { 25, "Z" } };
+  std::erase_if(mm, is_odd_pair);
+  std::multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
+				     { 22, "V" }, { 24, "Y" } };
+  VERIFY( mm == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/set/erasure.cc
===================================================================
--- testsuite/23_containers/set/erasure.cc	(nonexistent)
+++ testsuite/23_containers/set/erasure.cc	(working copy)
@@ -0,0 +1,50 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <set>
+#include <testsuite_hooks.h>
+
+auto is_odd = [](const int i) { return i % 2 != 0; };
+
+void
+test01()
+{
+  std::set<int> s{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(s, is_odd);
+  std::set<int> t{ 10, 12, 14, 18 };
+  VERIFY( s == t );
+}
+
+void
+test02()
+{
+  std::multiset<int> ms{ 20, 21, 22, 22, 23, 23, 24, 25 };
+  std::erase_if(ms, is_odd);
+  std::multiset<int> t{ 20, 22, 22, 24 };
+  VERIFY( ms == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/unordered_map/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_map/erasure.cc	(nonexistent)
+++ testsuite/23_containers/unordered_map/erasure.cc	(working copy)
@@ -0,0 +1,61 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_odd_pair = [](const std::pair<const int, std::string>& p)
+{
+  return p.first % 2 != 0;
+};
+
+void
+test01()
+{
+  std::unordered_map<int, std::string> um{ { 10, "A" }, { 11, "B" },
+					   { 12, "C" }, { 14, "D" },
+					   { 15, "E" }, { 17, "F" },
+					   { 18, "G" }, { 19, "H" } };
+  std::erase_if(um, is_odd_pair);
+  std::unordered_map<int, std::string> t{ { 10, "A" }, { 12, "C" },
+					  { 14, "D" }, { 18, "G" } };
+  VERIFY( um == t );
+}
+
+void
+test02()
+{
+  std::unordered_multimap<int, std::string> umm{ { 20, "S" }, { 21, "T" },
+						 { 22, "U" }, { 22, "V" },
+						 { 23, "W" }, { 23, "X" },
+						 { 24, "Y" }, { 25, "Z" } };
+  std::erase_if(umm, is_odd_pair);
+  std::unordered_multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
+					       { 22, "V" }, { 24, "Y" } };
+  VERIFY( umm == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/unordered_set/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_set/erasure.cc	(nonexistent)
+++ testsuite/23_containers/unordered_set/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::unordered_set<int> us{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(us, is_odd);
+  std::unordered_set<int> t{ 10, 12, 14, 18 };
+  VERIFY( us == t );
+}
+
+void
+test02()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::unordered_multiset<int> ums{ 20, 21, 22, 22, 23, 23, 24, 25 };
+  std::erase_if(ums, is_odd);
+  std::unordered_multiset<int> t{ 20, 22, 22, 24 };
+  VERIFY( ums == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}
Index: testsuite/23_containers/vector/erasure.cc
===================================================================
--- testsuite/23_containers/vector/erasure.cc	(nonexistent)
+++ testsuite/23_containers/vector/erasure.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-do run { target c++2a } }
+
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <vector>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto is_odd = [](const int i) { return i % 2 != 0; };
+
+  std::vector<int> v{ 10, 11, 12, 14, 15, 17, 18, 19 };
+  std::erase_if(v, is_odd);
+  std::vector<int> t{ 10, 12, 14, 18 };
+  VERIFY( v == t );
+}
+
+void
+test02()
+{
+  std::vector<int> v{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
+  std::erase(v, 0);
+  std::vector<int> t{ 11, 22, 33, 44 };
+  VERIFY( v == t );
+  std::erase(v, 55);
+  VERIFY( v == t );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+
+  return 0;
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-28 17:12   ` Ed Smith-Rowland
@ 2018-11-29  0:25     ` Jonathan Wakely
  2018-11-29 13:47       ` Ed Smith-Rowland
  0 siblings, 1 reply; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-29  0:25 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: libstdc++, gcc-patches, Jakub Jelinek

On 28/11/18 12:12 -0500, Ed Smith-Rowland wrote:
>Index: testsuite/21_strings/basic_string/erasure.cc
>===================================================================
>--- testsuite/21_strings/basic_string/erasure.cc	(nonexistent)
>+++ testsuite/21_strings/basic_string/erasure.cc	(working copy)
>@@ -0,0 +1,53 @@
>+// { dg-do run { target c++2a } }
>+

None of these new tests actually run by default, because they are
gated to only run for C++2a and the default is gnu++14. That means
they're all skipped as UNSUPPORTED.

(When I add new tests I always try to remember to check the
testsuite/libstdc++.sum file to make sure they are actually running).

The tests need an explicit -std option added via dg-options, which has
to come before the dg-do directive, otherwise the target check still
uses the default options i.e.

// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }

With that added, most of them start to FAIL:

FAIL: 23_containers/deque/erasure.cc (test for excess errors)
UNRESOLVED: 23_containers/deque/erasure.cc compilation failed to produce executable
FAIL: 23_containers/unordered_set/erasure.cc (test for excess errors)
UNRESOLVED: 23_containers/unordered_set/erasure.cc compilation failed to produce executable
FAIL: 23_containers/vector/erasure.cc (test for excess errors)
UNRESOLVED: 23_containers/vector/erasure.cc compilation failed to produce executable
FAIL: experimental/deque/erasure.cc (test for excess errors)
UNRESOLVED: experimental/deque/erasure.cc compilation failed to produce executable
FAIL: experimental/forward_list/erasure.cc (test for excess errors)
UNRESOLVED: experimental/forward_list/erasure.cc compilation failed to produce executable
FAIL: experimental/list/erasure.cc (test for excess errors)
UNRESOLVED: experimental/list/erasure.cc compilation failed to produce executable
FAIL: experimental/vector/erasure.cc (test for excess errors)
UNRESOLVED: experimental/vector/erasure.cc compilation failed to produce executable


The errors are all like:

In file included from /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/23_containers/vector/erasure.cc:21:
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector: In function 'void std::erase_if(std::vector<_Tp, _Alloc>&, _Predicate)':
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector:101: error: 'remove_if' is not a member of 'std'; did you mean 'remove_cv'?
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector: In function 'void std::erase(std::vector<_Tp, _Alloc>&, const _Up&)':
/home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector:109: error: 'remove' is not a member of 'std'; did you mean 'move'?

This is because std::remove and std::remove_if are defined in
<bits/stl_algo.h> which is not included.

Could you please fix this ASAP?


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29  0:25     ` Jonathan Wakely
@ 2018-11-29 13:47       ` Ed Smith-Rowland
  2018-11-29 14:09         ` Jonathan Wakely
  2018-11-29 14:12         ` Jakub Jelinek
  0 siblings, 2 replies; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-29 13:47 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 3088 bytes --]

On 11/28/18 7:25 PM, Jonathan Wakely wrote:
> On 28/11/18 12:12 -0500, Ed Smith-Rowland wrote:
>> Index: testsuite/21_strings/basic_string/erasure.cc
>> ===================================================================
>> --- testsuite/21_strings/basic_string/erasure.cc (nonexistent)
>> +++ testsuite/21_strings/basic_string/erasure.cc    (working copy)
>> @@ -0,0 +1,53 @@
>> +// { dg-do run { target c++2a } }
>> +
>
> None of these new tests actually run by default, because they are
> gated to only run for C++2a and the default is gnu++14. That means
> they're all skipped as UNSUPPORTED.
>
> (When I add new tests I always try to remember to check the
> testsuite/libstdc++.sum file to make sure they are actually running).
>
> The tests need an explicit -std option added via dg-options, which has
> to come before the dg-do directive, otherwise the target check still
> uses the default options i.e.
>
> // { dg-options "-std=gnu++2a" }
> // { dg-do run { target c++2a } }
>
> With that added, most of them start to FAIL:
>
> FAIL: 23_containers/deque/erasure.cc (test for excess errors)
> UNRESOLVED: 23_containers/deque/erasure.cc compilation failed to 
> produce executable
> FAIL: 23_containers/unordered_set/erasure.cc (test for excess errors)
> UNRESOLVED: 23_containers/unordered_set/erasure.cc compilation failed 
> to produce executable
> FAIL: 23_containers/vector/erasure.cc (test for excess errors)
> UNRESOLVED: 23_containers/vector/erasure.cc compilation failed to 
> produce executable
> FAIL: experimental/deque/erasure.cc (test for excess errors)
> UNRESOLVED: experimental/deque/erasure.cc compilation failed to 
> produce executable
> FAIL: experimental/forward_list/erasure.cc (test for excess errors)
> UNRESOLVED: experimental/forward_list/erasure.cc compilation failed to 
> produce executable
> FAIL: experimental/list/erasure.cc (test for excess errors)
> UNRESOLVED: experimental/list/erasure.cc compilation failed to produce 
> executable
> FAIL: experimental/vector/erasure.cc (test for excess errors)
> UNRESOLVED: experimental/vector/erasure.cc compilation failed to 
> produce executable
>
>
> The errors are all like:
>
> In file included from 
> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/23_containers/vector/erasure.cc:21:
> /home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector: 
> In function 'void std::erase_if(std::vector<_Tp, _Alloc>&, _Predicate)':
> /home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector:101: 
> error: 'remove_if' is not a member of 'std'; did you mean 'remove_cv'?
> /home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector: 
> In function 'void std::erase(std::vector<_Tp, _Alloc>&, const _Up&)':
> /home/jwakely/src/gcc/build/x86_64-pc-linux-gnu/libstdc++-v3/include/vector:109: 
> error: 'remove' is not a member of 'std'; did you mean 'move'?
>
> This is because std::remove and std::remove_if are defined in
> <bits/stl_algo.h> which is not included.
>
> Could you please fix this ASAP 


Sorry about that.

Fixed with 266616.

Ed



[-- Attachment #2: CL_fix_erasure --]
[-- Type: text/plain, Size: 869 bytes --]


2018-11-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Fix erasure goofs.
	* include/experimental/deque: Make inline.
	* include/std/deque: Include bits/stl_algo.h.
	(erase, erase_if): Make inline.
	* include/std/string: Include bits/stl_algo.h.
	* include/std/unordered_set: Add erase, erase_if!
	* include/std/vector: Include bits/stl_algo.h.
	* testsuite/21_strings/basic_string/erasure.cc:
	Add { dg-options "-std=gnu++2a" }.
	* testsuite/23_containers/deque/erasure.cc: Ditto.
	* testsuite/23_containers/forward_list/erasure.cc: Ditto.
	* testsuite/23_containers/list/erasure.cc: Ditto.
	* testsuite/23_containers/map/erasure.cc: Ditto.
	* testsuite/23_containers/set/erasure.cc: Ditto.
	* testsuite/23_containers/unordered_map/erasure.cc: Ditto.
	* testsuite/23_containers/unordered_set/erasure.cc: Ditto.
	* testsuite/23_containers/vector/erasure.cc: Ditto.


[-- Attachment #3: patch_fix_erasure --]
[-- Type: text/plain, Size: 7089 bytes --]

Index: include/experimental/deque
===================================================================
--- include/experimental/deque	(revision 266566)
+++ include/experimental/deque	(working copy)
@@ -46,7 +46,7 @@
 inline namespace fundamentals_v2
 {
   template<typename _Tp, typename _Alloc, typename _Predicate>
-    void
+    inline void
     erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred)
     {
       __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
@@ -54,7 +54,7 @@
     }
 
   template<typename _Tp, typename _Alloc, typename _Up>
-    void
+    inline void
     erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
     {
       __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
Index: include/std/deque
===================================================================
--- include/std/deque	(revision 266567)
+++ include/std/deque	(working copy)
@@ -58,6 +58,7 @@
 #pragma GCC system_header
 
 #include <bits/stl_algobase.h>
+#include <bits/stl_algo.h> // For remove and remove_if
 #include <bits/allocator.h>
 #include <bits/stl_construct.h>
 #include <bits/stl_uninitialized.h>
@@ -92,7 +93,7 @@
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc, typename _Predicate>
-    void
+    inline void
     erase_if(deque<_Tp, _Alloc>& __cont, _Predicate __pred)
     {
       __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
@@ -100,7 +101,7 @@
     }
 
   template<typename _Tp, typename _Alloc, typename _Up>
-    void
+    inline void
     erase(deque<_Tp, _Alloc>& __cont, const _Up& __value)
     {
       __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
Index: include/std/string
===================================================================
--- include/std/string	(revision 266567)
+++ include/std/string	(working copy)
@@ -48,10 +48,10 @@
 #include <bits/stl_function.h> // For less
 #include <ext/numeric_traits.h>
 #include <bits/stl_algobase.h>
+#include <bits/stl_algo.h> // For remove and remove_if
 #include <bits/range_access.h>
 #include <bits/basic_string.h>
 #include <bits/basic_string.tcc>
-#include <algorithm> // For remove and remove_if
 
 #if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI
 namespace std _GLIBCXX_VISIBILITY(default)
Index: include/std/unordered_set
===================================================================
--- include/std/unordered_set	(revision 266567)
+++ include/std/unordered_set	(working copy)
@@ -82,6 +82,19 @@
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
+
+  template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
+	   typename _Predicate>
+    inline void
+    erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
+	     _Predicate __pred)
+    { std::__detail::__erase_nodes_if(__cont, __pred); }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20
Index: include/std/vector
===================================================================
--- include/std/vector	(revision 266567)
+++ include/std/vector	(working copy)
@@ -58,6 +58,7 @@
 #pragma GCC system_header
 
 #include <bits/stl_algobase.h>
+#include <bits/stl_algo.h> // For remove and remove_if
 #include <bits/allocator.h>
 #include <bits/stl_construct.h>
 #include <bits/stl_uninitialized.h>
Index: testsuite/21_strings/basic_string/erasure.cc
===================================================================
--- testsuite/21_strings/basic_string/erasure.cc	(revision 266567)
+++ testsuite/21_strings/basic_string/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/deque/erasure.cc
===================================================================
--- testsuite/23_containers/deque/erasure.cc	(revision 266567)
+++ testsuite/23_containers/deque/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/forward_list/erasure.cc
===================================================================
--- testsuite/23_containers/forward_list/erasure.cc	(revision 266567)
+++ testsuite/23_containers/forward_list/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/list/erasure.cc
===================================================================
--- testsuite/23_containers/list/erasure.cc	(revision 266567)
+++ testsuite/23_containers/list/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/map/erasure.cc
===================================================================
--- testsuite/23_containers/map/erasure.cc	(revision 266567)
+++ testsuite/23_containers/map/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/set/erasure.cc
===================================================================
--- testsuite/23_containers/set/erasure.cc	(revision 266567)
+++ testsuite/23_containers/set/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/unordered_map/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_map/erasure.cc	(revision 266567)
+++ testsuite/23_containers/unordered_map/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/unordered_set/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_set/erasure.cc	(revision 266567)
+++ testsuite/23_containers/unordered_set/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.
Index: testsuite/23_containers/vector/erasure.cc
===================================================================
--- testsuite/23_containers/vector/erasure.cc	(revision 266567)
+++ testsuite/23_containers/vector/erasure.cc	(working copy)
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++2a" }
 // { dg-do run { target c++2a } }
 
 // Copyright (C) 2018 Free Software Foundation, Inc.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29 13:47       ` Ed Smith-Rowland
@ 2018-11-29 14:09         ` Jonathan Wakely
  2018-11-29 15:19           ` Ed Smith-Rowland
  2018-11-29 14:12         ` Jakub Jelinek
  1 sibling, 1 reply; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-29 14:09 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: libstdc++, gcc-patches, Jakub Jelinek

On 29/11/18 08:47 -0500, Ed Smith-Rowland wrote:
>Fixed with 266616.

Thanks!

>Index: include/std/deque
>===================================================================
>--- include/std/deque	(revision 266567)
>+++ include/std/deque	(working copy)
>@@ -58,6 +58,7 @@
> #pragma GCC system_header
>
> #include <bits/stl_algobase.h>
>+#include <bits/stl_algo.h> // For remove and remove_if

Please only include <bits/stl_algo.h> when __cplusplus > 201703L
otherwise we include hundreds of kilobytes of code just for these tiny
functions that aren't even defined in the default C++14 dialect.

At some point I'll split std::remove and std::remove_if into their own
header, and we can just include that instead.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29 13:47       ` Ed Smith-Rowland
  2018-11-29 14:09         ` Jonathan Wakely
@ 2018-11-29 14:12         ` Jakub Jelinek
  1 sibling, 0 replies; 14+ messages in thread
From: Jakub Jelinek @ 2018-11-29 14:12 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: Jonathan Wakely, libstdc++, gcc-patches

On Thu, Nov 29, 2018 at 08:47:15AM -0500, Ed Smith-Rowland wrote:
> --- include/std/deque	(revision 266567)
> +++ include/std/deque	(working copy)
> @@ -58,6 +58,7 @@
>  #pragma GCC system_header
>  
>  #include <bits/stl_algobase.h>
> +#include <bits/stl_algo.h> // For remove and remove_if

Isn't that too expensive, especially in non-C++20 modes?
stl_algo.h is larger than 200KB.

So, could these includes be either guarded with __cplusplus > 201703
if they are only needed for C++20, or better have bits/stl_remove.h
containing just those?

	Jakub

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29 14:09         ` Jonathan Wakely
@ 2018-11-29 15:19           ` Ed Smith-Rowland
  2018-11-29 16:32             ` Jonathan Wakely
  0 siblings, 1 reply; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-29 15:19 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 838 bytes --]

On 11/29/18 9:09 AM, Jonathan Wakely wrote:
> On 29/11/18 08:47 -0500, Ed Smith-Rowland wrote:
>> Fixed with 266616.
>
> Thanks!
>
>> Index: include/std/deque
>> ===================================================================
>> --- include/std/deque    (revision 266567)
>> +++ include/std/deque    (working copy)
>> @@ -58,6 +58,7 @@
>> #pragma GCC system_header
>>
>> #include <bits/stl_algobase.h>
>> +#include <bits/stl_algo.h> // For remove and remove_if
>
> Please only include <bits/stl_algo.h> when __cplusplus > 201703L
> otherwise we include hundreds of kilobytes of code just for these tiny
> functions that aren't even defined in the default C++14 dialect.

Done with 266624.

Ed

> At some point I'll split std::remove and std::remove_if into their own
> header, and we can just include that instead



[-- Attachment #2: CL_erasure_incs --]
[-- Type: text/plain, Size: 221 bytes --]


2018-11-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Only include bits/stl_algo.h for C++20.
	* include/std/deque: Only include bits/stl_algo.h for C++20.
	* include/std/string: Ditto.
	* include/std/vector: Ditto.


[-- Attachment #3: patch_erasure_incs --]
[-- Type: text/plain, Size: 1571 bytes --]

Index: include/std/deque
===================================================================
--- include/std/deque	(revision 266616)
+++ include/std/deque	(working copy)
@@ -58,7 +58,9 @@
 #pragma GCC system_header
 
 #include <bits/stl_algobase.h>
-#include <bits/stl_algo.h> // For remove and remove_if
+#if __cplusplus > 201703L
+#  include <bits/stl_algo.h> // For remove and remove_if
+#endif // C++20
 #include <bits/allocator.h>
 #include <bits/stl_construct.h>
 #include <bits/stl_uninitialized.h>
Index: include/std/string
===================================================================
--- include/std/string	(revision 266616)
+++ include/std/string	(working copy)
@@ -48,7 +48,9 @@
 #include <bits/stl_function.h> // For less
 #include <ext/numeric_traits.h>
 #include <bits/stl_algobase.h>
-#include <bits/stl_algo.h> // For remove and remove_if
+#if __cplusplus > 201703L
+#  include <bits/stl_algo.h> // For remove and remove_if
+#endif // C++20
 #include <bits/range_access.h>
 #include <bits/basic_string.h>
 #include <bits/basic_string.tcc>
Index: include/std/vector
===================================================================
--- include/std/vector	(revision 266616)
+++ include/std/vector	(working copy)
@@ -58,7 +58,9 @@
 #pragma GCC system_header
 
 #include <bits/stl_algobase.h>
-#include <bits/stl_algo.h> // For remove and remove_if
+#if __cplusplus > 201703L
+#  include <bits/stl_algo.h> // For remove and remove_if
+#endif // C++20
 #include <bits/allocator.h>
 #include <bits/stl_construct.h>
 #include <bits/stl_uninitialized.h>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29 15:19           ` Ed Smith-Rowland
@ 2018-11-29 16:32             ` Jonathan Wakely
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-29 16:32 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: libstdc++, gcc-patches, Jakub Jelinek

On 29/11/18 10:18 -0500, Ed Smith-Rowland wrote:
>On 11/29/18 9:09 AM, Jonathan Wakely wrote:
>>On 29/11/18 08:47 -0500, Ed Smith-Rowland wrote:
>>>Fixed with 266616.
>>
>>Thanks!
>>
>>>Index: include/std/deque
>>>===================================================================
>>>--- include/std/deque    (revision 266567)
>>>+++ include/std/deque    (working copy)
>>>@@ -58,6 +58,7 @@
>>>#pragma GCC system_header
>>>
>>>#include <bits/stl_algobase.h>
>>>+#include <bits/stl_algo.h> // For remove and remove_if
>>
>>Please only include <bits/stl_algo.h> when __cplusplus > 201703L
>>otherwise we include hundreds of kilobytes of code just for these tiny
>>functions that aren't even defined in the default C++14 dialect.
>
>Done with 266624.

Thanks for the quick turnaround.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-26 11:18 ` Jonathan Wakely
  2018-11-28 17:12   ` Ed Smith-Rowland
@ 2018-11-29 17:06   ` Ed Smith-Rowland
  2018-11-30  0:05     ` [PATCH, libstdc++] Uniform container erasure for c++20 returning number of erasures Ed Smith-Rowland
  2018-11-30 10:25     ` [PATCH, libstdc++] Uniform container erasure for c++20 Jonathan Wakely
  1 sibling, 2 replies; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-29 17:06 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1410 bytes --]

On 11/26/18 6:18 AM, Jonathan Wakely wrote:
> On 24/11/18 13:54 -0500, Ed Smith-Rowland wrote:
>> All,
>>
>> I's very late but uniform container erasure is, I think, the last 
>> little tidbit to graduate from fundamentals/v2 to std at the last 
>> meeting.  I think it would be a shame not to nudge this into gcc-9.  
>> The routines are very short so I just copied them. Ditto the 
>> testcases (with adjustments).  The node erasure tool was moved from 
>> experimental to std/bits and adjustments made to affected *set/*map 
>> headers.
>>
>> The experimental code has been in our tree since 2015.
>>
>> This builds and tests clean on x86_64-linux.
>
> OK for trunk as it only touches experimental C++2a and TS material.
> Thanks.
>
> I pointed out to the committee that the erase_if functions added to
> C++20 completely overlook P0646R1 "Improving the Return Value of
> Erase-Like Algorithms" and so fail to preserve the useful information
> returned by the members of the linked list containers.
Is *this* what you has in mind for this?  I basically return the number 
of erased items for all the things.
>
> I expect that to get fixed as a defect. If you have time and
> motivation, I think we should make that change proactively in
> libstdc++. The Library Fundamentals versions can continue to return
> void, but the ones in namespace std can return the number of elements
> removed

Ed



[-- Attachment #2: CL_num_erased --]
[-- Type: text/plain, Size: 999 bytes --]


2018-11-29  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Pre-emptively support P0646R1 for std container erasure.
	* include/bits/erase_if.h: Accumulate and return number of erased nodes.
	* include/std/forward_list (): Return number of erased items.
	* include/std/list (): Ditto.
	* include/std/map (): Ditto.
	* include/std/set (): Ditto.
	* include/std/string (): Ditto.
	* include/std/unordered_map (): Ditto.
	* include/std/unordered_set (): Ditto.
	* include/std/vector (): Ditto.
	* testsuite/21_strings/basic_string/erasure.cc: Test number of erasures.
	* testsuite/23_containers/deque/erasure.cc: Ditto.
	* testsuite/23_containers/forward_list/erasure.cc: Ditto.
	* testsuite/23_containers/list/erasure.cc: Ditto.
	* testsuite/23_containers/map/erasure.cc: Ditto.
	* testsuite/23_containers/set/erasure.cc: Ditto.
	* testsuite/23_containers/unordered_map/erasure.cc: Ditto.
	* testsuite/23_containers/unordered_set/erasure.cc: Ditto.
	* testsuite/23_containers/vector/erasure.cc: Ditto.


[-- Attachment #3: patch_num_erased --]
[-- Type: text/plain, Size: 17032 bytes --]

Index: include/bits/erase_if.h
===================================================================
--- include/bits/erase_if.h	(revision 266623)
+++ include/bits/erase_if.h	(working copy)
@@ -41,17 +41,22 @@
   namespace __detail
   {
     template<typename _Container, typename _Predicate>
-      void
+      typename _Container::size_type
       __erase_nodes_if(_Container& __cont, _Predicate __pred)
       {
+	typename _Container::size_type __num = 0;
 	for (auto __iter = __cont.begin(), __last = __cont.end();
 	     __iter != __last;)
-	{
-	  if (__pred(*__iter))
-	    __iter = __cont.erase(__iter);
-	  else
-	    ++__iter;
-	}
+	  {
+	    if (__pred(*__iter))
+	      {
+		__iter = __cont.erase(__iter);
+		++__num;
+	      }
+	    else
+	      ++__iter;
+	  }
+	return __num;
       }
   } // namespace __detail
 
Index: include/std/forward_list
===================================================================
--- include/std/forward_list	(revision 266623)
+++ include/std/forward_list	(working copy)
@@ -66,16 +66,17 @@
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc, typename _Predicate>
-    inline void 
+    inline typename forward_list<_Tp, _Alloc>::size_type 
     erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
-    { __cont.remove_if(__pred); }
+    { return __cont.remove_if(__pred); }
 
   template<typename _Tp, typename _Alloc, typename _Up>
-    inline void
+    inline typename forward_list<_Tp, _Alloc>::size_type
     erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
     {
       using __elem_type = typename forward_list<_Tp, _Alloc>::value_type;
-      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+      return erase_if(__cont,
+		      [&](__elem_type& __elem) { return __elem == __value; });
     }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
Index: include/std/list
===================================================================
--- include/std/list	(revision 266623)
+++ include/std/list	(working copy)
@@ -90,16 +90,17 @@
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc, typename _Predicate>
-    inline void
+    inline typename list<_Tp, _Alloc>::size_type
     erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
-    { __cont.remove_if(__pred); }
+    { return __cont.remove_if(__pred); }
 
   template<typename _Tp, typename _Alloc, typename _Up>
-    inline void
+    inline typename list<_Tp, _Alloc>::size_type
     erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
     {
       using __elem_type = typename list<_Tp, _Alloc>::value_type;
-      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
+      return erase_if(__cont,
+		      [&](__elem_type& __elem) { return __elem == __value; });
     }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
Index: include/std/map
===================================================================
--- include/std/map	(revision 266623)
+++ include/std/map	(working copy)
@@ -97,15 +97,15 @@
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename map<_Key, _Tp, _Compare, _Alloc>::size_type
     erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename multimap<_Key, _Tp, _Compare, _Alloc>::size_type
     erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20
Index: include/std/set
===================================================================
--- include/std/set	(revision 266623)
+++ include/std/set	(working copy)
@@ -93,15 +93,15 @@
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Compare, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename set<_Key, _Compare, _Alloc>::size_type
     erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Compare, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename multiset<_Key, _Compare, _Alloc>::size_type
     erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20
Index: include/std/string
===================================================================
--- include/std/string	(revision 266624)
+++ include/std/string	(working copy)
@@ -81,19 +81,23 @@
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _CharT, typename _Traits, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline basic_string<_CharT, _Traits, _Alloc>::size_type
     erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
     {
+      const auto __osz = __cont.size();
       __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
 		   __cont.end());
+      return __cont.size() - __osz;
     }
 
   template<typename _CharT, typename _Traits, typename _Alloc, typename _Up>
-    inline void
+    inline basic_string<_CharT, _Traits, _Alloc>::size_type
     erase(basic_string<_CharT, _Traits, _Alloc>& __cont, const _Up& __value)
     {
+      const auto __osz = __cont.size();
       __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
 		   __cont.end());
+      return __cont.size() - __osz;
     }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
Index: include/std/unordered_map
===================================================================
--- include/std/unordered_map	(revision 266623)
+++ include/std/unordered_map	(working copy)
@@ -84,17 +84,17 @@
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
 	   typename _Alloc, typename _Predicate>
-    inline void
+    inline unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>::size_type
     erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
 	   typename _Alloc, typename _Predicate>
-    inline void
+    inline unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>::size_type
     erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { __detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20
Index: include/std/unordered_set
===================================================================
--- include/std/unordered_set	(revision 266623)
+++ include/std/unordered_set	(working copy)
@@ -84,17 +84,17 @@
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename unordered_set<_Key, _Hash, _CPred, _Alloc>::size_type
     erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { std::__detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 
   template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
 	   typename _Predicate>
-    inline void
+    inline typename unordered_multiset<_Key, _Hash, _CPred, _Alloc>::size_type
     erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
 	     _Predicate __pred)
-    { std::__detail::__erase_nodes_if(__cont, __pred); }
+    { return __detail::__erase_nodes_if(__cont, __pred); }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // C++20
Index: include/std/vector
===================================================================
--- include/std/vector	(revision 266624)
+++ include/std/vector	(working copy)
@@ -98,19 +98,23 @@
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp, typename _Alloc, typename _Predicate>
-    inline void
+    inline vector<_Tp, _Alloc>::size_type
     erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred)
     {
+      const auto __osz = __cont.size();
       __cont.erase(std::remove_if(__cont.begin(), __cont.end(), __pred),
 		   __cont.end());
+      return __cont.size() - __osz;
     }
 
   template<typename _Tp, typename _Alloc, typename _Up>
-    inline void
+    inline vector<_Tp, _Alloc>::size_type
     erase(vector<_Tp, _Alloc>& __cont, const _Up& __value)
     {
+      const auto __osz = __cont.size();
       __cont.erase(std::remove(__cont.begin(), __cont.end(), __value),
 		   __cont.end());
+      return __cont.size() - __osz;
     }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
Index: testsuite/21_strings/basic_string/erasure.cc
===================================================================
--- testsuite/21_strings/basic_string/erasure.cc	(revision 266623)
+++ testsuite/21_strings/basic_string/erasure.cc	(working copy)
@@ -30,8 +30,9 @@
   };
 
   std::string str("cute fluffy kittens");
-  std::erase_if(str, is_vowel);
+  auto num = std::erase_if(str, is_vowel);
   VERIFY( str == "ct flffy kttns" );
+  VERIFY( num == 5 );
 }
 
 void
@@ -38,10 +39,12 @@
 test02()
 {
   std::string str = "cute fluffy kittens";
-  std::erase(str, 'f');
+  auto num = std::erase(str, 'f');
   VERIFY( str == "cute luy kittens" );
-  std::erase(str, 'z');
+  VERIFY( num == 3 );
+  num = std::erase(str, 'z');
   VERIFY( str == "cute luy kittens" );
+  VERIFY( num == 0 );
 }
 
 int
Index: testsuite/23_containers/deque/erasure.cc
===================================================================
--- testsuite/23_containers/deque/erasure.cc	(revision 266623)
+++ testsuite/23_containers/deque/erasure.cc	(working copy)
@@ -27,9 +27,10 @@
   auto is_odd = [](const int i) { return i % 2 != 0; };
 
   std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase_if(d, is_odd);
+  auto num = std::erase_if(d, is_odd);
   std::deque<int> t{ 10, 12, 14, 18 };
   VERIFY( d == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -36,11 +37,13 @@
 test02()
 {
   std::deque<int> d{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase(d, 14);
+  auto num = std::erase(d, 14);
   std::deque<int> t{ 10, 11, 12, 15, 17, 18, 19 };
   VERIFY( d == t );
-  std::erase(d, 20);
+  VERIFY( num == 4 );
+  num = std::erase(d, 20);
   VERIFY( d == t );
+  VERIFY( num == 0 );
 }
 
 int
Index: testsuite/23_containers/forward_list/erasure.cc
===================================================================
--- testsuite/23_containers/forward_list/erasure.cc	(revision 266623)
+++ testsuite/23_containers/forward_list/erasure.cc	(working copy)
@@ -27,9 +27,10 @@
   auto is_odd = [](const int i) { return i % 2 != 0; };
 
   std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase_if(fl, is_odd);
+  auto num = std::erase_if(fl, is_odd);
   std::forward_list<int> t{ 10, 12, 14, 18 };
   VERIFY( fl == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -36,11 +37,13 @@
 test02()
 {
   std::forward_list<int> fl{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase(fl, 14);
+  auto num = std::erase(fl, 14);
   std::forward_list<int> t{ 10, 11, 12, 15, 17, 18, 19 };
   VERIFY( fl == t );
-  std::erase(fl, 20);
+  VERIFY( num == 1 );
+  num = std::erase(fl, 20);
   VERIFY( fl == t );
+  VERIFY( num == 0 );
 }
 
 int
Index: testsuite/23_containers/list/erasure.cc
===================================================================
--- testsuite/23_containers/list/erasure.cc	(revision 266623)
+++ testsuite/23_containers/list/erasure.cc	(working copy)
@@ -36,11 +36,13 @@
 test02()
 {
   std::list<int> l{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
-  std::erase(l, 0);
+  auto num = std::erase(l, 0);
   std::list<int> t{ 11, 22, 33, 44 };
   VERIFY( l == t );
-  std::erase(l, 55);
+  VERIFY( num == 6 );
+  num = std::erase(l, 55);
   VERIFY( l == t );
+  VERIFY( num == 0 );
 }
 
 int
Index: testsuite/23_containers/map/erasure.cc
===================================================================
--- testsuite/23_containers/map/erasure.cc	(revision 266623)
+++ testsuite/23_containers/map/erasure.cc	(working copy)
@@ -33,10 +33,11 @@
 				{ 12, "C" }, { 14, "D" },
 				{ 15, "E" }, { 17, "F" },
 				{ 18, "G" }, { 19, "H" } };
-  std::erase_if(m, is_odd_pair);
+  auto num = std::erase_if(m, is_odd_pair);
   std::map<int, std::string> t{ { 10, "A" }, { 12, "C" },
 				{ 14, "D" }, { 18, "G" } };
   VERIFY( m == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -46,10 +47,11 @@
 				      { 22, "U" }, { 22, "V" },
 				      { 23, "W" }, { 23, "X" },
 				      { 24, "Y" }, { 25, "Z" } };
-  std::erase_if(mm, is_odd_pair);
+  auto num = std::erase_if(mm, is_odd_pair);
   std::multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
 				     { 22, "V" }, { 24, "Y" } };
   VERIFY( mm == t );
+  VERIFY( num == 4 );
 }
 
 int
Index: testsuite/23_containers/set/erasure.cc
===================================================================
--- testsuite/23_containers/set/erasure.cc	(revision 266623)
+++ testsuite/23_containers/set/erasure.cc	(working copy)
@@ -27,9 +27,10 @@
 test01()
 {
   std::set<int> s{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase_if(s, is_odd);
+  auto num = std::erase_if(s, is_odd);
   std::set<int> t{ 10, 12, 14, 18 };
   VERIFY( s == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -36,9 +37,10 @@
 test02()
 {
   std::multiset<int> ms{ 20, 21, 22, 22, 23, 23, 24, 25 };
-  std::erase_if(ms, is_odd);
+  auto num = std::erase_if(ms, is_odd);
   std::multiset<int> t{ 20, 22, 22, 24 };
   VERIFY( ms == t );
+  VERIFY( num == 4 );
 }
 
 int
Index: testsuite/23_containers/unordered_map/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_map/erasure.cc	(revision 266623)
+++ testsuite/23_containers/unordered_map/erasure.cc	(working copy)
@@ -33,10 +33,11 @@
 					   { 12, "C" }, { 14, "D" },
 					   { 15, "E" }, { 17, "F" },
 					   { 18, "G" }, { 19, "H" } };
-  std::erase_if(um, is_odd_pair);
+  auto num = std::erase_if(um, is_odd_pair);
   std::unordered_map<int, std::string> t{ { 10, "A" }, { 12, "C" },
 					  { 14, "D" }, { 18, "G" } };
   VERIFY( um == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -46,10 +47,11 @@
 						 { 22, "U" }, { 22, "V" },
 						 { 23, "W" }, { 23, "X" },
 						 { 24, "Y" }, { 25, "Z" } };
-  std::erase_if(umm, is_odd_pair);
+  auto num = std::erase_if(umm, is_odd_pair);
   std::unordered_multimap<int, std::string> t{ { 20, "S" }, { 22, "U" },
 					       { 22, "V" }, { 24, "Y" } };
   VERIFY( umm == t );
+  VERIFY( num == 4 );
 }
 
 int
Index: testsuite/23_containers/unordered_set/erasure.cc
===================================================================
--- testsuite/23_containers/unordered_set/erasure.cc	(revision 266623)
+++ testsuite/23_containers/unordered_set/erasure.cc	(working copy)
@@ -27,9 +27,10 @@
   auto is_odd = [](const int i) { return i % 2 != 0; };
 
   std::unordered_set<int> us{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase_if(us, is_odd);
+  auto num = std::erase_if(us, is_odd);
   std::unordered_set<int> t{ 10, 12, 14, 18 };
   VERIFY( us == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -38,9 +39,10 @@
   auto is_odd = [](const int i) { return i % 2 != 0; };
 
   std::unordered_multiset<int> ums{ 20, 21, 22, 22, 23, 23, 24, 25 };
-  std::erase_if(ums, is_odd);
+  auto num = std::erase_if(ums, is_odd);
   std::unordered_multiset<int> t{ 20, 22, 22, 24 };
   VERIFY( ums == t );
+  VERIFY( num == 4 );
 }
 
 int
Index: testsuite/23_containers/vector/erasure.cc
===================================================================
--- testsuite/23_containers/vector/erasure.cc	(revision 266623)
+++ testsuite/23_containers/vector/erasure.cc	(working copy)
@@ -27,9 +27,10 @@
   auto is_odd = [](const int i) { return i % 2 != 0; };
 
   std::vector<int> v{ 10, 11, 12, 14, 15, 17, 18, 19 };
-  std::erase_if(v, is_odd);
+  auto num = std::erase_if(v, is_odd);
   std::vector<int> t{ 10, 12, 14, 18 };
   VERIFY( v == t );
+  VERIFY( num == 4 );
 }
 
 void
@@ -36,11 +37,13 @@
 test02()
 {
   std::vector<int> v{ 0, 11, 0, 0, 22, 33, 0, 0, 44, 0 };
-  std::erase(v, 0);
+  auto num = std::erase(v, 0);
   std::vector<int> t{ 11, 22, 33, 44 };
   VERIFY( v == t );
-  std::erase(v, 55);
+  VERIFY( num == 4 );
+  num = std::erase(v, 55);
   VERIFY( v == t );
+  VERIFY( num == 0 );
 }
 
 int

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH, libstdc++] Uniform container erasure for c++20 returning number of erasures.
  2018-11-29 17:06   ` Ed Smith-Rowland
@ 2018-11-30  0:05     ` Ed Smith-Rowland
  2018-11-30 10:25     ` [PATCH, libstdc++] Uniform container erasure for c++20 Jonathan Wakely
  1 sibling, 0 replies; 14+ messages in thread
From: Ed Smith-Rowland @ 2018-11-30  0:05 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

This version of erase_if/erase returning number erased actually build 
and tests cleanly on x86_64-linux.

Is this what you has in mind for this?  I basically return the number of 
erased items for all the things

Ed


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-29 17:06   ` Ed Smith-Rowland
  2018-11-30  0:05     ` [PATCH, libstdc++] Uniform container erasure for c++20 returning number of erasures Ed Smith-Rowland
@ 2018-11-30 10:25     ` Jonathan Wakely
  2018-11-30 10:41       ` Ville Voutilainen
  1 sibling, 1 reply; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-30 10:25 UTC (permalink / raw)
  To: Ed Smith-Rowland; +Cc: libstdc++, gcc-patches

On 29/11/18 12:05 -0500, Ed Smith-Rowland wrote:
>On 11/26/18 6:18 AM, Jonathan Wakely wrote:
>>On 24/11/18 13:54 -0500, Ed Smith-Rowland wrote:
>>>All,
>>>
>>>I's very late but uniform container erasure is, I think, the last 
>>>little tidbit to graduate from fundamentals/v2 to std at the last 
>>>meeting.  I think it would be a shame not to nudge this into 
>>>gcc-9.  The routines are very short so I just copied them. Ditto 
>>>the testcases (with adjustments).  The node erasure tool was moved 
>>>from experimental to std/bits and adjustments made to affected 
>>>*set/*map headers.
>>>
>>>The experimental code has been in our tree since 2015.
>>>
>>>This builds and tests clean on x86_64-linux.
>>
>>OK for trunk as it only touches experimental C++2a and TS material.
>>Thanks.
>>
>>I pointed out to the committee that the erase_if functions added to
>>C++20 completely overlook P0646R1 "Improving the Return Value of
>>Erase-Like Algorithms" and so fail to preserve the useful information
>>returned by the members of the linked list containers.
>Is *this* what you has in mind for this?  I basically return the 
>number of erased items for all the things.

Yes, that's exactly what I had in mind (and what I expect to get
proposed for C++20 in the near future).

What does everyone else think, should we go ahead and do this?

The point is that C++20 changed forward_list (and list, for
consistency) to return the number of removed elements. The reason for
that is you can't easily find out the size before and after removing
elements, because forward_list doesn't have a size() member!

So IMHO the non-member erase should also return the size, and so that
it's uniform it should do that for all containers not just the lists.


>Index: include/std/forward_list
>===================================================================
>--- include/std/forward_list	(revision 266623)
>+++ include/std/forward_list	(working copy)
>@@ -66,16 +66,17 @@
> {
> _GLIBCXX_BEGIN_NAMESPACE_VERSION
>   template<typename _Tp, typename _Alloc, typename _Predicate>
>-    inline void
>+    inline typename forward_list<_Tp, _Alloc>::size_type
>     erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
>-    { __cont.remove_if(__pred); }
>+    { return __cont.remove_if(__pred); }
>
>   template<typename _Tp, typename _Alloc, typename _Up>
>-    inline void
>+    inline typename forward_list<_Tp, _Alloc>::size_type
>     erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
>     {
>       using __elem_type = typename forward_list<_Tp, _Alloc>::value_type;
>-      erase_if(__cont, [&](__elem_type& __elem) { return __elem == __value; });
>+      return erase_if(__cont,
>+		      [&](__elem_type& __elem) { return __elem == __value; });
>     }

I realised this can be a polymorphic lambda (here and in the TS
version) because it's only defined for C++14 and later. Also, the
erase overload that calls erase_if needs to qualify it as std::erase_if
to prevent ADL:

      return std::erase_if(__cont,
                           [&](auto& __elem) { return __elem == __value; });

Same comment for the erase(std::list) case.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-30 10:25     ` [PATCH, libstdc++] Uniform container erasure for c++20 Jonathan Wakely
@ 2018-11-30 10:41       ` Ville Voutilainen
  2018-11-30 11:01         ` Jonathan Wakely
  0 siblings, 1 reply; 14+ messages in thread
From: Ville Voutilainen @ 2018-11-30 10:41 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Ed Smith-Rowland, libstdc++, gcc-patches List

On Fri, 30 Nov 2018 at 12:25, Jonathan Wakely <jwakely@redhat.com> wrote:
> Yes, that's exactly what I had in mind (and what I expect to get
> proposed for C++20 in the near future).
>
> What does everyone else think, should we go ahead and do this?

Yes, if we are confident that's what will be in C++20.

> The point is that C++20 changed forward_list (and list, for
> consistency) to return the number of removed elements. The reason for
> that is you can't easily find out the size before and after removing
> elements, because forward_list doesn't have a size() member!
> So IMHO the non-member erase should also return the size, and so that
> it's uniform it should do that for all containers not just the lists.

I don't mind forward_list being an exception. Returning the size from
other containers
is a bit pointless; presumably it would need to return a pair, and
handling that is clunky
even with structured bindings.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH, libstdc++] Uniform container erasure for c++20.
  2018-11-30 10:41       ` Ville Voutilainen
@ 2018-11-30 11:01         ` Jonathan Wakely
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Wakely @ 2018-11-30 11:01 UTC (permalink / raw)
  To: Ville Voutilainen; +Cc: Ed Smith-Rowland, libstdc++, gcc-patches List

On 30/11/18 12:40 +0200, Ville Voutilainen wrote:
>On Fri, 30 Nov 2018 at 12:25, Jonathan Wakely <jwakely@redhat.com> wrote:
>> Yes, that's exactly what I had in mind (and what I expect to get
>> proposed for C++20 in the near future).
>>
>> What does everyone else think, should we go ahead and do this?
>
>Yes, if we are confident that's what will be in C++20.

We're not, but we don't need to be. Anything in the current draft
could get removed before the final standard.

>> The point is that C++20 changed forward_list (and list, for
>> consistency) to return the number of removed elements. The reason for
>> that is you can't easily find out the size before and after removing
>> elements, because forward_list doesn't have a size() member!
>> So IMHO the non-member erase should also return the size, and so that

Oops, I meant "should also return the number of removed elements", not
"the number of removed element and also the new size".


>> it's uniform it should do that for all containers not just the lists.
>
>I don't mind forward_list being an exception. Returning the size from
>other containers
>is a bit pointless; presumably it would need to return a pair, and
>handling that is clunky
>even with structured bindings.

No need for a pair, sorry for the confusing wording above.


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-11-30 11:01 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-24 18:55 [PATCH, libstdc++] Uniform container erasure for c++20 Ed Smith-Rowland
2018-11-26 11:18 ` Jonathan Wakely
2018-11-28 17:12   ` Ed Smith-Rowland
2018-11-29  0:25     ` Jonathan Wakely
2018-11-29 13:47       ` Ed Smith-Rowland
2018-11-29 14:09         ` Jonathan Wakely
2018-11-29 15:19           ` Ed Smith-Rowland
2018-11-29 16:32             ` Jonathan Wakely
2018-11-29 14:12         ` Jakub Jelinek
2018-11-29 17:06   ` Ed Smith-Rowland
2018-11-30  0:05     ` [PATCH, libstdc++] Uniform container erasure for c++20 returning number of erasures Ed Smith-Rowland
2018-11-30 10:25     ` [PATCH, libstdc++] Uniform container erasure for c++20 Jonathan Wakely
2018-11-30 10:41       ` Ville Voutilainen
2018-11-30 11:01         ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).