From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 112452 invoked by alias); 4 Oct 2017 05:04:51 -0000 Mailing-List: contact libstdc++-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libstdc++-owner@gcc.gnu.org Received: (qmail 112433 invoked by uid 89); 4 Oct 2017 05:04:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-19.2 required=5.0 tests=AWL,BAYES_00,DATE_IN_PAST_96_XX,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_INFOUSMEBIZ,KAM_LAZY_DOMAIN_SECURITY,RDNS_DYNAMIC autolearn=ham version=3.3.2 spammy= X-Spam-User: qpsmtpd, 2 recipients X-HELO: void-ptr.info Received: from pppoe.185.44.68.223.lanport.ru (HELO void-ptr.info) (185.44.68.223) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 04 Oct 2017 05:04:49 +0000 Received: from ptr by void-ptr.info with local (Exim 4.72) (envelope-from ) id 1dzbrP-0008CX-Di; Wed, 04 Oct 2017 08:04:43 +0300 Message-Id: From: Petr Ovtchenkov Date: Wed, 04 Oct 2017 05:04:00 -0000 Subject: [PATCH v2] libstdc++: istreambuf_iterator keep attached streambuf To: libstdc++@gcc.gnu.org, Jonathan Wakely Cc: gcc-patches@gcc.gnu.org In-Reply-To: <20171003233927.6b5a151c@void-ptr.info> References: <20170928103425.GG4582@redhat.com> <20170928150643.2f667ec9@void-ptr.info> <20170928123806.GN4582@redhat.com> <20171003233927.6b5a151c@void-ptr.info> X-IsSubscribed: yes X-SW-Source: 2017-10/txt/msg00012.txt.bz2 istreambuf_iterator should not forget about attached streambuf when it reach EOF. Checks in debug mode has no infuence more on character extraction in istreambuf_iterator increment operators. In this aspect behaviour in debug and non-debug mode is similar now. Test for detached srteambuf in istreambuf_iterator: When istreambuf_iterator reach EOF of istream, it should not forget about attached streambuf. >From fact "EOF in stream reached" not follow that stream reach end of life and input operation impossible more. postfix increment (r++) return isb_iterator_proxy, due to copies of the previous value of r are no longer required either to be dereferenceable or to be in the domain of ==. i.e. type that usable only for dereference and extraction "previous" character. --- libstdc++-v3/include/bits/streambuf_iterator.h | 60 ++++++++++++-------- .../24_iterators/istreambuf_iterator/3.cc | 64 ++++++++++++++++++++++ 2 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h index f0451b1..b71bdd2 100644 --- a/libstdc++-v3/include/bits/streambuf_iterator.h +++ b/libstdc++-v3/include/bits/streambuf_iterator.h @@ -97,6 +97,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION mutable streambuf_type* _M_sbuf; mutable int_type _M_c; + class isb_iterator_proxy + { + friend class istreambuf_iterator; + private: + isb_iterator_proxy(int_type c) : + _M_c(c) + { } + int_type _M_c; + + public: + char_type + operator*() const + { return traits_type::to_char_type(_M_c); } + }; + public: /// Construct end of input stream iterator. _GLIBCXX_CONSTEXPR istreambuf_iterator() _GLIBCXX_USE_NOEXCEPT @@ -136,29 +151,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION istreambuf_iterator& operator++() { - __glibcxx_requires_cond(!_M_at_eof(), + __glibcxx_requires_cond(_M_sbuf, _M_message(__gnu_debug::__msg_inc_istreambuf) ._M_iterator(*this)); if (_M_sbuf) { +#ifdef _GLIBCXX_DEBUG_PEDANTIC + int_type __tmp = +#endif _M_sbuf->sbumpc(); +#ifdef _GLIBCXX_DEBUG_PEDANTIC + __glibcxx_requires_cond(!traits_type::eq_int_type(__tmp,traits_type::eof()), + _M_message(__gnu_debug::__msg_inc_istreambuf) + ._M_iterator(*this)); +#endif _M_c = traits_type::eof(); } return *this; } /// Advance the iterator. Calls streambuf.sbumpc(). - istreambuf_iterator + isb_iterator_proxy operator++(int) { - __glibcxx_requires_cond(!_M_at_eof(), + _M_get(); + __glibcxx_requires_cond(_M_sbuf + && !traits_type::eq_int_type(_M_c,traits_type::eof()), _M_message(__gnu_debug::__msg_inc_istreambuf) ._M_iterator(*this)); - istreambuf_iterator __old = *this; + isb_iterator_proxy __old(_M_c); if (_M_sbuf) { - __old._M_c = _M_sbuf->sbumpc(); + _M_sbuf->sbumpc(); _M_c = traits_type::eof(); } return __old; @@ -177,18 +202,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_get() const { const int_type __eof = traits_type::eof(); - int_type __ret = __eof; - if (_M_sbuf) - { - if (!traits_type::eq_int_type(_M_c, __eof)) - __ret = _M_c; - else if (!traits_type::eq_int_type((__ret = _M_sbuf->sgetc()), - __eof)) - _M_c = __ret; - else - _M_sbuf = 0; - } - return __ret; + if (_M_sbuf && traits_type::eq_int_type(_M_c, __eof)) + _M_c = _M_sbuf->sgetc(); + return _M_c; } bool @@ -339,7 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef typename __is_iterator_type::streambuf_type streambuf_type; typedef typename traits_type::int_type int_type; - if (__first._M_sbuf && !__last._M_sbuf) + if (__first._M_sbuf && (__last == istreambuf_iterator<_CharT>())) { streambuf_type* __sb = __first._M_sbuf; int_type __c = __sb->sgetc(); @@ -374,7 +390,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef typename __is_iterator_type::streambuf_type streambuf_type; typedef typename traits_type::int_type int_type; - if (__first._M_sbuf && !__last._M_sbuf) + if (__first._M_sbuf && (__last == istreambuf_iterator<_CharT>())) { const int_type __ival = traits_type::to_int_type(__val); streambuf_type* __sb = __first._M_sbuf; @@ -395,11 +411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else __c = __sb->snextc(); } - - if (!traits_type::eq_int_type(__c, traits_type::eof())) - __first._M_c = __c; - else - __first._M_sbuf = 0; + __first._M_c = __c; } return __first; } diff --git a/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc new file mode 100644 index 0000000..5792e0d --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc @@ -0,0 +1,64 @@ +// { dg-options "-std=gnu++17" } + +// Copyright (C) 2017 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 test03() +{ + using namespace std; + + std::stringstream s; + char b[] = "c2ee3d09-43b3-466d-b490-db35999a22cf"; + char r[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + char q[] = "3c4852d6-d47b-4f46-b05e-b5edc1aa440e"; + // 012345678901234567890123456789012345 + // 0 1 2 3 + s << b; + VERIFY( !s.fail() ); + + istreambuf_iterator i(s); + copy_n(i, 36, r); + ++i; // EOF reached + VERIFY(i == std::istreambuf_iterator()); + + VERIFY(memcmp(b, r, 36) == 0); + + s << q; + VERIFY(!s.fail()); + + copy_n(i, 36, r); + ++i; // EOF reached + VERIFY(i == std::istreambuf_iterator()); + + VERIFY(memcmp(q, r, 36) == 0); + + s << 'Q'; + + VERIFY(*i++ == 'Q'); +} + +int main() +{ + test03(); + return 0; +} -- 2.10.1