From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x342.google.com (mail-wm1-x342.google.com [IPv6:2a00:1450:4864:20::342]) by sourceware.org (Postfix) with ESMTPS id 9F48D3973008; Fri, 22 May 2020 20:57:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9F48D3973008 Received: by mail-wm1-x342.google.com with SMTP id w64so11133313wmg.4; Fri, 22 May 2020 13:57:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=L55rLVBKQeoVQyVCPg4ThgFjq3j7MtNFcEANx2fLNYc=; b=JaWG+/zZ14SLD1GOGCZOmSPHijljuF6xBlIr9Jj7Fxvtv5JY5FfUwrSvAIfpe/A6sR /KkcZblg56zckoJkF8LbSNrQPl731TmWd/3gooCAgW+DNIeZ6dWDvXoz7xKqSgLhzokW hyD8rxh3vrdUTmX/fVNx92Y5/CtBWC57KnExXAowmlzkgQ4aPuQhfXA6zCr+6dnZHzaS Wc2VufjfPETY5bHtk3TZRTMbfaGN7HhRLoMlORFI3qDgYhXE5SrIlYH6b8qSWt98JHip wxPLt/EYHIRo/Q76SuEPpFW4JQAmAeYLjC6FdpkW4yp7a1SmKTzatfZ/yrUBVJHgD9v1 L6Yw== X-Gm-Message-State: AOAM533BaXSEwd4JTp4eryBOPQpF5wje95OsUXllg9ronmTNPJTuwKJ1 9+KPMasot9qfiB6iipy63jmWqmXXtzE= X-Google-Smtp-Source: ABdhPJyplhfPSIifv/olPLesRlfc9c+wjQYRnOGT0AFhZhgn9duqjo21JWc4hBNtcja1yZ3LUf/sMQ== X-Received: by 2002:a7b:cb86:: with SMTP id m6mr15356962wmi.41.1590181041347; Fri, 22 May 2020 13:57:21 -0700 (PDT) Received: from ?IPv6:2a01:e0a:1dc:b1c0:39b2:8917:272b:b82a? ([2a01:e0a:1dc:b1c0:39b2:8917:272b:b82a]) by smtp.googlemail.com with ESMTPSA id z16sm1678579wmf.3.2020.05.22.13.57.19 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 22 May 2020 13:57:19 -0700 (PDT) Subject: Re: [PATCH] Extend std::copy/std::copy_n char* overload to deque iterator To: Jonathan Wakely Cc: "libstdc++@gcc.gnu.org" , gcc-patches References: <20200521121712.GC2678@redhat.com> From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= Message-ID: <1f3fe6ef-cd1a-5fad-7d2b-a01a80a37269@gmail.com> Date: Fri, 22 May 2020 22:57:18 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 MIME-Version: 1.0 In-Reply-To: <20200521121712.GC2678@redhat.com> Content-Type: multipart/mixed; boundary="------------D54D6AC09909B1A717E115CA" Content-Language: fr X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 22 May 2020 20:57:25 -0000 This is a multi-part message in MIME format. --------------D54D6AC09909B1A717E115CA Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit On 21/05/20 2:17 pm, Jonathan Wakely wrote: > > Why is the optimization not done for C++03 mode? > I did it this way because the new std::copy overload rely on std::copy_n implementation details which is a C++11 algo. > It looks like the uses of 'auto' can be reaplced easily, and > __enable_if_t<> can be replaced with __gnu_cxx::__enable_if<>::__type. > But yes, we can indeed provide those implementation details in pre-C++11. This is what I've done in this new version. Tested under Linux x86_64 in default c++ mode. I tried to use CXXFLAGS=-std=c++03 but it doesn't seem to work even if I do see the option in build logs. I remember you adivised a different approach, can you tell me again ? François --------------D54D6AC09909B1A717E115CA Content-Type: text/x-patch; charset=UTF-8; name="deque_streambuf_ite.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="deque_streambuf_ite.patch" diff --git a/libstdc++-v3/include/bits/deque.tcc b/libstdc++-v3/include/bits/deque.tcc index e773f32b256..66ecd9da2f3 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; } + template + 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 __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 _OI diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h index 932ece55529..70d8232aece 100644 --- a/libstdc++-v3/include/bits/stl_algo.h +++ b/libstdc++-v3/include/bits/stl_algo.h @@ -705,31 +705,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __result; } - template - _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 - __enable_if_t<__is_char<_CharT>::__value, _CharT*> - __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT>>, - _Size, _CharT*); - template _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::value) { return __it; } + template + _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 + 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 _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 + _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 __gnu_cxx::__enable_if< + __is_char<_CharT>::__value, _CharT*>::__type + __copy_n_a(istreambuf_iterator<_CharT, char_traits<_CharT> >, + _Size, _CharT*, bool); + + template + 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 diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h index d3f1610fc8d..184c82cd5bf 100644 --- a/libstdc++-v3/include/bits/streambuf_iterator.h +++ b/libstdc++-v3/include/bits/streambuf_iterator.h @@ -82,11 +82,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __copy_move_a2(istreambuf_iterator<_CharT2>, istreambuf_iterator<_CharT2>, _CharT2*); -#if __cplusplus >= 201103L template - 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 friend typename __gnu_cxx::__enable_if<__is_char<_CharT2>::__value, @@ -396,10 +395,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __result; } -#if __cplusplus >= 201103L template - __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 __gnu_cxx::__enable_if<__is_char<_CharT>::__value, diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc b/libstdc++-v3/include/debug/safe_iterator.tcc index f90bbf3d125..ca4e2d52d1d 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 + _Ite + __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, + std::random_access_iterator_tag>& __it) + { return __it.base(); } + template _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 fe04e9342e7..bc23497ff0e 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 #include #include +#include #include @@ -76,9 +77,34 @@ void test02() VERIFY( !memcmp(buffer.data(), buffer_ref, 16500) ); } +void test03() +{ + using namespace std; + + typedef istreambuf_iterator in_iterator_type; + + ifstream fbuf_ref("istream_unformatted-1.txt"), + fbuf("istream_unformatted-1.txt"); + + char buffer_ref[16500]; + std::deque 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..26627e37440 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/streambuf_iterators/char/debug/deque_neg.cc @@ -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 +// . + +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include +#include +#include +#include + +void test01() +{ + using namespace std; + + typedef istreambuf_iterator 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 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..ede641820b5 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/debug/istreambuf_ite_deque_neg.cc @@ -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 +// . + +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-fileio "" } +// { dg-require-debug-mode "" } + +#include +#include +#include +#include + +void test01() +{ + using namespace std; + + typedef istreambuf_iterator in_iterator_type; + + ifstream fbuf_ref("istream_unformatted-1.txt"), + fbuf("istream_unformatted-1.txt"); + + char buffer_ref[16500]; + deque 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..5e1a0c2b75b --- /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) 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 +// . + +#include +#include +#include +#include + +#include + +void test01() +{ + using namespace std; + + typedef istreambuf_iterator 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..ace73701b90 --- /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) 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 +// . + +#include +#include +#include +#include + +#include + +void test01() +{ + using namespace std; + + typedef istreambuf_iterator in_iterator_type; + + ifstream fbuf_ref("istream_unformatted-1.txt"), + fbuf("istream_unformatted-1.txt"); + + char buffer_ref[16500]; + deque 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; +} --------------D54D6AC09909B1A717E115CA--