libstdc++: Specialize copy/copy_n for istreambuf_iterator and deque iterators
authorFrançois Dumont <fdumont@gcc.gnu.org>
Wed, 22 Jan 2020 17:21:28 +0000 (18:21 +0100)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Thu, 4 Jun 2020 20:27:47 +0000 (22:27 +0200)
Add __copy_n_a overloads for std::deque iterators to replace with C memmove
when possible. Expose std::copy_n implementation details in pre-C++11 modes
and use it for std::copy overloads.

libstdc++-v3/ChangeLog

* include/bits/stl_algo.h (__copy_n_a): Move to ...
* include/bits/stl_algobase.h (__copy_n_a): ...here. Add __strict
parameter.
(__copy_n_a(istreambuf_iterator<>, _Size, _Deque_iterator<>, bool)):
Declare.
(__niter_base(const _Safe_iterator<_Ite, _Seq,
random_access_iterator_tag>&)): Declare.
(__copy_move_a2(istreambuf_iterator<>, istreambuf_iterator<>,
_Deque_iterator<>)): Declare.
* include/bits/deque.tcc
(__copy_move_a2(istreambuf_iterator<>, istreambuf_iterator<>,
_Deque_iterator<>)): New.
(__copy_n_a(istreambuf_iterator<>, _Size, _Deque_iterator<>, bool)):
New.
* include/bits/streambuf_iterator.h
(__copy_n_a(istreambuf_iterator<>, _Size, _CharT*, bool)): Adapt.
* include/debug/safe_iterator.tcc (__niter_base): New.
* testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc
(test03): New.
* testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc:
New test.
* testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc:
New test.
* testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc: New test.
* testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc:
New test.

libstdc++-v3/include/bits/deque.tcc
libstdc++-v3/include/bits/stl_algo.h
libstdc++-v3/include/bits/stl_algobase.h
libstdc++-v3/include/bits/streambuf_iterator.h
libstdc++-v3/include/debug/safe_iterator.tcc
libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc
libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc [new file with mode: 0644]

index b4943e8ea77f7d5b6df60041475274a1bdea3680..1d32a1691c79713c0bcc7d024e9e10e01f3518f3 100644 (file)
@@ -1065,6 +1065,57 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
       return __result;
     }
 
+  template<bool _IsMove, typename _CharT>
+    typename __gnu_cxx::__enable_if<
+      __is_char<_CharT>::__value,
+      _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> >::__type
+    __copy_move_a2(
+       istreambuf_iterator<_CharT, char_traits<_CharT> > __first,
+       istreambuf_iterator<_CharT, char_traits<_CharT> > __last,
+       _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> __result)
+    {
+      if (__first == __last)
+       return __result;
+
+      for (;;)
+       {
+         const std::ptrdiff_t __len = __result._M_last - __result._M_cur;
+         const std::ptrdiff_t __nb
+           = std::__copy_n_a(__first, __len, __result._M_cur, false)
+           - __result._M_cur;
+         __result += __nb;
+
+         if (__nb != __len)
+           break;
+       }
+
+      return __result;
+    }
+
+  template<typename _CharT, typename _Size>
+    typename __gnu_cxx::__enable_if<
+      __is_char<_CharT>::__value,
+      _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> >::__type
+    __copy_n_a(
+      istreambuf_iterator<_CharT, char_traits<_CharT> > __it, _Size __size,
+      _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> __result,
+      bool __strict)
+    {
+      if (__size == 0)
+       return __result;
+
+      do
+       {
+         const _Size __len
+           = std::min<_Size>(__result._M_last - __result._M_cur, __size);
+         std::__copy_n_a(__it, __len, __result._M_cur, __strict);
+         __result += __len;
+         __size -= __len;
+       }
+      while (__size != 0);
+      return __result;
+    }
+
   template<bool _IsMove,
           typename _Tp, typename _Ref, typename _Ptr, typename _OI>
     _OI
index b743c87cb80a325e33361242ce22cf4748d545e4..fd6edd0d5f4a5a2937cb64f54542228611d6e8b8 100644 (file)
@@ -705,31 +705,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __result;
     }
 
-  template<typename _InputIterator, typename _Size, typename _OutputIterator>
-    _GLIBCXX20_CONSTEXPR
-    _OutputIterator
-    __copy_n_a(_InputIterator __first, _Size __n, _OutputIterator __result)
-    {
-      if (__n > 0)
-       {
-         while (true)
-           {
-             *__result = *__first;
-             ++__result;
-             if (--__n > 0)
-               ++__first;
-             else
-               break;
-           }
-       }
-      return __result;
-    }
-  template<typename _CharT, typename _Size>
-    __enable_if_t<__is_char<_CharT>::__value, _CharT*>
-    __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT>>,
-              _Size, _CharT*);
-
   template<typename _InputIterator, typename _Size, typename _OutputIterator>
     _GLIBCXX20_CONSTEXPR
     _OutputIterator
