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] Fix libstdc++/9404 (and all that)


Hi!

Finally, here it is. I have incorporated Nathan's rewrote of
stringbuf::overflow and implemented his suggestion to let the
string grow according to his builtin exponential policy: the
first time that overflow is called the new capacity is
max(capacity + 1, _M_buf_size_opt), then we let the string grow
exponentially on its own, by requesting, essentially,
reserve(capacity + 1). This change led to some further improvements
wrt my previous post (in particular, now _M_buf_size is now unused
for stringbuf, since the information is readily available as
_M_string.capacity).

In a nutshell, I think we have implemented the bulk of Nathan's
outline explained here, for example:

http://gcc.gnu.org/ml/libstdc++/2003-02/msg00282.html

The TODO list includes:
1- Fixing the broken strstreams (this point makes me _really_ nervous).
2- Performance work (now that correctness is achieved ;)
3- Further clean-ups (_M_set_*determinate?, checks having dubious end
  limits)

I have tested the below (which now includes both filebuf and stringbuf
testcases), with reduced _M_buf_size_opt too in order to exercise more
heavily the overflow/reallocation scenarios: from 8192 to 16 for filebuf,
and from 512 to 4 for stringbuf. Everything on x86-linux, as usual.

Shall we put this in?

Thank,
Paolo.
2003-02-23  Paolo Carlini <pcarlini at unitus dot it>
	    Nathan Myers <ncm at cantrip dot org>

	PR libstdc++/9404
	(aka pptr == epptr implies overflow)
	* include/bits/fstream.tcc (_M_allocate_internal_buffer):
	Consistently, _M_out_end points to the end of the buffer just
	created.
	(overflow): Tweak to use _M_out_buf_size().
	(_M_convert_to_external): The role of the old _M_out_end is
	now played by _M_out_lim.
	(_M_really_overflow): Likewise.
	(seekoff): Likewise.
	(setbuf): _M_out_end points to the end of the external buffer.
	* include/bits/sstream.tcc (overflow): Rewrote, taking into
	account the resolution of DR 169 (TC).
	(seekoff): Use _M_string.capacity(); ios_base::end is now _M_out_lim.
	(seekpos): Use _M_string.capacity(); tweak.
	* include/bits/streambuf.tcc (sputc, xsputn): Remove comments.
	* include/std/std_fstream.h (sync): The role of the old
	_M_out_end is now played by _M_out_lim.
	(_M_set_indeterminate): Use _M_set_determinate.
	(_M_set_determinate): _M_out_end is now _M_out_lim.
	(_M_is_indeterminate): Likewise.
	* include/std/std_sstream.h (str()): _M_out_end is now _M_out_lim.
	(_M_stringbuf_init): Don't set _M_buf_size, unused for sstreams,
	which have the information readily available as _M_string.capacity();
	for ate and app modes, pass the string size to _M_really_sync.
	(_M_really_sync): Consistently set _M_out_end and _M_out_lim, to
	point to the end of the buffer (i.e., epptr) and to the string end,
	respectively.
	* include/std/std_streambuf.h: tweak comments, add _M_out_lim,
	which points to the right limit of the used put area.
	(_M_out_cur_move): The role of the old _M_out_end is now played
	by _M_out_lim.
	(_M_out_buf_size): Simplify: now (when _M_out_cur) return simply
	_M_out_end  - _M_out_cur (i.e., pptr), _very_ close to the letter
	of the standard.
	(basic_streambuf()): Initialize _M_out_lim too.
	* testsuite/27_io/filebuf_virtuals.cc (test10): Trivial tweak.
	* testsuite/27_io/filebuf_virtuals.cc (test11): Add.
 	* testsuite/27_io/stringbuf_virtuals.cc (test09): Add.
diff -prN libstdc++-v3-orig/include/bits/fstream.tcc libstdc++-v3/include/bits/fstream.tcc
*** libstdc++-v3-orig/include/bits/fstream.tcc	Sun Feb 16 20:02:52 2003
--- libstdc++-v3/include/bits/fstream.tcc	Sun Feb 23 00:09:01 2003
*************** namespace std
*** 48,55 ****
  	{
  	  this->_M_buf_size = this->_M_buf_size_opt;
  
! 	  // Allocate internal buffer.
! 	  this->_M_buf = new char_type[this->_M_buf_size]; 
  	  _M_buf_allocated = true;
  	}
      }
--- 48,57 ----
  	{
  	  this->_M_buf_size = this->_M_buf_size_opt;
  
! 	  // Allocate internal buffer...
! 	  this->_M_buf = new char_type[this->_M_buf_size];
! 	  // ... and consistently set the end of buffer pointer.
! 	  this->_M_out_end = this->_M_buf + this->_M_buf_size;
  	  _M_buf_allocated = true;
  	}
      }
