Last patch of my series following this one: https://gcc.gnu.org/ml/libstdc++/2019-12/msg00028.html
This time I work on std::copy_n/std::copy overloads for istreambuf_iterator so that it works also for deque iterators and transparently in _GLIBCXX_DEBUG mode.
* include/bits/stl_algo.h (__copy_n_a): Move to ... * include/bits/stl_algobase.h (__copy_n_a): ...here. Add __strict parameter. (__niter_base(const _Safe_iterator<_Ite, _Seq, random_access_iterator_tag>&)): New declaration. (__copy_move_a2(istreambuf_iterator<>, istreambuf_iterator<>, _Deque_iterator<>)): New declaration. (__copy_n_a(istreambuf_iterator<>, _Size, _Deque_iterator<>, bool)): New declaration. * include/bits/deque.tcc (__copy_move_a2(istreambuf_iterator<>, istreambuf_iterator<>, _Deque_iterator<>)): Add definition. (__copy_n_a(istreambuf_iterator<>, _Size, _Deque_iterator<>, bool)): Add definition. * include/bits/streambuf_iterator.h (__copy_n_a(istreambuf_iterator<>, _Size, _CharT*, bool)): Adapt definition. * include/debug/safe_iterator.tcc (__niter_base): Add definition. * testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc (test03): New. * testsuite/25_algorithms/copy/streambuf_iterators/char/debug/ deque_neg.cc: New. * testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc: New. * testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc: New. * testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc: New. Tested under Linux x86_64 normal and debug modes. François
diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index ef32d2d19dd..009b696e7c4 100644 --- a/libstdc++-v3/include/bits/deque.tcc +++ b/libstdc++-v3/include/bits/deque.tcc @@ -1065,6 +1065,57 @@ _GLIBCXX_END_NAMESPACE_CONTAINER return __result; } +#if __cplusplus >= 201103L + template<bool _IsMove, typename _CharT> + __enable_if_t<__is_char<_CharT>::__value, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>> + __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 auto __len = __result._M_last - __result._M_cur; + const auto __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> + __enable_if_t<__is_char<_CharT>::__value, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>> + __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 auto __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; + } +#endif + template<bool _IsMove, typename _Tp, typename _Ref, typename _Ptr, typename _OI> _OI diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 769c27a02b6..4f2a6bbdbbf 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -775,31 +775,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 @@ -808,7 +783,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, diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 26addc26252..84c533ce0ba 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -370,6 +370,11 @@ namespace __detail _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). @@ -484,6 +489,13 @@ namespace __detail } }; +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + template<typename _Tp, typename _Ref, typename _Ptr> + struct _Deque_iterator; + +_GLIBCXX_END_NAMESPACE_CONTAINER + // Helpers for streambuf iterators (either istream or ostream). // NB: avoid including <iosfwd>, relatively large. template<typename _CharT> @@ -513,6 +525,16 @@ namespace __detail __copy_move_a2(istreambuf_iterator<_CharT, char_traits<_CharT> >, istreambuf_iterator<_CharT, char_traits<_CharT> >, _CharT*); +#if __cplusplus >= 201103L + template<bool _IsMove, typename _CharT> + __enable_if_t<__is_char<_CharT>::__value, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>> + __copy_move_a2( + istreambuf_iterator<_CharT, char_traits<_CharT> >, + istreambuf_iterator<_CharT, char_traits<_CharT> >, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>); +#endif + template<bool _IsMove, typename _II, typename _OI> _GLIBCXX20_CONSTEXPR inline _OI @@ -529,13 +551,6 @@ namespace __detail _Category>::__copy_m(__first, __last, __result); } -_GLIBCXX_BEGIN_NAMESPACE_CONTAINER - - template<typename _Tp, typename _Ref, typename _Ptr> - struct _Deque_iterator; - -_GLIBCXX_END_NAMESPACE_CONTAINER - template<bool _IsMove, typename _Tp, typename _Ref, typename _Ptr, typename _OI> _OI @@ -594,6 +609,41 @@ _GLIBCXX_END_NAMESPACE_CONTAINER const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&, const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>&); +#if __cplusplus >= 201103L + 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> + __enable_if_t<__is_char<_CharT>::__value, _CharT*> + __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT>>, + _Size, _CharT*, bool); + + template<typename _CharT, typename _Size> + __enable_if_t<__is_char<_CharT>::__value, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>> + __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT>>, _Size, + _GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>, + bool); +#endif + /** * @brief Copies the range [first,last) into result. * @ingroup mutating_algorithms diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h index f3a3bdf28f2..84d53ae9681 100644 --- a/libstdc++-v3/include/bits/streambuf_iterator.h +++ b/libstdc++-v3/include/bits/streambuf_iterator.h @@ -88,7 +88,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #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*); + __copy_n_a(istreambuf_iterator<_CharT2>, _Size, _CharT2*, bool); #endif template<typename _CharT2> @@ -384,7 +384,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #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) + __copy_n_a(istreambuf_iterator<_CharT> __it, _Size __n, _CharT* __result, + bool __strict __attribute__((__unused__))) { if (__n == 0) return __result; @@ -394,7 +395,7 @@ _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; diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc index 15b1a361e58..75e1d2e6a23 100644 --- a/libstdc++-v3/include/debug/safe_iterator.tcc +++ b/libstdc++-v3/include/debug/safe_iterator.tcc @@ -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 diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc index 3fd4e271521..ce44b538875 100644 --- a/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc +++ b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/4.cc @@ -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 index 00000000000..2f37857b9e8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc @@ -0,0 +1,46 @@ +// Copyright (C) 2019 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 index 00000000000..a821b380e61 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc @@ -0,0 +1,50 @@ +// Copyright (C) 2019 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 index 00000000000..fd45c438ee7 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/2.cc @@ -0,0 +1,56 @@ +// { dg-do run { target c++11 } } +// { dg-require-fileio "" } + +// Copyright (C) 2019 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 index 00000000000..69c57238caa --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/istreambuf_iterator/deque.cc @@ -0,0 +1,56 @@ +// { dg-do run { target c++11 } } +// { dg-require-fileio "" } + +// Copyright (C) 2019 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; +}