This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch] Reimplement (and split) istream::ignore


Hi,

eventually I went ahead with the idea sketched some time ago. Similarly
to what other implementations are already doing, the mandated

ignore(streamsize __n = 1, int_type __delim = traits_type::eof())

can be profitably "split" into:

ignore()

ignore(streamsize __n)

ignore(streamsize __n, int_type __delim)

since this allows much simpler and better performing implementations of
the first two. Also, the last two can thus exploit the same mechanism
already used for istream::getline.

To give you some numbers, on x86-64-2GHz, "ignoring" 2400000 lines each
200 char long and '\n' terminated of a disk file takes:

current
-------
1.971u 0.347s 0:02.31 100.0%    0+0k 0+0io 0pf+0w

patched
-------
0.180u 0.381s 0:00.56 100.0%    0+0k 0+0io 0pf+0w

and this is the "worst" case, since the first two overloads are faster
than the general case.

Regtested x86/x86-64.

Paolo.

////////////////
2004-06-21  Paolo Carlini  <pcarlini@suse.de>

	* include/std/std_istream.h (ignore(streamsize __n = 1,
	int_type __delim = traits_type::eof())): Split into...
	(ignore(), ignore(streamsize __n), ignore(streamsize __n,
	int_type __delim)): The first two can be much more simpler
	and efficient than the fully general case; also, the last
	two can take advantage of the same mechanism already used
	for getline.
	* include/bits/istream.tcc (ignore(streamsize __n = 1,
	int_type __delim = traits_type::eof()): Remove.
	(ignore(), ignore(streamsize __n), ignore(streamsize __n,
	int_type __delim)): New.
diff -prN libstdc++-v3-orig/include/bits/istream.tcc libstdc++-v3/include/bits/istream.tcc
*** libstdc++-v3-orig/include/bits/istream.tcc	Thu Jun 10 21:54:59 2004
--- libstdc++-v3/include/bits/istream.tcc	Sun Jun 20 12:08:29 2004
*************** namespace std
*** 644,651 ****
--- 644,734 ----
    template<typename _CharT, typename _Traits>
      basic_istream<_CharT, _Traits>&
      basic_istream<_CharT, _Traits>::
+     ignore(void)
+     {
+       _M_gcount = 0;
+       sentry __cerb(*this, true);
+       if (__cerb)
+ 	{
+ 	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
+ 	  try
+ 	    {
+ 	      const int_type __eof = traits_type::eof();
+ 	      __streambuf_type* __sb = this->rdbuf();
+ 
+ 	      if (traits_type::eq_int_type(__sb->sbumpc(), __eof))
+ 		__err |= ios_base::eofbit;
+ 	      else
+ 		_M_gcount = 1;
+ 	    }
+ 	  catch(...)
+ 	    { this->_M_setstate(ios_base::badbit); }
+ 	  if (__err)
+ 	    this->setstate(__err);
+ 	}
+       return *this;
+     }
+ 
+   template<typename _CharT, typename _Traits>
+     basic_istream<_CharT, _Traits>&
+     basic_istream<_CharT, _Traits>::
+     ignore(streamsize __n)
+     {
+       if (__n == 1)
+ 	return ignore();
+       
+       _M_gcount = 0;
+       sentry __cerb(*this, true);
+       if (__cerb && __n > 0)
+ 	{
+ 	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
+ 	  try
+ 	    {
+ 	      const int_type __eof = traits_type::eof();
+ 	      __streambuf_type* __sb = this->rdbuf();
+ 	      int_type __c = __sb->sgetc();
+ 	      
+ 	      const bool __bound = __n != numeric_limits<streamsize>::max();
+ 	      if (__bound)
+ 		--__n;
+ 	      while (_M_gcount <= __n
+ 		     && !traits_type::eq_int_type(__c, __eof))
+ 		{
+ 		  streamsize __size = __sb->egptr() - __sb->gptr();
+ 		  if (__bound)
+ 		    __size = std::min(__size, __n - _M_gcount + 1);
+ 
+ 		  if (__size > 1)
+ 		    {
+ 		      __sb->gbump(__size);
+ 		      _M_gcount += __size;
+ 		      __c = __sb->sgetc();
+ 		    }
+ 		  else
+ 		    {
+ 		      ++_M_gcount;
+ 		      __c = __sb->snextc();
+ 		    }		  
+ 		}
+ 	      if (traits_type::eq_int_type(__c, __eof))
+ 		__err |= ios_base::eofbit;
+ 	    }
+ 	  catch(...)
+ 	    { this->_M_setstate(ios_base::badbit); }
+ 	  if (__err)
+ 	    this->setstate(__err);
+ 	}
+       return *this;
+     }
+ 
+   template<typename _CharT, typename _Traits>
+     basic_istream<_CharT, _Traits>&
+     basic_istream<_CharT, _Traits>::
      ignore(streamsize __n, int_type __delim)
      {
+       if (traits_type::eq_int_type(__delim, traits_type::eof()))
+ 	return ignore(__n);
+ 
        _M_gcount = 0;
        sentry __cerb(*this, true);
        if (__cerb && __n > 0)
*************** namespace std
*** 653,673 ****
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try
  	    {
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
! 	      int_type __c = __eof;
  
! 	      if (__n != numeric_limits<streamsize>::max())
  		--__n;
  	      while (_M_gcount <= __n
! 		     && !traits_type::eq_int_type(__c = __sb->sbumpc(), __eof))
  		{
! 		  ++_M_gcount;
! 		  if (traits_type::eq_int_type(__c, __delim))
! 		    break;
  		}
  	      if (traits_type::eq_int_type(__c, __eof))
  		__err |= ios_base::eofbit;
  	    }
  	  catch(...)
  	    { this->_M_setstate(ios_base::badbit); }
--- 736,781 ----
  	  ios_base::iostate __err = ios_base::iostate(ios_base::goodbit);
  	  try
  	    {
+ 	      const char_type __cdelim = traits_type::to_char_type(__delim);	      
  	      const int_type __eof = traits_type::eof();
  	      __streambuf_type* __sb = this->rdbuf();
! 	      int_type __c = __sb->sgetc();
  
! 	      const bool __bound = __n != numeric_limits<streamsize>::max();
! 	      if (__bound)
  		--__n;
  	      while (_M_gcount <= __n
! 		     && !traits_type::eq_int_type(__c, __eof)
! 		     && !traits_type::eq_int_type(__c, __delim))
  		{
! 		  streamsize __size = __sb->egptr() - __sb->gptr();
! 		  if (__bound)
! 		    __size = std::min(__size, __n - _M_gcount + 1);
! 
! 		  if (__size > 1)
! 		    {
! 		      const char_type* __p = traits_type::find(__sb->gptr(),
! 							       __size,
! 							       __cdelim);
! 		      if (__p)
! 			__size = __p - __sb->gptr();
! 		      __sb->gbump(__size);
! 		      _M_gcount += __size;
! 		      __c = __sb->sgetc();
! 		    }
! 		  else
! 		    {
! 		      ++_M_gcount;
! 		      __c = __sb->snextc();
! 		    }		  
  		}
  	      if (traits_type::eq_int_type(__c, __eof))
  		__err |= ios_base::eofbit;
+ 	      else if (traits_type::eq_int_type(__c, __delim))
+ 		{
+ 		  ++_M_gcount;
+ 		  __sb->sbumpc();
+ 		}
  	    }
  	  catch(...)
  	    { this->_M_setstate(ios_base::badbit); }
diff -prN libstdc++-v3-orig/include/std/std_istream.h libstdc++-v3/include/std/std_istream.h
*** libstdc++-v3-orig/include/std/std_istream.h	Wed Feb 11 13:08:22 2004
--- libstdc++-v3/include/std/std_istream.h	Sun Jun 20 16:47:36 2004
*************** namespace std
*** 412,420 ****
         *  - the next character equals @a delim (in this case, the character
         *    is extracted); note that this condition will never occur if
         *    @a delim equals @c traits::eof().
        */
        __istream_type& 
!       ignore(streamsize __n = 1, int_type __delim = traits_type::eof());
        
        /**
         *  @brief  Looking ahead in the stream
--- 412,430 ----
         *  - the next character equals @a delim (in this case, the character
         *    is extracted); note that this condition will never occur if
         *    @a delim equals @c traits::eof().
+        *
+        *  NB: Conformingly, we provide three overloads, instead of the single
+        *  function (with defaults) mandated by the Standard: this leads to a
+        *  better performing implementation.
        */
        __istream_type& 
!       ignore();
! 
!       __istream_type& 
!       ignore(streamsize __n);
! 
!       __istream_type& 
!       ignore(streamsize __n, int_type __delim);
        
        /**
         *  @brief  Looking ahead in the stream

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]