From: Paolo Carlini Date: Thu, 15 May 2003 23:43:15 +0000 (+0200) Subject: fstream.tcc (_M_overflow): Rewrote to call _M_convert_to_external only once (_M_buf_s... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e3033a2240395246cdfce0197c39162e02c71995;p=gcc.git fstream.tcc (_M_overflow): Rewrote to call _M_convert_to_external only once (_M_buf_size is now the size... 2003-05-15 Paolo Carlini Nathan Myers * include/bits/fstream.tcc (_M_overflow): Rewrote to call _M_convert_to_external only once (_M_buf_size is now the size of the put area + 1 for the overflow char of a full area); call _M_set_buffer instead of _M_set_indeterminate. (setbuf): Don't accept a buffer smaller than 2 chars. (_M_underflow): Refill _M_buf_size - 1 chars; call _M_set_buffer, instead of _M_set_determinate. (open): Call _M_set_buffer, instead of _M_set_indeterminate. (seekoff): Likewise. * include/ext/stdio_filebuf.h (stdio_filebuf(int, std::ios_base::openmode, bool, size_t), stdio_filebuf(std::__c_file*, std::ios_base::openmode, size_t): Likewise. * include/std/std_fstream.h (_M_set_indeterminate): Remove. (_M_set_determinate): Rename as _M_set_buffer, _M_buf_size -> _M_buf_size - 1. * include/std/std_streambuf.h: Tweak _M_out_lim comment. * testsuite/27_io/basic_filebuf/sgetn/char/1.cc: Tweak, taking into account that, for _M_buf_size == BUFSIZ == 8192, the size of the put area is now BUFSIZ - 1. * testsuite/ext/stdio_filebuf_2.cc: Tweak, taking into account that now the smallest _M_buf_size is 2 (still fails, for the same reason, with 3.2.3) Co-Authored-By: Nathan Myers From-SVN: r66848 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d5cb45daecb..10ad1d6e012 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,30 @@ +2003-05-15 Paolo Carlini + Nathan Myers + + * include/bits/fstream.tcc (_M_overflow): Rewrote to call + _M_convert_to_external only once (_M_buf_size is now the size of + the put area + 1 for the overflow char of a full area); call + _M_set_buffer instead of _M_set_indeterminate. + (setbuf): Don't accept a buffer smaller than 2 chars. + (_M_underflow): Refill _M_buf_size - 1 chars; call _M_set_buffer, + instead of _M_set_determinate. + (open): Call _M_set_buffer, instead of _M_set_indeterminate. + (seekoff): Likewise. + * include/ext/stdio_filebuf.h (stdio_filebuf(int, + std::ios_base::openmode, bool, size_t), + stdio_filebuf(std::__c_file*, std::ios_base::openmode, size_t): + Likewise. + * include/std/std_fstream.h (_M_set_indeterminate): Remove. + (_M_set_determinate): Rename as _M_set_buffer, _M_buf_size -> + _M_buf_size - 1. + * include/std/std_streambuf.h: Tweak _M_out_lim comment. + * testsuite/27_io/basic_filebuf/sgetn/char/1.cc: Tweak, taking + into account that, for _M_buf_size == BUFSIZ == 8192, the size of + the put area is now BUFSIZ - 1. + * testsuite/ext/stdio_filebuf_2.cc: Tweak, taking into account + that now the smallest _M_buf_size is 2 (still fails, for the same + reason, with 3.2.3) + 2003-05-14 Loren J. Rittle * testsuite/thread/pthread4.cc: Tweak test. diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index 3397071bd84..4fb153ff724 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -48,7 +48,7 @@ namespace std basic_filebuf<_CharT, _Traits>:: _M_allocate_internal_buffer() { - if (!this->_M_buf && this->_M_buf_size) + if (!_M_buf_allocated && this->_M_buf_size) { // Allocate internal buffer. this->_M_buf = new char_type[this->_M_buf_size]; @@ -101,9 +101,9 @@ namespace std this->_M_mode = __mode; // Setup initial position of buffer. - _M_set_indeterminate(); + _M_set_buffer(0); - if ((__mode & ios_base::ate) + if ((__mode & ios_base::ate) && this->seekoff(0, ios_base::end, __mode) < 0) // 27.8.1.3,4 this->close(); @@ -218,27 +218,28 @@ namespace std ios_base::in); } - if (_M_buf_size) + if (_M_buf_size > 1) { streamsize __elen = 0; streamsize __ilen = 0; if (__check_facet(_M_codecvt).always_noconv()) { - __elen = _M_file.xsgetn(reinterpret_cast(this->_M_in_beg), _M_buf_size); + __elen = _M_file.xsgetn(reinterpret_cast(this->_M_in_beg), _M_buf_size - 1); __ilen = __elen; } else { - char* __buf = static_cast(__builtin_alloca(_M_buf_size)); - __elen = _M_file.xsgetn(__buf, _M_buf_size); + char* __buf = static_cast(__builtin_alloca(_M_buf_size - 1)); + __elen = _M_file.xsgetn(__buf, _M_buf_size - 1); const char* __eend; char_type* __iend; codecvt_base::result __r; __r = _M_codecvt->in(_M_state_cur, __buf, __buf + __elen, __eend, this->_M_in_beg, - this->_M_in_beg + _M_buf_size, __iend); + this->_M_in_beg + _M_buf_size - 1, + __iend); if (__r == codecvt_base::ok) __ilen = __iend - this->_M_in_beg; else if (__r == codecvt_base::noconv) @@ -258,7 +259,7 @@ namespace std if (0 < __ilen) { - _M_set_determinate(__ilen); + _M_set_buffer(__ilen); __ret = traits_type::to_int_type(*this->_M_in_cur); if (__bump) _M_move_in_cur(1); @@ -338,41 +339,30 @@ namespace std _M_overflow(int_type __c) { int_type __ret = traits_type::eof(); + const bool __testeof = traits_type::eq_int_type(__c, __ret); const bool __testput = this->_M_out_beg < this->_M_out_lim; if (__testput) - { - // Need to restore current position. The position of the external - // byte sequence (_M_file) corresponds to _M_filepos, and we need - // to move it to _M_out_beg for the write. - if (_M_filepos && _M_filepos != this->_M_out_beg) - { - off_type __off = this->_M_out_beg - _M_filepos; - _M_file.seekoff(__off, ios_base::cur); - } - - // Convert internal buffer to external representation, output. - if (_M_convert_to_external(this->_M_out_beg, - this->_M_out_lim - this->_M_out_beg)) + { + // Need to restore current position. The position of the + // external byte sequence (_M_file) corresponds to + // _M_filepos, and we need to move it to _M_out_beg for the + // write. + if (_M_filepos != this->_M_out_beg) + _M_file.seekoff(this->_M_out_beg - _M_filepos, ios_base::cur); + + // If appropriate, append the overflow char. + if (!__testeof) + *this->_M_out_lim++ = traits_type::to_char_type(__c); + + // Convert pending sequence to external representation, + // output. + if (_M_convert_to_external(this->_M_out_beg, + this->_M_out_lim - this->_M_out_beg) + && (!__testeof || (__testeof && !_M_file.sync()))) { - // Convert pending sequence to external representation, output. - // If eof, then just attempt sync. - if (!traits_type::eq_int_type(__c, traits_type::eof())) - { - // User code must flush when switching modes (thus - // don't sync). - char_type __pending = traits_type::to_char_type(__c); - if (_M_convert_to_external(&__pending, 1)) - { - _M_set_indeterminate(); - __ret = traits_type::not_eof(__c); - } - } - else if (!_M_file.sync()) - { - _M_set_indeterminate(); - __ret = traits_type::not_eof(__c); - } + _M_set_buffer(0); + __ret = traits_type::not_eof(__c); } } _M_last_overflowed = true; @@ -388,20 +378,22 @@ namespace std const bool __testput = this->_M_out_cur < this->_M_out_end; const bool __testout = this->_M_mode & ios_base::out; + // Perhaps set below in _M_overflow. + _M_last_overflowed = false; + if (__testout) { if (traits_type::eq_int_type(__c, traits_type::eof())) __ret = traits_type::not_eof(__c); else if (__testput) { - *this->_M_out_cur = traits_type::to_char_type(__c); + *this->_M_out_cur = traits_type::to_char_type(__c); _M_move_out_cur(1); __ret = traits_type::not_eof(__c); } else __ret = this->_M_overflow(__c); } - _M_last_overflowed = false; // Set in _M_overflow, below. return __ret; } @@ -479,12 +471,15 @@ namespace std { if (!this->is_open() && __s == 0 && __n == 0) this->_M_buf_size = 0; - else if (__s && __n) + else if (__s && __n > 1) { - // This is implementation-defined behavior, and assumes - // 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. + // This is implementation-defined behavior, and assumes 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. The length argument __n must + // be greater than 1 because __n - 1 positions will be used + // for the get and put areas, and 1 position is needed to + // host the overflow char of a full put area. // Step 1: Destroy the current internal array. _M_destroy_internal_buffer(); @@ -492,7 +487,7 @@ namespace std // Step 2: Use the external array. this->_M_buf = __s; this->_M_buf_size = __n; - _M_set_indeterminate(); + _M_set_buffer(0); } _M_last_overflowed = false; return this; @@ -539,7 +534,7 @@ namespace std // Return pos_type(off_type(-1)) in case of failure. __ret = _M_file.seekoff(__computed_off, __way, __mode); - _M_set_indeterminate(); + _M_set_buffer(0); } else { diff --git a/libstdc++-v3/include/ext/stdio_filebuf.h b/libstdc++-v3/include/ext/stdio_filebuf.h index 4d3c9d07eee..3f7cd1c69f5 100644 --- a/libstdc++-v3/include/ext/stdio_filebuf.h +++ b/libstdc++-v3/include/ext/stdio_filebuf.h @@ -67,19 +67,23 @@ namespace __gnu_cxx * @param mode Same meaning as in a standard filebuf. * @param del Whether to close the file on destruction. * @param size Optimal or preferred size of internal buffer, in bytes. + * Note that it includes a position for the overflow char, + * therefore, can't be smaller than 2. * * This constructor associates a file stream buffer with an open * POSIX file descriptor. Iff @a del is true, then the associated * file will be closed when the stdio_filebuf is closed/destroyed. */ stdio_filebuf(int __fd, std::ios_base::openmode __mode, bool __del, - size_t __size); + size_t __size = static_cast(BUFSIZ)); /** * @param f An open @c FILE*. * @param mode Same meaning as in a standard filebuf. * @param size Optimal or preferred size of internal buffer, in bytes. - * Defaults to system's @c BUFSIZ. + * Defaults to system's @c BUFSIZ. Note that it includes + * a position for the overflow char, therefore, can't be + * smaller than 2. * * This constructor associates a file stream buffer with an open * C @c FILE*. The @c FILE* will not be automatically closed when the @@ -123,7 +127,7 @@ namespace __gnu_cxx this->_M_mode = __mode; this->_M_buf_size = __size; _M_allocate_internal_buffer(); - _M_set_indeterminate(); + _M_set_buffer(0); } } @@ -138,7 +142,7 @@ namespace __gnu_cxx this->_M_mode = __mode; this->_M_buf_size = __size; _M_allocate_internal_buffer(); - _M_set_indeterminate(); + _M_set_buffer(0); } } } // namespace __gnu_cxx diff --git a/libstdc++-v3/include/std/std_fstream.h b/libstdc++-v3/include/std/std_fstream.h index 2ff4ec15d10..e99d8103286 100644 --- a/libstdc++-v3/include/std/std_fstream.h +++ b/libstdc++-v3/include/std/std_fstream.h @@ -123,7 +123,9 @@ namespace std /** * @if maint - * Actual size of internal buffer. + * Actual size of internal buffer. This number is equal to the size + * of the put area + 1 position, reserved for the overflow char of + * a full area. * @endif */ size_t _M_buf_size; @@ -452,41 +454,30 @@ namespace std void _M_output_unshift(); - // These two functions are used to clarify internal buffer - // maintenance. After an overflow, or after a seekoff call that - // started at beg or end, or possibly when the stream becomes - // unbuffered, and a myrid other obscure corner cases, the - // internal buffer does not truly reflect the contents of the - // external buffer. At this point, for whatever reason, it is in - // an indeterminate state. - /** - * @if maint - * @doctodo - * @endif - */ - void - _M_set_indeterminate(void) - { _M_set_determinate(off_type(0)); } - - /** - * @if maint - * @doctodo - * @endif - */ - void - _M_set_determinate(off_type __off) - { - const bool __testin = this->_M_mode & ios_base::in; - const 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 function sets the pointers of the internal buffer, both get + // and put areas. Typically, __off == _M_in_end - _M_in_beg upon + // _M_underflow; __off == 0 upon _M_overflow, seekoff, open, setbuf. + // + // NB: _M_out_end - _M_out_beg == _M_buf_size - 1, since _M_buf_size + // reflects the actual allocated memory and the last cell is reserved + // for the overflow char of a full put area. + void + _M_set_buffer(streamsize __off) + { + const bool __testin = this->_M_mode & ios_base::in; + const bool __testout = this->_M_mode & ios_base::out; + if (_M_buf_size) { - this->setp(this->_M_buf, this->_M_buf + this->_M_buf_size); - this->_M_out_lim += __off; + if (__testin) + this->setg(this->_M_buf, this->_M_buf, this->_M_buf + __off); + if (__testout) + { + this->setp(this->_M_buf, this->_M_buf + this->_M_buf_size - 1); + this->_M_out_lim += __off; + } + _M_filepos = this->_M_buf + __off; } - _M_filepos = this->_M_buf + __off; - } + } }; // [27.8.1.5] Template class basic_ifstream diff --git a/libstdc++-v3/include/std/std_streambuf.h b/libstdc++-v3/include/std/std_streambuf.h index e258501c18b..38aa6075f03 100644 --- a/libstdc++-v3/include/std/std_streambuf.h +++ b/libstdc++-v3/include/std/std_streambuf.h @@ -187,9 +187,9 @@ namespace std //@{ /** * @if maint - * _M_set_indeterminate and setp set it equal to _M_out_beg, then - * at each put operation it may be moved forward (toward _M_out_end) - * by _M_out_cur_move. + * setp (and _M_set_buffer(0) in basic_filebuf) set it equal to + * _M_out_beg, then at each put operation it may be moved + * forward (toward _M_out_end) by _M_out_cur_move. * @endif */ char_type* _M_out_lim; // End limit of used put area. diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/1.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/1.cc index 05fbd23a573..d890f3e7dcf 100644 --- a/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/1.cc +++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/1.cc @@ -123,11 +123,11 @@ void test05() VERIFY( c7 == c2 ); // n != i strmsz_1 = fb_03.sgetn(carray1, 10); VERIFY( !strmsz_1 ); //zero - strmsz_1 = fb_01.in_avail(); + strmsz_1 = fb_01.in_avail(); // N.B.: _M_in_end - _M_in_beg == BUFSIZ - 1 strmsz_2 = fb_01.sgetn(carray2, strmsz_1 + 5); VERIFY( strmsz_1 == strmsz_2 - 5 ); c4 = fb_01.sgetc(); // buffer should have underflowed from above. - VERIFY( c4 == 'i' ); + VERIFY( c4 == 'h' ); strmsz_1 = fb_01.in_avail(); VERIFY( strmsz_1 > 0 ); strmsz_2 = fb_01.sgetn(carray2, strmsz_1 + 5); diff --git a/libstdc++-v3/testsuite/ext/stdio_filebuf_2.cc b/libstdc++-v3/testsuite/ext/stdio_filebuf_2.cc index b4b30c65c93..a46f2399b42 100644 --- a/libstdc++-v3/testsuite/ext/stdio_filebuf_2.cc +++ b/libstdc++-v3/testsuite/ext/stdio_filebuf_2.cc @@ -29,7 +29,6 @@ // out by _M_really_overflow upon overflow. void test01() { - using namespace std; bool test = true; @@ -37,11 +36,10 @@ void test01() FILE* file = fopen(name, "w"); { using namespace __gnu_cxx; - - // One char big stack-based buffer. - stdio_filebuf sbuf(file, ios_base::out, 1); + stdio_filebuf sbuf(file, ios_base::out, 2); sbuf.sputc('T'); sbuf.sputc('S'); + sbuf.sputc('P'); } fclose(file); @@ -51,8 +49,8 @@ void test01() streamsize n = fbuf.sgetn(buf, sizeof(buf)); fbuf.close(); - VERIFY( n == 2 ); - VERIFY( !memcmp(buf, "TS", 2) ); + VERIFY( n == 3 ); + VERIFY( !memcmp(buf, "TSP", 3) ); } int main()