@@ -738,7 +713,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       return std::__niter_wrap(__result,
                               __copy_n_a(__first, __n,
-                                         std::__niter_base(__result)));
+                                         std::__niter_base(__result), true));
     }
 
   template<typename _RandomAccessIterator, typename _Size,
index 0a0e29923b8c94b52c2da9e08ff1274def3fea34..0163d8f902d697b5652668e107791bd1fd918383 100644 (file)
@@ -314,6 +314,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value)
     { return __it; }
 
+  template<typename _Ite, typename _Seq>
+    _Ite
+    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+                std::random_access_iterator_tag>&);
+
   // Reverse the __niter_base transformation to get a
   // __normal_iterator back again (this assumes that __normal_iterator
   // is only used to wrap random access iterators, like pointers).
@@ -466,6 +471,15 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
     __copy_move_a2(istreambuf_iterator<_CharT, char_traits<_CharT> >,
                   istreambuf_iterator<_CharT, char_traits<_CharT> >, _CharT*);
 
+  template<bool _IsMove, typename _CharT>
+    typename __gnu_cxx::__enable_if<
+      __is_char<_CharT>::__value,
+      _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> >::__type
+    __copy_move_a2(
+       istreambuf_iterator<_CharT, char_traits<_CharT> >,
+       istreambuf_iterator<_CharT, char_traits<_CharT> >,
+       _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>);
+
   template<bool _IsMove, typename _II, typename _OI>
     _GLIBCXX20_CONSTEXPR
     inline _OI
@@ -539,6 +553,41 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
                  const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
                  const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>&);
 
