mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-19 03:18:57 +08:00
re PR libstdc++/4150 (catastrophic performance decrease in C++ code)
PR libstdc++/4150 * include/std/std_streambuf.h (basic_streambuf::_M_set_indeterminate): Move to filebuf. (basic_streambuf::_M_set_determinate): Likewise. (basic_streambuf::_M_is_indeterminate): Likewise. * include/bits/std_fstream.h (basic_filebuf::_M_filepos): New non-static data member. (basic_filebuf::_M_underflow_common): New non-static member function. (basic_filebuf::_M_underflow, _M_uflow): Call it. (basic_filebuf::sync): Avoid useless seeking. (basic_filebuf::_M_set_indeterminate): Move here from streambuf. Set _M_filepos. (basic_filebuf::_M_set_determinate): Likewise. (basic_filebuf::_M_is_indeterminate): Likewise. * include/bits/fstream.tcc (basic_filebuf::_M_really_overflow): Seek back to _M_out_beg if necessary. (basic_filebuf::seekoff): Likewise. (basic_filebuf::_M_underflow_common): Generalization of old underflow(). Don't seek back to _M_in_beg. * src/ios.cc: Lose _GLIBCPP_AVOID_FSEEK stuff. * config/os/solaris/solaris2.?/bits/os_defines.h: Likewise. * config/os/bsd/freebsd/bits/os_defines.h: Likewise. * config/os/mingw32/bits/os_defines.h: Likewise. * testsuite/27_io/filebuf_virtuals.cc (test05): Don't overspecify ungetc test. From-SVN: r52634
This commit is contained in:
parent
f942d7a5df
commit
5066927d9e
@ -1,3 +1,31 @@
|
||||
2002-04-20 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR libstdc++/4150
|
||||
* include/std/std_streambuf.h (basic_streambuf::_M_set_indeterminate):
|
||||
Move to filebuf.
|
||||
(basic_streambuf::_M_set_determinate): Likewise.
|
||||
(basic_streambuf::_M_is_indeterminate): Likewise.
|
||||
* include/bits/std_fstream.h (basic_filebuf::_M_filepos): New
|
||||
non-static data member.
|
||||
(basic_filebuf::_M_underflow_common): New non-static member function.
|
||||
(basic_filebuf::_M_underflow, _M_uflow): Call it.
|
||||
(basic_filebuf::sync): Avoid useless seeking.
|
||||
(basic_filebuf::_M_set_indeterminate): Move here from streambuf.
|
||||
Set _M_filepos.
|
||||
(basic_filebuf::_M_set_determinate): Likewise.
|
||||
(basic_filebuf::_M_is_indeterminate): Likewise.
|
||||
* include/bits/fstream.tcc (basic_filebuf::_M_really_overflow): Seek
|
||||
back to _M_out_beg if necessary.
|
||||
(basic_filebuf::seekoff): Likewise.
|
||||
(basic_filebuf::_M_underflow_common): Generalization of old
|
||||
underflow(). Don't seek back to _M_in_beg.
|
||||
* src/ios.cc: Lose _GLIBCPP_AVOID_FSEEK stuff.
|
||||
* config/os/solaris/solaris2.?/bits/os_defines.h: Likewise.
|
||||
* config/os/bsd/freebsd/bits/os_defines.h: Likewise.
|
||||
* config/os/mingw32/bits/os_defines.h: Likewise.
|
||||
* testsuite/27_io/filebuf_virtuals.cc (test05): Don't overspecify
|
||||
ungetc test.
|
||||
|
||||
2002-04-22 Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
* include/bits/istream.tcc (istream::read): Fix.
|
||||
|
@ -36,6 +36,4 @@
|
||||
|
||||
#define __glibcpp_long_double_bits __glibcpp_double_bits
|
||||
|
||||
#define _GLIBCPP_AVOID_FSEEK 1
|
||||
|
||||
#endif
|
||||
|
@ -34,7 +34,4 @@
|
||||
// System-specific #define, typedefs, corrections, etc, go here. This
|
||||
// file will come before all others.
|
||||
|
||||
#define _GLIBCPP_AVOID_FSEEK 1
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -33,8 +33,6 @@
|
||||
// System-specific #define, typedefs, corrections, etc, go here. This
|
||||
// file will come before all others.
|
||||
|
||||
#define _GLIBCPP_AVOID_FSEEK 1
|
||||
|
||||
// These are typedefs which libio assumes are already in place (because
|
||||
// they really are, under Linux).
|
||||
#define __off_t off_t
|
||||
|
@ -33,8 +33,6 @@
|
||||
// System-specific #define, typedefs, corrections, etc, go here. This
|
||||
// file will come before all others.
|
||||
|
||||
#define _GLIBCPP_AVOID_FSEEK 1
|
||||
|
||||
// These are typedefs which libio assumes are already in place (because
|
||||
// they really are, under Linux).
|
||||
#define __off_t off_t
|
||||
|
@ -33,8 +33,6 @@
|
||||
// System-specific #define, typedefs, corrections, etc, go here. This
|
||||
// file will come before all others.
|
||||
|
||||
#define _GLIBCPP_AVOID_FSEEK 1
|
||||
|
||||
// These are typedefs which libio assumes are already in place (because
|
||||
// they really are, under Linux).
|
||||
#define __off_t off_t
|
||||
|
@ -206,7 +206,7 @@ namespace std
|
||||
template<typename _CharT, typename _Traits>
|
||||
typename basic_filebuf<_CharT, _Traits>::int_type
|
||||
basic_filebuf<_CharT, _Traits>::
|
||||
underflow()
|
||||
_M_underflow_common(bool __bump)
|
||||
{
|
||||
int_type __ret = traits_type::eof();
|
||||
bool __testin = _M_mode & ios_base::in;
|
||||
@ -232,12 +232,8 @@ namespace std
|
||||
{
|
||||
if (__testout)
|
||||
_M_really_overflow();
|
||||
#if _GLIBCPP_AVOID_FSEEK
|
||||
else if ((_M_in_cur - _M_in_beg) == 1)
|
||||
_M_file.sys_getc();
|
||||
#endif
|
||||
else
|
||||
_M_file.seekoff(_M_in_cur - _M_in_beg,
|
||||
else if (_M_in_cur != _M_filepos)
|
||||
_M_file.seekoff(_M_in_cur - _M_filepos,
|
||||
ios_base::cur, ios_base::in);
|
||||
}
|
||||
|
||||
@ -280,16 +276,16 @@ namespace std
|
||||
if (__testout)
|
||||
_M_out_cur = _M_in_cur;
|
||||
__ret = traits_type::to_int_type(*_M_in_cur);
|
||||
#if _GLIBCPP_AVOID_FSEEK
|
||||
if (__elen == 1)
|
||||
_M_file.sys_ungetc(*_M_in_cur);
|
||||
else
|
||||
if (__bump)
|
||||
_M_in_cur_move(1);
|
||||
else if (_M_buf_size == 1)
|
||||
{
|
||||
#endif
|
||||
_M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
|
||||
#if _GLIBCPP_AVOID_FSEEK
|
||||
// If we are synced with stdio, we have to unget the
|
||||
// character we just read so that the file pointer
|
||||
// doesn't move.
|
||||
_M_file.sys_ungetc(*_M_in_cur);
|
||||
_M_set_indeterminate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -464,6 +460,15 @@ namespace std
|
||||
streamsize __elen = 0;
|
||||
streamsize __plen = 0;
|
||||
|
||||
// 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 != _M_out_beg)
|
||||
{
|
||||
off_type __off = _M_out_beg - _M_filepos;
|
||||
_M_file.seekoff(__off, ios_base::cur);
|
||||
}
|
||||
|
||||
// Convert internal buffer to external representation, output.
|
||||
// NB: In the unbuffered case, no internal buffer exists.
|
||||
if (!__testunbuffered)
|
||||
@ -551,9 +556,8 @@ namespace std
|
||||
_M_output_unshift();
|
||||
}
|
||||
//in
|
||||
// NB: underflow() rewinds the external buffer.
|
||||
else if (__testget && __way == ios_base::cur)
|
||||
__computed_off += _M_in_cur - _M_in_beg;
|
||||
__computed_off += _M_in_cur - _M_filepos;
|
||||
|
||||
__ret = _M_file.seekoff(__computed_off, __way, __mode);
|
||||
_M_set_indeterminate();
|
||||
|
@ -93,6 +93,10 @@ namespace std
|
||||
// XXX Needed?
|
||||
bool _M_last_overflowed;
|
||||
|
||||
// The position in the buffer corresponding to the external file
|
||||
// pointer.
|
||||
char_type* _M_filepos;
|
||||
|
||||
public:
|
||||
// Constructors/destructor:
|
||||
basic_filebuf();
|
||||
@ -137,8 +141,21 @@ namespace std
|
||||
// underflow() and uflow() functions are called to get the next
|
||||
// charater from the real input source when the buffer is empty.
|
||||
// Buffered input uses underflow()
|
||||
|
||||
// The only difference between underflow() and uflow() is that the
|
||||
// latter bumps _M_in_cur after the read. In the sync_with_stdio
|
||||
// case, this is important, as we need to unget the read character in
|
||||
// the underflow() case in order to maintain synchronization. So
|
||||
// instead of calling underflow() from uflow(), we create a common
|
||||
// subroutine to do the real work.
|
||||
int_type
|
||||
_M_underflow_common(bool __bump);
|
||||
|
||||
virtual int_type
|
||||
underflow();
|
||||
underflow() { return _M_underflow_common(false); }
|
||||
|
||||
virtual int_type
|
||||
uflow() { return _M_underflow_common(true); }
|
||||
|
||||
virtual int_type
|
||||
pbackfail(int_type __c = _Traits::eof());
|
||||
@ -189,14 +206,11 @@ namespace std
|
||||
// the file position with the external file.
|
||||
if (__testput && !_M_file.sync())
|
||||
{
|
||||
// Need to restore current position. This interpreted as
|
||||
// the position of the external byte sequence (_M_file)
|
||||
// plus the offset in the current internal buffer
|
||||
// (_M_out_beg - _M_out_cur)
|
||||
streamoff __cur = _M_file.seekoff(0, ios_base::cur);
|
||||
off_type __off = _M_out_cur - _M_out_beg;
|
||||
// Need to restore current position after the write.
|
||||
off_type __off = _M_out_cur - _M_out_end;
|
||||
_M_really_overflow();
|
||||
_M_file.seekpos(__cur + __off);
|
||||
if (__off)
|
||||
_M_file.seekoff(__off, ios_base::cur);
|
||||
}
|
||||
_M_last_overflowed = false;
|
||||
return 0;
|
||||
@ -235,6 +249,50 @@ namespace std
|
||||
|
||||
void
|
||||
_M_output_unshift();
|
||||
|
||||
// These three 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.
|
||||
void
|
||||
_M_set_indeterminate(void)
|
||||
{
|
||||
if (_M_mode & ios_base::in)
|
||||
this->setg(_M_buf, _M_buf, _M_buf);
|
||||
if (_M_mode & ios_base::out)
|
||||
this->setp(_M_buf, _M_buf);
|
||||
_M_filepos = _M_in_end;
|
||||
}
|
||||
|
||||
void
|
||||
_M_set_determinate(off_type __off)
|
||||
{
|
||||
bool __testin = _M_mode & ios_base::in;
|
||||
bool __testout = _M_mode & ios_base::out;
|
||||
if (__testin)
|
||||
this->setg(_M_buf, _M_buf, _M_buf + __off);
|
||||
if (__testout)
|
||||
this->setp(_M_buf, _M_buf + __off);
|
||||
_M_filepos = _M_in_end;
|
||||
}
|
||||
|
||||
bool
|
||||
_M_is_indeterminate(void)
|
||||
{
|
||||
bool __ret = false;
|
||||
// Don't return true if unbuffered.
|
||||
if (_M_buf)
|
||||
{
|
||||
if (_M_mode & ios_base::in)
|
||||
__ret = _M_in_beg == _M_in_cur && _M_in_cur == _M_in_end;
|
||||
if (_M_mode & ios_base::out)
|
||||
__ret = _M_out_beg == _M_out_cur && _M_out_cur == _M_out_end;
|
||||
}
|
||||
return __ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -231,48 +231,6 @@ namespace std
|
||||
return __ret;
|
||||
}
|
||||
|
||||
// These three 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.
|
||||
void
|
||||
_M_set_indeterminate(void)
|
||||
{
|
||||
if (_M_mode & ios_base::in)
|
||||
this->setg(_M_buf, _M_buf, _M_buf);
|
||||
if (_M_mode & ios_base::out)
|
||||
this->setp(_M_buf, _M_buf);
|
||||
}
|
||||
|
||||
void
|
||||
_M_set_determinate(off_type __off)
|
||||
{
|
||||
bool __testin = _M_mode & ios_base::in;
|
||||
bool __testout = _M_mode & ios_base::out;
|
||||
if (__testin)
|
||||
this->setg(_M_buf, _M_buf, _M_buf + __off);
|
||||
if (__testout)
|
||||
this->setp(_M_buf, _M_buf + __off);
|
||||
}
|
||||
|
||||
bool
|
||||
_M_is_indeterminate(void)
|
||||
{
|
||||
bool __ret = false;
|
||||
// Don't return true if unbuffered.
|
||||
if (_M_buf)
|
||||
{
|
||||
if (_M_mode & ios_base::in)
|
||||
__ret = _M_in_beg == _M_in_cur && _M_in_cur == _M_in_end;
|
||||
if (_M_mode & ios_base::out)
|
||||
__ret = _M_out_beg == _M_out_cur && _M_out_cur == _M_out_end;
|
||||
}
|
||||
return __ret;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual
|
||||
~basic_streambuf()
|
||||
|
@ -150,14 +150,6 @@ namespace std
|
||||
int __out_bufsize = __sync ? 0 : static_cast<int>(BUFSIZ);
|
||||
int __in_bufsize = __sync ? 1 : static_cast<int>(BUFSIZ);
|
||||
|
||||
#if _GLIBCPP_AVOID_FSEEK
|
||||
// Platforms that prefer to avoid fseek() calls on streams only
|
||||
// get their desire when the C++-layer input buffer size is 1.
|
||||
// This hack hurts performance but keeps correctness across
|
||||
// all types of streams that might be attached to (e.g.) cin.
|
||||
__in_bufsize = 1;
|
||||
#endif
|
||||
|
||||
// NB: The file globals.cc creates the four standard files
|
||||
// with NULL buffers. At this point, we swap out the dummy NULL
|
||||
// [io]stream objects and buffers with the real deal.
|
||||
|
@ -444,6 +444,9 @@ void test05()
|
||||
strmsz_1 = fb_03.sputn("because because because. . .", 28);
|
||||
VERIFY( strmsz_1 == 28 );
|
||||
c1 = fb_03.sungetc();
|
||||
// Defect? retval of sungetc is not necessarily the character ungotten.
|
||||
// So re-get it.
|
||||
c1 = fb_03.sgetc();
|
||||
fb_03.pubsync();
|
||||
c3 = fb_03.sgetc();
|
||||
VERIFY( c1 == c3 );
|
||||
|
Loading…
Reference in New Issue
Block a user