*************** namespace std
*** 125,131 ****
  	{
  	  const int_type __eof = traits_type::eof();
  	  bool __testput = this->_M_out_cur
! 	    && this->_M_out_beg < this->_M_out_end;
  	  if (__testput 
  	      && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
  	    return __ret;
--- 127,133 ----
  	{
  	  const int_type __eof = traits_type::eof();
  	  bool __testput = this->_M_out_cur
! 	    && this->_M_out_beg < this->_M_out_lim;
  	  if (__testput 
  	      && traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
  	    return __ret;
*************** namespace std
*** 245,252 ****
      overflow(int_type __c)
      {
        int_type __ret = traits_type::eof();
!       bool __testput = this->_M_out_cur
! 	&& this->_M_out_cur < this->_M_buf + this->_M_buf_size;
        bool __testout = this->_M_mode & ios_base::out;
        
        if (__testout)
--- 247,253 ----
      overflow(int_type __c)
      {
        int_type __ret = traits_type::eof();
!       bool __testput = _M_out_buf_size();
        bool __testout = this->_M_mode & ios_base::out;
        
        if (__testout)
*************** namespace std
*** 314,320 ****
  	  if (__r == codecvt_base::partial)
  	    {
  	      const char_type* __iresume = __iend;
! 	      streamsize __rlen = this->_M_out_end - __iend;
  	      __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
  			      __iend, __buf, __buf + __blen, __bend);
  	      if (__r != codecvt_base::error)
--- 315,321 ----
  	  if (__r == codecvt_base::partial)
  	    {
  	      const char_type* __iresume = __iend;
! 	      streamsize __rlen = this->_M_out_lim - __iend;
  	      __r = __cvt.out(_M_state_cur, __iresume, __iresume + __rlen, 
  			      __iend, __buf, __buf + __blen, __bend);
  	      if (__r != codecvt_base::error)
*************** namespace std
*** 336,342 ****
      _M_really_overflow(int_type __c)
      {
        int_type __ret = traits_type::eof();
!       bool __testput = this->_M_out_cur && this->_M_out_beg < this->_M_out_end;
        bool __testunbuffered = _M_file.is_open() && !this->_M_buf_size_opt;
  
        if (__testput || __testunbuffered)
--- 337,343 ----
      _M_really_overflow(int_type __c)
      {
        int_type __ret = traits_type::eof();
!       bool __testput = this->_M_out_cur && this->_M_out_beg < this->_M_out_lim;
        bool __testunbuffered = _M_file.is_open() && !this->_M_buf_size_opt;
  
        if (__testput || __testunbuffered)
*************** namespace std
*** 358,364 ****
  	  // NB: In the unbuffered case, no internal buffer exists. 
  	  if (!__testunbuffered)
  	    _M_convert_to_external(this->_M_out_beg,
! 				   this->_M_out_end - this->_M_out_beg, 
  				   __elen, __plen);
  
  	  // Convert pending sequence to external representation, output.
--- 359,365 ----
  	  // NB: In the unbuffered case, no internal buffer exists. 
  	  if (!__testunbuffered)
  	    _M_convert_to_external(this->_M_out_beg,
! 				   this->_M_out_lim - this->_M_out_beg, 
  				   __elen, __plen);
  
  	  // Convert pending sequence to external representation, output.
*************** namespace std
*** 398,409 ****
--- 399,413 ----
  	  // that an external char_type array of length (__s + __n)
  	  // exists and has been pre-allocated. If this is not the
  	  // case, things will quickly blow up.
+ 
  	  // Step 1: Destroy the current internal array.
  	  _M_destroy_internal_buffer();
  	  
  	  // Step 2: Use the external array.
  	  this->_M_buf = __s;
  	  this->_M_buf_size_opt = this->_M_buf_size = __n;
+ 	  // Consistently set the end of buffer pointer.
+ 	  this->_M_out_end = this->_M_buf + this->_M_buf_size;
  	  _M_set_indeterminate();
  	}
        _M_last_overflowed = false;	
*************** namespace std
*** 437,443 ****
  	      bool __testget = this->_M_in_cur
  		&& this->_M_in_beg < this->_M_in_end;
  	      bool __testput = this->_M_out_cur
! 		&& this->_M_out_beg < this->_M_out_end;
  	      // Sync the internal and external streams.
  	      // out
  	      if (__testput || _M_last_overflowed)
--- 441,447 ----
  	      bool __testget = this->_M_in_cur
  		&& this->_M_in_beg < this->_M_in_end;
  	      bool __testput = this->_M_out_cur
! 		&& this->_M_out_beg < this->_M_out_lim;
  	      // Sync the internal and external streams.
  	      // out
  	      if (__testput || _M_last_overflowed)
diff -prN libstdc++-v3-orig/include/bits/sstream.tcc libstdc++-v3/include/bits/sstream.tcc
*** libstdc++-v3-orig/include/bits/sstream.tcc	Thu Feb 20 02:09:53 2003
--- libstdc++-v3/include/bits/sstream.tcc	Sat Feb 22 23:38:25 2003
*************** namespace std
*** 80,117 ****
      basic_stringbuf<_CharT, _Traits, _Alloc>::
      overflow(int_type __c)
      {
-       int_type __ret = traits_type::eof();
-       bool __testeof = traits_type::eq_int_type(__c, __ret);
-       bool __testwrite = this->_M_out_cur < this->_M_buf + this->_M_buf_size;
        bool __testout = this->_M_mode & ios_base::out;
  
        // Try to append __c into output sequence in one of two ways.
        // Order these tests done in is unspecified by the standard.
!       if (__testout)
  	{
! 	  if (!__testeof)
! 	    {
! 	      __size_type __len = std::max(this->_M_buf_size, 
! 					   this->_M_buf_size_opt);
! 	      __len *= 2;
! 
! 	      if (__testwrite)
! 		__ret = this->sputc(traits_type::to_char_type(__c));
! 	      else if (__len <= _M_string.max_size())
! 		{
! 		  // Force-allocate, re-sync.
! 		  _M_string = this->str();
! 		  _M_string.reserve(__len);
! 		  this->_M_buf_size = __len;
! 		  _M_really_sync(this->_M_in_cur - this->_M_in_beg, 
! 				 this->_M_out_cur - this->_M_out_beg);
! 		  __ret = this->sputc(traits_type::to_char_type(__c));
! 		}
! 	    }
! 	  else
! 	    __ret = traits_type::not_eof(__c);
  	}
!       return __ret;
      }
  
    template <class _CharT, class _Traits, class _Alloc>
--- 80,114 ----
      basic_stringbuf<_CharT, _Traits, _Alloc>::
      overflow(int_type __c)
      {
        bool __testout = this->_M_mode & ios_base::out;
+       if (__builtin_expect(!__testout, false))
+ 	return traits_type::eof();
+       bool __testeof = traits_type::eq_int_type(__c, traits_type::eof());
+       if (__builtin_expect(__testeof, false))
+ 	return traits_type::not_eof(__c);
+ 
+       // In virtue of DR 169 (TC) we are allowed to grow more than
+       // one char the first time and also...
+       __size_type __len =
+ 	std::max(_M_string.capacity() + 1, this->_M_buf_size_opt);
+ 
+       bool __testwrite = _M_out_buf_size();
+       if (__builtin_expect(!__testwrite && __len > _M_string.max_size(), false))
+ 	return traits_type::eof();
  
        // Try to append __c into output sequence in one of two ways.
        // Order these tests done in is unspecified by the standard.
!       if (!__testwrite)
  	{
! 	  // Force-allocate, re-sync.
! 	  _M_string = this->str();
! 	  // ... the next times. That's easy to implement thanks to the
! 	  // exponential growth policy builtin into basic_string.
! 	  _M_string.reserve(__len);
! 	  _M_really_sync(this->_M_in_cur - this->_M_in_beg, 
! 			 this->_M_out_cur - this->_M_out_beg);
  	}
!       return this->sputc(traits_type::to_char_type(__c));
      }
  
    template <class _CharT, class _Traits, class _Alloc>
*************** namespace std
*** 126,132 ****
        __testin &= !(__mode & ios_base::out);
        __testout &= !(__mode & ios_base::in);
  
!       if (this->_M_buf_size && (__testin || __testout || __testboth))
  	{
  	  char_type* __beg = this->_M_buf;
  	  char_type* __curi = NULL;
--- 123,129 ----
        __testin &= !(__mode & ios_base::out);
        __testout &= !(__mode & ios_base::in);
  
!       if (_M_string.capacity() && (__testin || __testout || __testboth))
  	{
  	  char_type* __beg = this->_M_buf;
  	  char_type* __curi = NULL;
*************** namespace std
*** 142,148 ****
  	  if (__testout || __testboth)
  	    {
  	      __curo = this->pptr();
! 	      __endo = this->epptr();
  	    }
  
  	  off_type __newoffi = 0;
--- 139,147 ----
  	  if (__testout || __testboth)
  	    {
  	      __curo = this->pptr();
! 	      // Due to the resolution of DR169, ios_base::end
! 	      // is this->_M_out_lim, not epptr().
! 	      __endo = this->_M_out_lim;
  	    }
  
  	  off_type __newoffi = 0;
*************** namespace std
*** 181,187 ****
      {
        pos_type __ret =  pos_type(off_type(-1)); 
        
!       if (this->_M_buf_size)
  	{
  	  off_type __pos = __sp; // Use streamoff operator to do conversion.
  	  char_type* __beg = NULL;
--- 180,186 ----
      {
        pos_type __ret =  pos_type(off_type(-1)); 
        
!       if (_M_string.capacity())
  	{
  	  off_type __pos = __sp; // Use streamoff operator to do conversion.
  	  char_type* __beg = NULL;
*************** namespace std
*** 205,211 ****
  	  if (__testout || __testboth)
  	    {
  	      __beg = this->pbase();
! 	      __end = this->_M_buf + this->_M_buf_size;
  	      if (0 <= __pos && __pos <= __end - __beg)
  		__testposo = true;
  	    }
--- 204,210 ----
  	  if (__testout || __testboth)
  	    {
  	      __beg = this->pbase();
! 	      __end = this->epptr();
  	      if (0 <= __pos && __pos <= __end - __beg)
  		__testposo = true;
  	    }
diff -prN libstdc++-v3-orig/include/bits/streambuf.tcc libstdc++-v3/include/bits/streambuf.tcc
*** libstdc++-v3-orig/include/bits/streambuf.tcc	Sun Feb 16 12:22:29 2003
--- libstdc++-v3/include/bits/streambuf.tcc	Sat Feb 22 21:16:20 2003
*************** namespace std 
*** 93,103 ****
        return __ret;
      }
  
-   // Don't test against _M_buf + _M_buf_size, because _M_buf reflects
-   // allocated space, and on certain (rare but entirely legal)
-   // situations, there will be no allocated space yet the internal
-   // buffers will still be valid. (This happens if setp is used to set
-   // the internal buffer to say some externally-allocated sequence.)
    template<typename _CharT, typename _Traits>
      typename basic_streambuf<_CharT, _Traits>::int_type
      basic_streambuf<_CharT, _Traits>::
--- 93,98 ----
*************** namespace std 
*** 149,159 ****
        return __ret;
      }
  
-   // Don't test against _M_buf + _M_buf_size, because _M_buf reflects
-   // allocated space, and on certain (rare but entirely legal)
-   // situations, there will be no allocated space yet the internal
-   // buffers will still be valid. (This happens if setp is used to set
-   // the internal buffer to say some externally-allocated sequence.)
    template<typename _CharT, typename _Traits>
      streamsize
      basic_streambuf<_CharT, _Traits>::
--- 144,149 ----
diff -prN libstdc++-v3-orig/include/std/std_fstream.h libstdc++-v3/include/std/std_fstream.h
*** libstdc++-v3-orig/include/std/std_fstream.h	Mon Feb 17 20:22:11 2003
--- libstdc++-v3/include/std/std_fstream.h	Sat Feb 22 17:16:49 2003
*************** namespace std
*** 312,325 ****
        sync()
        {
  	bool __testput = this->_M_out_cur
! 	  && this->_M_out_beg < this->_M_out_end;
  
  	// Make sure that the internal buffer resyncs its idea of
  	// the file position with the external file.
  	if (__testput)
  	  {
  	    // Need to restore current position after the write.
! 	    off_type __off = this->_M_out_cur - this->_M_out_end;
  	    _M_really_overflow(); // _M_file.sync() will be called within
  	    if (__off)
  	      _M_file.seekoff(__off, ios_base::cur);
--- 312,325 ----
        sync()
        {
  	bool __testput = this->_M_out_cur
! 	  && this->_M_out_beg < this->_M_out_lim;
  
  	// Make sure that the internal buffer resyncs its idea of
  	// the file position with the external file.
  	if (__testput)
  	  {
  	    // Need to restore current position after the write.
! 	    off_type __off = this->_M_out_cur - this->_M_out_lim;
  	    _M_really_overflow(); // _M_file.sync() will be called within
  	    if (__off)
  	      _M_file.seekoff(__off, ios_base::cur);
*************** namespace std
*** 387,397 ****
        void
        _M_set_indeterminate(void)
        {
! 	if (this->_M_mode & ios_base::in)
! 	  this->setg(this->_M_buf, this->_M_buf, this->_M_buf);
! 	if (this->_M_mode & ios_base::out)
! 	  this->setp(this->_M_buf, this->_M_buf);
! 	_M_filepos = this->_M_buf;
        }
  
        /**
--- 387,393 ----
        void
        _M_set_indeterminate(void)
        {
! 	_M_set_determinate(off_type(0));
        }
  
        /**
*************** namespace std
*** 405,413 ****
  	bool __testin = this->_M_mode & ios_base::in;
  	bool __testout = this->_M_mode & ios_base::out;
  	if (__testin)
! 	  this->setg(this->_M_buf, this->_M_buf, this->_M_buf + __off);
  	if (__testout)
! 	  this->setp(this->_M_buf, this->_M_buf + __off);
  	_M_filepos = this->_M_buf + __off;
        }
  
--- 401,415 ----
  	bool __testin = this->_M_mode & ios_base::in;
  	bool __testout = this->_M_mode & ios_base::out;
  	if (__testin)
! 	  {
! 	    this->_M_in_beg = this->_M_in_cur = this->_M_buf;
! 	    this->_M_in_end = this->_M_buf + __off;
! 	  }
  	if (__testout)
! 	  {
! 	    this->_M_out_beg = this->_M_out_cur = this->_M_buf;
! 	    this->_M_out_lim = this->_M_buf + __off;
! 	  }
  	_M_filepos = this->_M_buf + __off;
        }
  
*************** namespace std
*** 419,434 ****
        bool
        _M_is_indeterminate(void)
        { 
  	bool __ret = false;
  	// Don't return true if unbuffered.
  	if (this->_M_buf)
  	  {
! 	    if (this->_M_mode & ios_base::in)
  	      __ret = this->_M_in_beg == this->_M_in_cur
  		&& this->_M_in_cur == this->_M_in_end;
! 	    if (this->_M_mode & ios_base::out)
  	      __ret = this->_M_out_beg == this->_M_out_cur
! 		&& this->_M_out_cur == this->_M_out_end;
  	  }
  	return __ret;
        }
--- 421,438 ----
        bool
        _M_is_indeterminate(void)
        { 
+ 	bool __testin = this->_M_mode & ios_base::in;
+ 	bool __testout = this->_M_mode & ios_base::out;
  	bool __ret = false;
  	// Don't return true if unbuffered.
  	if (this->_M_buf)
  	  {
! 	    if (__testin)
  	      __ret = this->_M_in_beg == this->_M_in_cur
  		&& this->_M_in_cur == this->_M_in_end;
! 	    if (__testout)
  	      __ret = this->_M_out_beg == this->_M_out_cur
! 		&& this->_M_out_cur == this->_M_out_lim;
  	  }
  	return __ret;
        }
diff -prN libstdc++-v3-orig/include/std/std_sstream.h libstdc++-v3/include/std/std_sstream.h
*** libstdc++-v3-orig/include/std/std_sstream.h	Tue Feb 18 14:29:19 2003
--- libstdc++-v3/include/std/std_sstream.h	Sat Feb 22 23:44:11 2003
*************** namespace std
*** 140,147 ****
  	    // _M_string, and may not be the correct size of the
  	    // current stringbuf internal buffer.
  	    __size_type __len = _M_string.size();
! 	    if (this->_M_out_end > this->_M_out_beg)
! 	      __len = std::max(__size_type(this->_M_out_end 
  					   - this->_M_out_beg), __len);
  	    return __string_type(this->_M_out_beg, this->_M_out_beg + __len);
  	  }
--- 140,147 ----
  	    // _M_string, and may not be the correct size of the
  	    // current stringbuf internal buffer.
  	    __size_type __len = _M_string.size();
! 	    if (this->_M_out_lim > this->_M_out_beg)
! 	      __len = std::max(__size_type(this->_M_out_lim 
  					   - this->_M_out_beg), __len);
  	    return __string_type(this->_M_out_beg, this->_M_out_beg + __len);
  	  }
*************** namespace std
*** 174,186 ****
        void
        _M_stringbuf_init(ios_base::openmode __mode)
        {
- 	// _M_buf_size is a convenient alias for "what the streambuf
- 	// thinks the allocated size of the string really is." This is
- 	// necessary as ostringstreams are implemented with the
- 	// streambufs having control of the allocation and
- 	// re-allocation of the internal string object, _M_string.
- 	this->_M_buf_size = _M_string.size();
- 
  	// NB: Start ostringstream buffers at 512 bytes. This is an
  	// experimental value (pronounced "arbitrary" in some of the
  	// hipper english-speaking countries), and can be changed to
--- 174,179 ----
*************** namespace std
*** 188,194 ****
  	this->_M_buf_size_opt = 512;
  	this->_M_mode = __mode;
  	if (this->_M_mode & (ios_base::ate | ios_base::app))
! 	  _M_really_sync(0, this->_M_buf_size);
  	else
  	  _M_really_sync(0, 0);
        }
--- 181,187 ----
  	this->_M_buf_size_opt = 512;
  	this->_M_mode = __mode;
  	if (this->_M_mode & (ios_base::ate | ios_base::app))
! 	  _M_really_sync(0, _M_string.size());
  	else
  	  _M_really_sync(0, 0);
        }
*************** namespace std
*** 268,274 ****
  	    this->setg(__base, __base + __i, __base + __len);
  	if (__testout)
  	  {
! 	    this->setp(__base, __base + __len);
  	    this->_M_out_cur += __o;
  	  }
  	return 0;
--- 261,269 ----
  	    this->setg(__base, __base + __i, __base + __len);
  	if (__testout)
  	  {
! 	    this->setp(__base, __base + _M_string.capacity());
! 	    // _M_out_lim points to the string end.
! 	    this->_M_out_lim = __base + __len;
  	    this->_M_out_cur += __o;
  	  }
  	return 0;
diff -prN libstdc++-v3-orig/include/std/std_streambuf.h libstdc++-v3/include/std/std_streambuf.h
*** libstdc++-v3-orig/include/std/std_streambuf.h	Thu Jan 23 23:53:35 2003
--- libstdc++-v3/include/std/std_streambuf.h	Sat Feb 22 21:24:58 2003
*************** namespace std
*** 172,178 ****
  
        /**
         *  @if maint
!        *  Actual size of allocated internal buffer, in bytes.
         *  @endif
        */
        size_t			_M_buf_size;
--- 172,179 ----
  
        /**
         *  @if maint
!        *  Actual size of allocated internal buffer, in bytes. Unused
!        *  for sstreams, which have readily available _M_string.capacity().
         *  @endif
        */
        size_t			_M_buf_size;
*************** namespace std
*** 202,213 ****
         *  -  put == output == write
         *  @endif
        */
!       char_type* 		_M_in_beg;  	// Start of get area. 
!       char_type* 		_M_in_cur;	// Current read area. 
!       char_type* 		_M_in_end;	// End of get area. 
!       char_type* 		_M_out_beg; 	// Start of put area. 
!       char_type* 		_M_out_cur;  	// Current put area. 
!       char_type* 		_M_out_end;  	// End of put area. 
        //@}
  
        /**
--- 203,217 ----
         *  -  put == output == write
         *  @endif
        */
!       char_type* 		_M_in_beg;     // Start of get area. 
!       char_type* 		_M_in_cur;     // Current read area. 
!       char_type* 		_M_in_end;     // End of get area. 
!       char_type* 		_M_out_beg;    // Start of put area. 
!       char_type* 		_M_out_cur;    // Current put area. 
!       char_type* 		_M_out_end;    // End of put area.
! 
!       char_type*                _M_out_lim;    // Right limit of used put area.
! 
        //@}
  
        /**
*************** namespace std
*** 305,317 ****
        }
  
        // Correctly sets the _M_out_cur pointer, and bumps the
!       // appropriate _M_*_end pointers as well. Necessary for the
!       // un-tied stringbufs, in in|out mode.
        // Invariant:
!       // __n + _M_out_[cur, end] <= _M_buf + _M_buf_size
!       // Assuming all _M_*_[beg, cur, end] pointers are operating on
        // the same range:
!       // _M_buf <= _M_*_ <= _M_buf + _M_buf_size
        void 
        _M_out_cur_move(off_type __n) // argument needs to be +-
        {
--- 309,321 ----
        }
  
        // Correctly sets the _M_out_cur pointer, and bumps the
!       // appropriate _M_out_lim and _M_in_end pointers as well. Necessary
!       // for the un-tied stringbufs, in in|out mode.
        // Invariant:
!       // __n + _M_out_[cur, lim] <= _M_out_end
!       // Assuming all _M_out_[beg, cur, lim] pointers are operating on
        // the same range:
!       // _M_buf <= _M_*_ <= _M_out_end
        void 
        _M_out_cur_move(off_type __n) // argument needs to be +-
        {
*************** namespace std
*** 320,351 ****
  	_M_out_cur += __n;
  	if (__testin && _M_buf_unified)
  	  _M_in_cur += __n;
! 	if (_M_out_cur > _M_out_end)
  	  {
! 	    _M_out_end = _M_out_cur;
  	    // NB: in | out buffers drag the _M_in_end pointer along...
  	    if (__testin)
  	      _M_in_end += __n;
  	  }
        }
  
!       // Return the size of the output buffer.  This depends on the
!       // buffer in use: allocated buffers have a stored size in
!       // _M_buf_size and setbuf() buffers don't.
        off_type
        _M_out_buf_size()
        {
- 	off_type __ret = 0;
  	if (_M_out_cur)
! 	  {
! 	    // Using allocated buffer.
! 	    if (_M_out_beg == _M_buf)
! 	      __ret = _M_out_beg + _M_buf_size - _M_out_cur;
! 	    // Using non-allocated buffer.
! 	    else
! 	      __ret = _M_out_end - _M_out_cur;
! 	  }
! 	return __ret;
        }
  
    public:
--- 324,346 ----
  	_M_out_cur += __n;
  	if (__testin && _M_buf_unified)
  	  _M_in_cur += __n;
! 	if (_M_out_cur > _M_out_lim)
  	  {
! 	    _M_out_lim = _M_out_cur;
  	    // NB: in | out buffers drag the _M_in_end pointer along...
  	    if (__testin)
  	      _M_in_end += __n;
  	  }
        }
  
!       // Returns zero if the output buffer is full (-> overflow).
        off_type
        _M_out_buf_size()
        {
  	if (_M_out_cur)
! 	  return _M_out_end - _M_out_cur;
! 	else
! 	  return off_type(0);
        }
  
    public:
*************** namespace std
*** 568,575 ****
        */
        basic_streambuf()
        : _M_buf(NULL), _M_buf_size(0), _M_buf_size_opt(BUFSIZ), 
!       _M_buf_unified(false), _M_in_beg(0), _M_in_cur(0), _M_in_end(0), 
!       _M_out_beg(0), _M_out_cur(0), _M_out_end(0), 
        _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()), 
        _M_pback_cur_save(0), _M_pback_end_save(0), 
        _M_pback_init(false)
--- 563,570 ----
        */
        basic_streambuf()
        : _M_buf(NULL), _M_buf_size(0), _M_buf_size_opt(BUFSIZ), 
!       _M_buf_unified(false), _M_in_beg(0), _M_in_cur(0), _M_in_end(0),
!       _M_out_beg(0), _M_out_cur(0), _M_out_end(0), _M_out_lim(0),
        _M_mode(ios_base::openmode(0)), _M_buf_locale(locale()), 
        _M_pback_cur_save(0), _M_pback_end_save(0), 
        _M_pback_init(false)
*************** namespace std
*** 666,672 ****
        setp(char_type* __pbeg, char_type* __pend)
        { 
  	_M_out_beg = _M_out_cur = __pbeg; 
! 	_M_out_end = __pend; 
  	if (!(_M_mode & ios_base::out) && __pbeg && __pend)
  	  _M_mode = _M_mode | ios_base::out;
        }
--- 661,667 ----
        setp(char_type* __pbeg, char_type* __pend)
        { 
  	_M_out_beg = _M_out_cur = __pbeg; 
! 	_M_out_end = __pend;
  	if (!(_M_mode & ios_base::out) && __pbeg && __pend)
  	  _M_mode = _M_mode | ios_base::out;
        }
diff -prN libstdc++-v3-orig/testsuite/27_io/filebuf_virtuals.cc libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc
*** libstdc++-v3-orig/testsuite/27_io/filebuf_virtuals.cc	Sun Feb 16 20:09:11 2003
--- libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc	Sun Feb 23 10:51:03 2003
*************** const char carray_02[] = "memphis, new o
*** 71,77 ****
  const char name_01[] = "filebuf_virtuals-1.txt"; // file with data in it
  const char name_02[] = "filebuf_virtuals-2.txt"; // empty file, need to create
  const char name_03[] = "filebuf_virtuals-3.txt"; // empty file, need to create
! 
  
  class derived_filebuf: public std::filebuf
  {
--- 71,78 ----
  const char name_01[] = "filebuf_virtuals-1.txt"; // file with data in it
  const char name_02[] = "filebuf_virtuals-2.txt"; // empty file, need to create
  const char name_03[] = "filebuf_virtuals-3.txt"; // empty file, need to create
! const char name_04[] = "filebuf_virtuals-4.txt"; // empty file, need to create
! const char name_05[] = "filebuf_virtuals-5.txt"; // empty file, need to create
  
  class derived_filebuf: public std::filebuf
  {
*************** void test10()
*** 607,620 ****
    {
      ofstream out;
      out.imbue(loc);
!     out.open("filebuf_virtuals-4.txt");
      copy(str.begin(), str.end(),
  	 ostreambuf_iterator<char>(out));
    }
  
    {
      ifstream in;
!     in.open("filebuf_virtuals-4.txt");
      copy(istreambuf_iterator<char>(in),
  	 istreambuf_iterator<char>(),
  	 back_inserter(tmp));
--- 608,621 ----
    {
      ofstream out;
      out.imbue(loc);
!     out.open(name_04);
      copy(str.begin(), str.end(),
  	 ostreambuf_iterator<char>(out));
    }
  
    {
      ifstream in;
!     in.open(name_04);
      copy(istreambuf_iterator<char>(in),
  	 istreambuf_iterator<char>(),
  	 back_inserter(tmp));
*************** void test10()
*** 624,629 ****
--- 625,686 ----
    VERIFY( tmp == str );
  }
  
+ bool over_called;
+ 
+ class Derived_filebuf : public std::filebuf
+ {
+ public:
+   int_type overflow(int_type c)
+   {
+     over_called = true;
+     return std::filebuf::overflow(c);
+   }
+   
+   const char_type* pub_epptr() const
+   {
+     return epptr();
+   }
+   
+   const char_type* pub_pptr() const
+   {
+     return pptr();
+   }
+ };
+ 
+ // libstdc++/9404
+ void test11()
+ {
+   bool test = true;
+ 
+   bool over_expected;
+ 
+   // sputc
+   Derived_filebuf dfbuf_01;
+   dfbuf_01.open(name_05, std::ios_base::out);
+   over_called = false;
+   dfbuf_01.sputc('i');
+   VERIFY( !over_called );
+   over_expected = dfbuf_01.pub_epptr() == dfbuf_01.pub_pptr();
+   over_called = false;
+   dfbuf_01.sputc('v');
+   VERIFY( (!over_expected && !over_called)
+ 	  || (over_expected && over_called) );
+   dfbuf_01.close();
+ 
+   // sputn
+   Derived_filebuf dfbuf_02;
+   dfbuf_02.open(name_05, std::ios_base::out);
+   over_called = false;
+   dfbuf_02.sputn("sonne's", 7);
+   VERIFY( !over_called );
+   over_expected = dfbuf_02.pub_epptr() == dfbuf_02.pub_pptr();
+   over_called = false;
+   dfbuf_02.sputn(" peak", 5);
+   VERIFY( (!over_expected && !over_called)
+ 	  || (over_expected && over_called) );
+   dfbuf_02.close();
+ }
+ 
  main() 
  {
    test01();
*************** main() 
*** 638,642 ****
--- 695,700 ----
    test08();
    test09();
    test10();
+   test11();
    return 0;
  }
diff -prN libstdc++-v3-orig/testsuite/27_io/stringbuf_virtuals.cc libstdc++-v3/testsuite/27_io/stringbuf_virtuals.cc
*** libstdc++-v3-orig/testsuite/27_io/stringbuf_virtuals.cc	Thu Jan 23 23:53:35 2003
--- libstdc++-v3/testsuite/27_io/stringbuf_virtuals.cc	Sat Feb 22 22:01:53 2003
*************** void test08()
*** 92,97 ****
--- 92,152 ----
    VERIFY( ob.getloc() == loc_de );
  }
  
+ bool over_called;
+ 
+ class Derived_stringbuf : public std::stringbuf
+ {
+ public:
+   int_type overflow(int_type c)
+   {
+     over_called = true;
+     return std::stringbuf::overflow(c);
+   }
+   
+   const char_type* pub_epptr() const
+   {
+     return epptr();
+   }
+   
+   const char_type* pub_pptr() const
+   {
+     return pptr();
+   }
+ };
+ 
+ // libstdc++/9404
+ void test09()
+ {
+   bool test = true;
+ 
+   bool over_expected;
+ 
+   // sputc
+   Derived_stringbuf dsbuf_01;
+   over_called = false;
+   dsbuf_01.sputc('i');
+   VERIFY( over_called );
+   over_expected = dsbuf_01.pub_epptr() == dsbuf_01.pub_pptr();
+   over_called = false;
+   dsbuf_01.sputc('v');
+   VERIFY( (!over_expected && !over_called)
+ 	  || (over_expected && over_called) );
+   dsbuf_01.sputc('i');
+   VERIFY( dsbuf_01.str() == "ivi" ); // Sanity check.
+ 
+   // sputn
+   Derived_stringbuf dsbuf_02;
+   over_called = false;
+   dsbuf_02.sputn("sonne's", 7);
+   VERIFY( over_called );
+   over_expected = dsbuf_02.pub_epptr() == dsbuf_02.pub_pptr();
+   over_called = false;
+   dsbuf_02.sputn(" peak", 5);
+   VERIFY( (!over_expected && !over_called)
+ 	  || (over_expected && over_called) );
+   VERIFY( dsbuf_02.str() == "sonne's peak" ); // Sanity check.
+ }
+ 
  int main() 
  {
    using namespace std;
*************** int main() 
*** 106,110 ****
--- 161,166 ----
    test02(in3, false);
  
    test08();
+   test09();
    return 0;
  }

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