+  template<typename _InputIterator, typename _Size, typename _OutputIterator>
+    _GLIBCXX20_CONSTEXPR
+    _OutputIterator
+    __copy_n_a(_InputIterator __first, _Size __n, _OutputIterator __result,
+              bool)
+    {
+      if (__n > 0)
+       {
+         while (true)
+           {
+             *__result = *__first;
+             ++__result;
+             if (--__n > 0)
+               ++__first;
+             else
+               break;
+           }
+       }
+      return __result;
+    }
+
+  template<typename _CharT, typename _Size>
+    typename __gnu_cxx::__enable_if<
+      __is_char<_CharT>::__value, _CharT*>::__type
+    __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT> >,
+              _Size, _CharT*, bool);
+
+  template<typename _CharT, typename _Size>
+    typename __gnu_cxx::__enable_if<
+      __is_char<_CharT>::__value,
+      _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*> >::__type
+    __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT> >, _Size,
+              _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>,
+              bool);
+
   /**
    *  @brief Copies the range [first,last) into result.
    *  @ingroup mutating_algorithms
index d3f1610fc8deee2992a345e79ec95f4faf87c27c..184c82cd5bf83375c735d2664d604cab20bded2d 100644 (file)
@@ -82,11 +82,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        __copy_move_a2(istreambuf_iterator<_CharT2>,
                       istreambuf_iterator<_CharT2>, _CharT2*);
 
-#if __cplusplus >= 201103L
       template<typename _CharT2, typename _Size>
-       friend __enable_if_t<__is_char<_CharT2>::__value, _CharT2*>
-       __copy_n_a(istreambuf_iterator<_CharT2>, _Size, _CharT2*);
-#endif
+       friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
+                                              _CharT2*>::__type
+       __copy_n_a(istreambuf_iterator<_CharT2>, _Size, _CharT2*, bool);
 
       template<typename _CharT2>
        friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value,
@@ -396,10 +395,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __result;
     }
 
-#if __cplusplus >= 201103L
   template<typename _CharT, typename _Size>
-    __enable_if_t<__is_char<_CharT>::__value, _CharT*>
-    __copy_n_a(istreambuf_iterator<_CharT> __it, _Size __n, _CharT* __result)
+    typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
+                                   _CharT*>::__type
+    __copy_n_a(istreambuf_iterator<_CharT> __it, _Size __n, _CharT* __result,
+              bool __strict __attribute__((__unused__)))
     {
       if (__n == 0)
        return __result;
@@ -409,12 +409,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                              ._M_iterator(__it));
       _CharT* __beg = __result;
       __result += __it._M_sbuf->sgetn(__beg, __n);
-      __glibcxx_requires_cond(__result - __beg == __n,
+      __glibcxx_requires_cond(!__strict || __result - __beg == __n,
                              _M_message(__gnu_debug::__msg_inc_istreambuf)
                              ._M_iterator(__it));
       return __result;
     }
-#endif // C++11
 
   template<typename _CharT>
     typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value,
index 312a88911ee3446bb7b6b965f9a4d3bd0bb562d5..888ac803ae53cbe58cdccfd19bbb59a161991a92 100644 (file)
@@ -234,6 +234,12 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  template<typename _Ite, typename _Seq>
+    _Ite
+    __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq,
+                std::random_access_iterator_tag>& __it)
+    { return __it.base(); }
+
   template<bool _IsMove,
           typename _Ite, typename _Seq, typename _Cat, typename _OI>
     _OI
index fe04e9342e73c36da66233cd5b4a9289d4913f3e..bc23497ff0ecdc54f17d9601d8fb974ed83994bd 100644 (file)
@@ -22,6 +22,7 @@
 #include <algorithm>
 #include <cstring>
 #include <vector>
+#include <deque>
 
 #include <testsuite_hooks.h>
 
@@ -76,9 +77,34 @@ void test02()
   VERIFY( !memcmp(buffer.data(), buffer_ref, 16500) );
 }
 
+void test03()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator<char> in_iterator_type;
+
+  ifstream fbuf_ref("istream_unformatted-1.txt"),
+          fbuf("istream_unformatted-1.txt");
+
+  char buffer_ref[16500];
+  std::deque<char> buffer(16500, 'a');
+
+  fbuf_ref.read(buffer_ref, 16500);
+
+  in_iterator_type beg(fbuf);
+  in_iterator_type end;
+  copy(beg, end, buffer.begin());
+
+  VERIFY( fbuf_ref.good() );
+  VERIFY( fbuf.good() );
+
+  VERIFY( std::equal(buffer.begin(), buffer.end(), buffer_ref) );
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
   return 0;
 }
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc
new file mode 100644 (file)
index 0000000..26627e3
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2020 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/>.
+
+// { dg-do run { xfail *-*-* } }
+// { dg-require-debug-mode "" }
+
+#include <iterator>
+#include <sstream>
+#include <deque>
+#include <algorithm>
+
+void test01()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator<char> in_iterator_type;
+
+  const char data1[] = "Drei Phantasien nach Friedrich Holderlin";
+  const string str1(data1);
+  istringstream iss1(str1);
+  in_iterator_type beg1(iss1);
+  in_iterator_type end1;
+  deque<char> d(sizeof(data1) - 2, '0');
+
+  copy(beg1, end1, d.begin());
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc
new file mode 100644 (file)
index 0000000..ede6418
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 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/>.
+
+// { dg-do run { target c++11 xfail *-*-* } }
+// { dg-require-fileio "" }
+// { dg-require-debug-mode "" }
+
+#include <iterator>
+#include <fstream>
+#include <algorithm>
+#include <deque>
+
+void test01()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator<char> in_iterator_type;
+
+  ifstream fbuf_ref("istream_unformatted-1.txt"),
+          fbuf("istream_unformatted-1.txt");
+
+  char buffer_ref[16500];
+  deque<char> dq(17000, 'a');
+
+  fbuf_ref.read(buffer_ref, 16500);
+
+  in_iterator_type beg(fbuf);
+  copy_n(beg, 17000, dq.begin());
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc
new file mode 100644 (file)
index 0000000..5e1a0c2
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do run { target c++11 } }
+// { dg-require-fileio "" }
+
+// Copyright (C) 2020 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 <iterator>
+#include <fstream>
+#include <algorithm>
+#include <cstring>
+
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator<char> in_iterator_type;
+
+  ifstream fbuf_ref("istream_unformatted-1.txt"),
+          fbuf("istream_unformatted-1.txt");
+
+  char buffer_ref[16500],
+       buffer[16501];
+
+  fbuf_ref.read(buffer_ref, 16500);
+
+  in_iterator_type beg(fbuf);
+  copy_n(beg, 16500, buffer);
+
+  VERIFY( fbuf_ref.good() );
+  VERIFY( fbuf.good() );
+
+  VERIFY( !memcmp(buffer, buffer_ref, 16500) );
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc
new file mode 100644 (file)
index 0000000..ace7370
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-do run { target c++11 } }
+// { dg-require-fileio "" }
+
+// Copyright (C) 2020 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 <iterator>
+#include <fstream>
+#include <algorithm>
+#include <deque>
+
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std;
+
+  typedef istreambuf_iterator<char> in_iterator_type;
+
+  ifstream fbuf_ref("istream_unformatted-1.txt"),
+          fbuf("istream_unformatted-1.txt");
+
+  char buffer_ref[16500];
+  deque<char> dq(16500, 'a');
+
+  fbuf_ref.read(buffer_ref, 16500);
+
+  in_iterator_type beg(fbuf);
+  copy_n(beg, 16500, dq.begin());
+
+  VERIFY( fbuf_ref.good() );
+  VERIFY( fbuf.good() );
+
+  VERIFY( equal(dq.begin(), dq.end(), buffer_ref) );
+}
+
+int
+main()
+{
+  test01();
+  return 0;
+}