This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/4] libstdc++: istreambuf_iterator keep attached streambuf
- From: Petr Ovtchenkov <ptr at void-ptr dot info>
- To: libstdc++ at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Tue, 14 Nov 2017 14:40:43 +0300
- Subject: [PATCH 2/4] libstdc++: istreambuf_iterator keep attached streambuf
- Authentication-results: sourceware.org; auth=none
- References: <cd085d750d6518747a71b80a55128e4639564746.1510778853.git.ptr@void-ptr.info>
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 proxy object, 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.
istreambuf_iterator should has ctor from proxy object,
so proxy should store pointer to streambuf object.
---
libstdc++-v3/include/bits/streambuf_iterator.h | 67 ++++++++++++++--------
.../24_iterators/istreambuf_iterator/3.cc | 66 +++++++++++++++++++++
2 files changed, 109 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 69ee013..08fb13b 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -98,6 +98,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
mutable int_type _M_c;
public:
+ class proxy
+ {
+ friend class istreambuf_iterator;
+ private:
+ proxy(int_type c, streambuf_type* sbuf_) :
+ _M_c(c),
+ _M_sbuf(sbuf_)
+ { }
+ int_type _M_c;
+ streambuf_type* _M_sbuf;
+
+ 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
: _M_sbuf(0), _M_c(traits_type::eof()) { }
@@ -116,6 +134,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
istreambuf_iterator(streambuf_type* __s) _GLIBCXX_USE_NOEXCEPT
: _M_sbuf(__s), _M_c(traits_type::eof()) { }
+ /// Construct start of istreambuf iterator.
+ istreambuf_iterator(const proxy& __p) _GLIBCXX_USE_NOEXCEPT
+ : _M_sbuf(__p._M_sbuf), _M_c(traits_type::eof()) { }
+
/// Return the current character pointed to by iterator. This returns
/// streambuf.sgetc(). It cannot be assigned. NB: The result of
/// operator*() on an end of stream is undefined.
@@ -136,29 +158,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
+ 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;
+ proxy __old(_M_c, _M_sbuf);
if (_M_sbuf)
{
- __old._M_c = _M_sbuf->sbumpc();
+ _M_sbuf->sbumpc();
_M_c = traits_type::eof();
}
return __old;
@@ -177,18 +209,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 +362,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 +397,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 +418,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..50413fa
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc
@@ -0,0 +1,66 @@
+// { 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
+// <http://www.gnu.org/licenses/>.
+
+#include <algorithm>
+#include <sstream>
+#include <iterator>
+#include <cstring>
+#include <testsuite_hooks.h>
+
+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<char> i(s);
+ copy_n(i, 36, r);
+ ++i; // EOF reached
+ VERIFY(i == std::istreambuf_iterator<char>());
+
+ VERIFY(memcmp(b, r, 36) == 0);
+
+ s << q;
+ VERIFY(!s.fail());
+
+ copy_n(i, 36, r);
+ ++i; // EOF reached
+ VERIFY(i == std::istreambuf_iterator<char>());
+
+ VERIFY(memcmp(q, r, 36) == 0);
+
+ s << 'Q';
+
+ VERIFY(*i++ == 'Q');
+ VERIFY(i == std::istreambuf_iterator<char>());
+}
+
+int main()
+{
+ test03();
+
+ return 0;
+}
--
2.10.1