From: Jonathan Wakely <jwakely@redhat.com>
To: "François Dumont" <frs.dumont@gmail.com>
Cc: "libstdc++@gcc.gnu.org" <libstdc++@gcc.gnu.org>,
gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: Make tests less istreambuf_iterator implementation dependent
Date: Tue, 03 Oct 2017 14:20:00 -0000 [thread overview]
Message-ID: <20171003142023.GW4582@redhat.com> (raw)
In-Reply-To: <2285784f-dfce-3e48-30bf-902fe1d157b8@gmail.com>
On 02/10/17 07:43 +0200, François Dumont wrote:
>On 28/09/2017 23:56, Jonathan Wakely wrote:
>>On 28/09/17 21:59 +0200, François Dumont wrote:
>>>
>>>The current istreambuf_iterator implementation capture the current
>>>streambuf state each time it is tested for eof or evaluated. This
>>>is why I considered those tests as fragile.
>>
>>Yes, and I think that's non-conforming.
>>
>
>Good, then we have something to fix.
>
>>As I said in the other thread, I'd really like to see references to
>>the standard used to justify any changes to our istreambuf_iterator
>
>I think _M_c has been introduced to cover this paragraph of the Standard:
>
>24.6.3.1
>
>"1. Class istreambuf_iterator<charT,traits>::proxy is for exposition
>only. An implementation is permit-
>ted to provide equivalent functionality without providing a class with
>this name. Class istreambuf_-
>iterator<charT, traits>::proxy provides a temporary placeholder as the
>return value of the post-
>increment operator (operator++). It keeps the character pointed to by
>the previous value of the iterator for
>some possible future access to get the character."
>
>This is why it is being set in operator++(int):
>
>Â Â Â istreambuf_iterator __old = *this;
>Â Â Â __old._M_c = _M_sbuf->sbumpc();
>
>It is also the reason why libstdc++ fails:
>http://llvm.org/svn/llvm-project/libcxx/trunk/test/std/iterators/stream.iterators/istreambuf.iterator/istreambuf.iterator.cons/proxy.pass.cpp
>
>
>It looks like this test is simply not Standard conformant.
I think you're right, because it relies on a property that may not be
true:
any copies of the previous
value of r are no longer
required either to be
dereferenceable or to be in
the domain of ==.
>I guess at some point _M_c started to be used also to cache the
>streambuf::sgetc resulting in current situation.
And arguably that is not "equivalent functionality" to returning a
proxy object. Although the standard seems a bit underspecified.
>In attached patch I limit usage of _M_c to cover 24.6.3.1.1 point and
>so made additional changes to 2.cc test case to demonstrate it.
Doesn't the modified test PASS anyway, even without changing how _M_c
is used?
Generally this looks good (I'm not sure if it addresses Petr's
concerns, but I don't think his "stop and go" usage is valid anyway -
it's certainly not portable or guaranteed by the standard).
>@@ -103,7 +103,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> : _M_sbuf(0), _M_c(traits_type::eof()) { }
>
> #if __cplusplus >= 201103L
>- istreambuf_iterator(const istreambuf_iterator&) noexcept = default;
>+ istreambuf_iterator(const istreambuf_iterator&) = default;
Please don't remove this.
It's present in the standard, and it ensures we don't accidentally add
a member that makes the default noexcept(false).
>
> ~istreambuf_iterator() = default;
> #endif
>@@ -122,28 +122,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> char_type
> operator*() const
> {
>+ int_type __c = _M_get();
>+
> #ifdef _GLIBCXX_DEBUG_PEDANTIC
> // Dereferencing a past-the-end istreambuf_iterator is a
> // libstdc++ extension
>- __glibcxx_requires_cond(!_M_at_eof(),
>+ __glibcxx_requires_cond(!_S_at_eof(__c),
> _M_message(__gnu_debug::__msg_deref_istreambuf)
> ._M_iterator(*this));
> #endif
>- return traits_type::to_char_type(_M_get());
>+ return traits_type::to_char_type(__c);
> }
>
> /// Advance the iterator. Calls streambuf.sbumpc().
> istreambuf_iterator&
> operator++()
> {
>- __glibcxx_requires_cond(!_M_at_eof(),
>+ __glibcxx_requires_cond(_M_sbuf &&
>+ (!_S_at_eof(_M_c) || !_S_at_eof(_M_sbuf->sgetc())),
> _M_message(__gnu_debug::__msg_inc_istreambuf)
> ._M_iterator(*this));
>- if (_M_sbuf)
>- {
This check should be unnecessary, because it's undefined to increment
and end-of-stream iterator, but I wonder if anyone is relying on it
being currently a no-op, rather than crashing.
Let's remove the check, and if it causes too many problems we can
restore it as:
if (__builtin_expect(_M_sbuf != 0, 1))
>+
> _M_sbuf->sbumpc();
> _M_c = traits_type::eof();
>- }
> return *this;
> }
>
>@@ -151,16 +152,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> istreambuf_iterator
> operator++(int)
> {
>- __glibcxx_requires_cond(!_M_at_eof(),
>+ __glibcxx_requires_cond(_M_sbuf &&
>+ (!_S_at_eof(_M_c) || !_S_at_eof(_M_sbuf->sgetc())),
> _M_message(__gnu_debug::__msg_inc_istreambuf)
> ._M_iterator(*this));
>
> istreambuf_iterator __old = *this;
>- if (_M_sbuf)
>- {
> __old._M_c = _M_sbuf->sbumpc();
> _M_c = traits_type::eof();
>- }
> return __old;
> }
>
>@@ -176,26 +175,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> int_type
> _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;
Removing this assignment means that we will call _M_sbuf->sgetc() for
every dereference operation, instead of caching the current value in
_M_c. I think that's probably OK, because it's unlikely that
performance critical code is dereferencing the same iterator
repeatedly without incrementing it.
And getting rid of the mutable member is a Good Thing.
An alternative would be to cache it in operator*() instead of in
_M_get(), which would still give the desired change of not updating it
when _M_get() is used elsewhere. But would still involve setting a
mutable member in a const function.
>- else
>+ int_type __ret = _M_c;
>+ if (_M_sbuf && _S_at_eof(__ret) && _S_at_eof(__ret = _M_sbuf->sgetc()))
> _M_sbuf = 0;
It's unfortunate that we still have this assignment to a mutable
member in a const function, but I think it's necessary to avoid an
end-of-stream iterator becoming valid again.
>- }
> return __ret;
> }
>
> bool
> _M_at_eof() const
>+ { return _S_at_eof(_M_get()); }
>+
>+ static bool
>+ _S_at_eof(int_type __c)
This should be called _S_is_eof, since it tests if the argument **is**
the EOF character. It doesn't test if the stream is **at** EOF, like
_M_at_eof does.
So with a suitable ChangeLog, the "noexcept" kept on the constructor,
and renaming _S_at_eof to _S_is_eof, this is OK for trunk.
next prev parent reply other threads:[~2017-10-03 14:20 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-27 20:16 François Dumont
2017-09-28 12:12 ` Jonathan Wakely
2017-09-28 19:59 ` François Dumont
2017-09-28 21:56 ` Jonathan Wakely
2017-10-02 5:43 ` François Dumont
2017-10-03 14:20 ` Jonathan Wakely [this message]
2017-10-04 16:21 ` François Dumont
2017-10-04 23:23 ` Jonathan Wakely
2017-11-15 20:52 ` [PATCH 1/4] Revert "2017-10-04 Petr Ovtchenkov <ptr@void-ptr.info>" Petr Ovtchenkov
2017-11-15 20:52 ` [PATCH 2/4] libstdc++: istreambuf_iterator keep attached streambuf Petr Ovtchenkov
2017-11-15 20:52 ` [PATCH 3/4] libstdc++: avoid character accumulation in istreambuf_iterator Petr Ovtchenkov
2017-11-15 20:52 ` [PATCH 4/4] libstdc++: immutable _M_sbuf " Petr Ovtchenkov
2017-11-15 21:31 ` [PATCH 3/4] libstdc++: avoid character accumulation " Paolo Carlini
2017-11-16 5:32 ` Petr Ovtchenkov
2017-11-16 9:39 ` Paolo Carlini
2017-11-16 11:03 ` Petr Ovtchenkov
2017-11-16 11:29 ` Paolo Carlini
2017-11-16 11:41 ` Petr Ovtchenkov
2017-11-16 11:51 ` Paolo Carlini
2017-11-16 10:56 ` [PATCH 1/4] Revert "2017-10-04 Petr Ovtchenkov <ptr@void-ptr.info>" Jonathan Wakely
2017-11-16 11:35 ` Petr Ovtchenkov
2017-11-16 11:39 ` Jonathan Wakely
2017-11-16 11:40 ` Jonathan Wakely
2017-11-16 11:57 ` Petr Ovtchenkov
-- strict thread matches above, loose matches on Subject: below --
2017-10-13 17:14 Make istreambuf_iterator::_M_sbuf immutable and add debug checks François Dumont
2017-10-23 19:08 ` François Dumont
2017-11-06 21:19 ` François Dumont
2017-11-16 5:52 ` Petr Ovtchenkov
2017-11-16 10:57 ` Jonathan Wakely
2017-11-16 11:46 ` Jonathan Wakely
2017-11-16 12:08 ` Petr Ovtchenkov
2017-11-16 17:40 ` François Dumont
2017-11-16 18:12 ` Petr Ovtchenkov
2017-11-16 21:31 ` François Dumont
2017-09-23 7:10 [PATCH] libstdc++: istreambuf_iterator keep attached streambuf Petr Ovtchenkov
2017-09-25 13:46 ` Jonathan Wakely
2017-09-28 10:34 ` Jonathan Wakely
2017-09-28 12:06 ` Petr Ovtchenkov
2017-09-28 12:38 ` Jonathan Wakely
2017-10-03 20:39 ` Petr Ovtchenkov
2017-10-04 5:04 ` [PATCH v2] " Petr Ovtchenkov
2017-10-06 16:01 ` [PATCH] libstdc++: istreambuf_iterator proxy (was: keep attached streambuf) François Dumont
2017-10-06 18:00 ` Petr Ovtchenkov
2017-10-08 14:59 ` [PATCH] libstdc++: istreambuf_iterator proxy François Dumont
2017-10-09 19:32 ` Petr Ovtchenkov
2017-10-10 5:52 ` Petr Ovtchenkov
2017-10-10 14:21 ` [PATCH] libstdc++: istreambuf_iterator proxy (was: keep attached streambuf) Jonathan Wakely
2017-08-24 11:27 [PATCH] streambuf_iterator: avoid debug-dependent behaviour Petr Ovtchenkov
2017-08-29 20:02 ` François Dumont
2017-08-30 5:05 ` Petr Ovtchenkov
2017-08-31 20:30 ` François Dumont
2017-09-01 9:10 ` Jonathan Wakely
2017-09-07 21:02 ` François Dumont
2017-09-08 5:47 ` Petr Ovtchenkov
2017-09-08 6:15 ` François Dumont
2017-09-09 20:17 ` François Dumont
2017-09-21 5:46 ` François Dumont
2017-09-28 10:50 ` Jonathan Wakely
2017-09-28 10:58 ` Jonathan Wakely
2017-09-21 18:23 ` Petr Ovtchenkov
2017-09-25 9:34 ` Petr Ovtchenkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171003142023.GW4582@redhat.com \
--to=jwakely@redhat.com \
--cc=frs.dumont@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).