This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[FYI] Forward movement on 9404
- From: Paolo Carlini <pcarlini at unitus dot it>
- To: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Cc: Nathan Myers <ncm at cantrip dot org>
- Date: Sat, 22 Feb 2003 00:15:41 +0100
- Subject: [FYI] Forward movement on 9404
Hi,
in case someone would like to help on testing/adding comments and
what else, before taking a little bit of sleep I'm sending my current
best attempt at fixing 9404 in a clean way, i.e., implementing the
more general points of Nathan's outline for a post-DR169 asset.
I'm quite happy with it! Of course the regression tests are ok and
everything seems quite clean: overflow now happens _always_ when it
should (pptr == epptr) both for filestreams and stringstreams.
I would appreciate, in particular, some help on the legacy <strstream>
bits, which must be broken right now.
Ciao, Paolo
//////////
diff -urN libstdc++-v3-orig/include/bits/fstream.tcc libstdc++-v3/include/bits/fstream.tcc
--- libstdc++-v3-orig/include/bits/fstream.tcc 2003-02-16 20:02:52.000000000 +0100
+++ libstdc++-v3/include/bits/fstream.tcc 2003-02-21 21:45:11.000000000 +0100
@@ -49,7 +49,8 @@
this->_M_buf_size = this->_M_buf_size_opt;
// Allocate internal buffer.
- this->_M_buf = new char_type[this->_M_buf_size];
+ this->_M_buf = new char_type[this->_M_buf_size];
+ this->_M_out_end = this->_M_buf + this->_M_buf_size;
_M_buf_allocated = true;
}
}
@@ -125,7 +126,7 @@
{
const int_type __eof = traits_type::eof();
bool __testput = this->_M_out_cur
- && this->_M_out_beg < this->_M_out_end;
+ && this->_M_out_beg < this->_M_out_lim;
if (__testput
&& traits_type::eq_int_type(_M_really_overflow(__eof), __eof))
return __ret;
@@ -245,8 +246,7 @@
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 __testput = this->_M_out_cur && _M_out_buf_size();
bool __testout = this->_M_mode & ios_base::out;
if (__testout)
@@ -314,7 +314,7 @@
if (__r == codecvt_base::partial)
{
const char_type* __iresume = __iend;
- streamsize __rlen = this->_M_out_end - __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)
@@ -336,7 +336,7 @@
_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 __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)
@@ -358,7 +358,7 @@
// 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,
+ this->_M_out_lim - this->_M_out_beg,
__elen, __plen);
// Convert pending sequence to external representation, output.
@@ -404,6 +404,7 @@
// Step 2: Use the external array.
this->_M_buf = __s;
this->_M_buf_size_opt = this->_M_buf_size = __n;
+ this->_M_out_end = this->_M_buf + this->_M_buf_size;
_M_set_indeterminate();
}
_M_last_overflowed = false;
@@ -437,7 +438,7 @@
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;
+ && this->_M_out_beg < this->_M_out_lim;
// Sync the internal and external streams.
// out
if (__testput || _M_last_overflowed)
diff -urN libstdc++-v3-orig/include/bits/sstream.tcc libstdc++-v3/include/bits/sstream.tcc
--- libstdc++-v3-orig/include/bits/sstream.tcc 2003-02-20 02:09:53.000000000 +0100
+++ libstdc++-v3/include/bits/sstream.tcc 2003-02-21 23:53:26.000000000 +0100
@@ -82,7 +82,6 @@
{
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.
@@ -91,18 +90,20 @@
{
if (!__testeof)
{
+ // The following exponential grow policy can be adopted
+ // thanks to the resolution of DR 169 (TC).
__size_type __len = std::max(this->_M_buf_size,
this->_M_buf_size_opt);
__len *= 2;
- if (__testwrite)
+ if (_M_out_buf_size())
__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;
+ this->_M_buf_size = _M_string.capacity();
_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));
@@ -142,7 +143,7 @@
if (__testout || __testboth)
{
__curo = this->pptr();
- __endo = this->epptr();
+ __endo = this->_M_out_lim;
}
off_type __newoffi = 0;
@@ -205,7 +206,7 @@
if (__testout || __testboth)
{
__beg = this->pbase();
- __end = this->_M_buf + this->_M_buf_size;
+ __end = this->epptr();
if (0 <= __pos && __pos <= __end - __beg)
__testposo = true;
}
diff -urN libstdc++-v3-orig/include/std/std_fstream.h libstdc++-v3/include/std/std_fstream.h
--- libstdc++-v3-orig/include/std/std_fstream.h 2003-02-17 20:22:11.000000000 +0100
+++ libstdc++-v3/include/std/std_fstream.h 2003-02-21 23:40:11.000000000 +0100
@@ -312,14 +312,14 @@
sync()
{
bool __testput = this->_M_out_cur
- && this->_M_out_beg < this->_M_out_end;
+ && 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_end;
+ 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);
@@ -387,10 +387,15 @@
void
_M_set_indeterminate(void)
{
- if (this->_M_mode & ios_base::in)
+ 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);
- if (this->_M_mode & ios_base::out)
- this->setp(this->_M_buf, this->_M_buf);
+ if (__testout)
+ {
+ this->_M_out_beg = this->_M_out_cur = this->_M_buf;
+ this->_M_out_lim = this->_M_buf;
+ }
_M_filepos = this->_M_buf;
}
@@ -407,7 +412,10 @@
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);
+ {
+ 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;
}
@@ -428,7 +436,7 @@
&& 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;
+ && this->_M_out_cur == this->_M_out_lim;
}
return __ret;
}
diff -urN libstdc++-v3-orig/include/std/std_sstream.h libstdc++-v3/include/std/std_sstream.h
--- libstdc++-v3-orig/include/std/std_sstream.h 2003-02-18 14:29:19.000000000 +0100
+++ libstdc++-v3/include/std/std_sstream.h 2003-02-21 22:23:54.000000000 +0100
@@ -140,8 +140,8 @@
// _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
+ 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);
}
@@ -179,8 +179,8 @@
// 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();
-
+ this->_M_buf_size = _M_string.capacity();
+
// 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
@@ -188,7 +188,7 @@
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);
+ _M_really_sync(0, _M_string.size());
else
_M_really_sync(0, 0);
}
@@ -268,7 +268,8 @@
this->setg(__base, __base + __i, __base + __len);
if (__testout)
{
- this->setp(__base, __base + __len);
+ this->setp(__base, __base + this->_M_buf_size);
+ this->_M_out_lim = __base + __len;
this->_M_out_cur += __o;
}
return 0;
diff -urN libstdc++-v3-orig/include/std/std_streambuf.h libstdc++-v3/include/std/std_streambuf.h
--- libstdc++-v3-orig/include/std/std_streambuf.h 2003-01-23 23:53:35.000000000 +0100
+++ libstdc++-v3/include/std/std_streambuf.h 2003-02-21 23:51:12.000000000 +0100
@@ -207,7 +207,9 @@
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_end; // End of put area.
+
+ char_type* _M_out_lim; // Right limit of used put area.
//@}
/**
@@ -305,11 +307,11 @@
}
// 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.
+ // 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, end] <= _M_buf + _M_buf_size
- // Assuming all _M_*_[beg, cur, end] pointers are operating on
+ // __n + _M_out_[cur, lim] <= _M_buf + _M_buf_size
+ // Assuming all _M_out_[beg, cur, lim] pointers are operating on
// the same range:
// _M_buf <= _M_*_ <= _M_buf + _M_buf_size
void
@@ -320,32 +322,23 @@
_M_out_cur += __n;
if (__testin && _M_buf_unified)
_M_in_cur += __n;
- if (_M_out_cur > _M_out_end)
+ if (_M_out_cur > _M_out_lim)
{
- _M_out_end = _M_out_cur;
+ _M_out_lim = _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.
+ // Returns zero if the output buffer is full (-> overflow).
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;
+ return _M_out_end - _M_out_cur;
+ else
+ return off_type(0);
}
public:
@@ -569,7 +562,7 @@
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_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)
@@ -666,7 +659,7 @@
setp(char_type* __pbeg, char_type* __pend)
{
_M_out_beg = _M_out_cur = __pbeg;
- _M_out_end = __pend;
+ _M_out_end = __pend;
if (!(_M_mode & ios_base::out) && __pbeg && __pend)
_M_mode = _M_mode | ios_base::out;
}
diff -urN 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 2003-01-23 23:53:35.000000000 +0100
+++ libstdc++-v3/testsuite/27_io/stringbuf_virtuals.cc 2003-02-21 22:02:44.000000000 +0100
@@ -92,6 +92,45 @@
VERIFY( ob.getloc() == loc_de );
}
+bool called = false;
+
+class Derived_stringbuf : public std::stringbuf
+{
+public:
+ int_type overflow(int_type c)
+ {
+ 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;
+
+ Derived_stringbuf dsbuf;
+ dsbuf.sputc('s');
+ VERIFY( called );
+
+ called = false;
+ dsbuf.sputc('i');
+ VERIFY( !called );
+
+ dsbuf.sputc('l');
+ VERIFY( dsbuf.str() == "sil" );
+}
+
int main()
{
using namespace std;
@@ -106,5 +145,6 @@
test02(in3, false);
test08();
+ test09();
return 0;
}