diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h index 32285a668fc..4527660e191 100644 --- a/libstdc++-v3/include/bits/streambuf_iterator.h +++ b/libstdc++-v3/include/bits/streambuf_iterator.h @@ -479,37 +479,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __glibcxx_assert(__n > 0); __glibcxx_requires_cond(!__i._M_at_eof(), - _M_message(__gnu_debug::__msg_inc_istreambuf) - ._M_iterator(__i)); + _M_message(__gnu_debug::__msg_advance_oob) + ._M_iterator(__i) + ._M_integer(__n)); typedef istreambuf_iterator<_CharT> __is_iterator_type; typedef typename __is_iterator_type::traits_type traits_type; typedef typename __is_iterator_type::streambuf_type streambuf_type; typedef typename traits_type::int_type int_type; + typedef typename traits_type::off_type off_type; + typedef typename streambuf_type::pos_type pos_type; const int_type __eof = traits_type::eof(); + const pos_type __npos = pos_type(off_type(-1)); streambuf_type* __sb = __i._M_sbuf; - while (__n > 0) - { streamsize __size = __sb->egptr() - __sb->gptr(); - if (__size > __n) - { + if (__size >= __n) __sb->__safe_gbump(__n); - break; - } - + else + { + // Check for seekoff support. + if (__sb->pubseekoff(0, ios_base::cur, ios_base::in) != __npos) + __sb->pubseekoff(__n, ios_base::cur, ios_base::in); + else + { + _GLIBCXX_DEBUG_ONLY(_Distance __n_orig = __n); + for (;;) + { __sb->__safe_gbump(__size); __n -= __size; + + if (__n == 0) + break; + if (traits_type::eq_int_type(__sb->underflow(), __eof)) { - __glibcxx_requires_cond(__n == 0, - _M_message(__gnu_debug::__msg_inc_istreambuf) - ._M_iterator(__i)); + __i._M_sbuf = 0; break; } + + __size = __sb->egptr() - __sb->gptr(); + if (__size > __n) + __size = __n; + } + + _GLIBCXX_DEBUG_ONLY(__n = __n_orig); + } } __i._M_c = __eof; + __glibcxx_requires_cond(!__i._M_at_eof(), + _M_message(__gnu_debug::__msg_advance_oob) + ._M_iterator(__i) + ._M_integer(__n)); } /// @} group iterators diff --git a/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/4_neg.cc b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/4_neg.cc new file mode 100644 index 00000000000..88ccaeff499 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/4_neg.cc @@ -0,0 +1,65 @@ +// { dg-require-fileio "" } +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include +#include +#include + +#include + +void test01() +{ + using namespace std; + + typedef istreambuf_iterator in_iterator_type; + + unsigned found = 0; + + { + ifstream fbuf("istream_unformatted-1.txt"); + + in_iterator_type beg(fbuf); + in_iterator_type end; + + for (;;) + { + beg = find(beg, end, '1'); + if (beg == end) + break; + + ++found; + VERIFY( *beg == '1' ); + + advance(beg, 9); + VERIFY( *beg == '0' ); + } + } + + { + ifstream fbuf("istream_unformatted-1.txt"); + + in_iterator_type beg(fbuf); + in_iterator_type end; + + beg = find(beg, end, '1'); + VERIFY( beg != end ); + VERIFY( *beg == '1' ); + + advance(beg, 9); + VERIFY( *beg == '0' ); + + unsigned line_length = 10; + while (*++beg != '1') + ++line_length; + + // Try to jump directly to the end + 1 through advance. + advance(beg, (found - 2) * line_length + 9 + 2); + } +} + +int main() +{ + test01(); + return 0; +}