On 09/11/17 22:12 +0100, François Dumont wrote:
Hi

    Working on istreambuf_iterator I realized that this iterator would really benefit from an std::advance overload so here it is.


    Tested under Linux x86_64 normal and debug modes, ok to commit ?

François


diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h 
b/libstdc++-v3/include/bits/streambuf_iterator.h
index 0a6c7f9..b60626a 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -417,6 +421,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      return __last;
    }

+  template<typename _CharT, typename _Distance>
+    inline _GLIBCXX17_CONSTEXPR void

This function can never be constexpr.

+    advance(istreambuf_iterator<_CharT>& __i, _Distance __n)
+    {
+      if (__n == 0)
+       return;
+
+      __glibcxx_assert(__n > 0);
+      __glibcxx_requires_cond(!__i._M_at_eof(),
+                             _M_message(__gnu_debug::__msg_inc_istreambuf)
+                             ._M_iterator(__i));
+
+      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;
+      const int_type __eof = traits_type::eof();
+
+      streambuf_type* __sb = __i._M_sbuf;

This function relies on private members of istreambuf_iterator which
may not be present in a user-defined specialization of
istreambuf_iterator.

I think realistically you can only do this optimization for
istreambuf_iterator<char> and istreambuf_iterator<wchar_t>. Look at
how the std::copy and std::find overloads are contrained with
__is_char.

+      int_type __c = __sb->sgetc();
+      while (__n && !traits_type::eq_int_type(__c, __eof))

Can we use __n > 0 as the condition? Would it give better behaviour
for negative values in non-debug mode?

+       {
+         streamsize __size = __sb->egptr() - __sb->gptr();
+         if (__size > __n)
+           {
+             __sb->__safe_gbump(__n);
+             __n = 0;
+           }
+         else if (__size > 1)
+           {
+             __sb->__safe_gbump(__size);
+             __n -= __size;
+             __c = __sb->underflow();
+           }
+         else
+           {
+             --__n;
+             __c = __sb->snextc();
+           }

It seems like it should be possible to optimize this loop, but I don't
see an obvious way to improve it.

+       }
+
+      __glibcxx_requires_cond(__n == 0,
+                             _M_message(__gnu_debug::__msg_inc_istreambuf)
+                             ._M_iterator(__i));
+      __i._M_c = __eof;
+      if (traits_type::eq_int_type(__c, __eof))
+       __i._M_sbuf = 0;
+    }
+


diff --git 
a/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/1.cc
new file mode 100644
index 0000000..7c3f882
--- /dev/null
+++ 
b/libstdc++-v3/testsuite/25_algorithms/advance/istreambuf_iterators/char/1.cc

Thanks for the comprehensive tests, they look great.


Reply via email to