re PR libstdc++/4150 (catastrophic performance decrease in C++ code)
authorJason Merrill <jason@redhat.com>
Mon, 22 Apr 2002 20:28:05 +0000 (16:28 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 22 Apr 2002 20:28:05 +0000 (16:28 -0400)
        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

libstdc++-v3/ChangeLog
libstdc++-v3/config/os/bsd/freebsd/bits/os_defines.h
libstdc++-v3/config/os/mingw32/bits/os_defines.h
libstdc++-v3/config/os/solaris/solaris2.5/bits/os_defines.h
libstdc++-v3/config/os/solaris/solaris2.6/bits/os_defines.h
libstdc++-v3/config/os/solaris/solaris2.7/bits/os_defines.h
libstdc++-v3/include/bits/fstream.tcc
libstdc++-v3/include/std/std_fstream.h
libstdc++-v3/include/std/std_streambuf.h
libstdc++-v3/src/ios.cc
libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc

index 3ac23e5fcf224054b4a128769c4d6001170bacfd..61788e081c9485aaae86d3c52a35e45efb757557 100644 (file)
@@ -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.
index 9e6bbaf453d4b38302ea7540807bb294c126f0cf..cfc917f58731a0d713e0c8a004a0309c2947a393 100644 (file)
@@ -36,6 +36,4 @@
 
 #define __glibcpp_long_double_bits __glibcpp_double_bits
 
-#define _GLIBCPP_AVOID_FSEEK 1
-
 #endif
index eb4bb1c3b764c57ab9d985b1cbe8b045b25fee07..5c99e09428cb89e2389c55640d55d2e07d33657f 100644 (file)
@@ -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
index 0edc784c9e13d1fa3276d96d1f46af69cd57d8cb..145ae66bf95d22e04285726462fc62175dc36df3 100644 (file)
@@ -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
index 3acdf5c002a2011fad11fa61276befb67cfe4300..7aa9a7e8c62d95e0eaa247989034934c2fe2d906 100644 (file)
@@ -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
index a0fd24309ffe4ad0ed458e711bf9eb4565e75416..356c55c19544ee5b339c15e4e9ad108fdd1a41a5 100644 (file)
@@ -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
index fb2f87672acc43afeca587c8c47df282a24b99ed..235b4a83fd386859304f0ba972a5ef2f1bb9b369 100644 (file)
@@ -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();
index 4db259438aad88d4c02431fecec6c4a848326a47..c0d80da37c4c270ba0b79d69522b818a184921fe 100644 (file)
@@ -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() { return _M_underflow_common(false); }
+
       virtual int_type
-      underflow();
+      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;
+      }
     };
 
 
index 53e1e08b23193ac09335a51fe5fc00a3d09dd7ab..012bf4e6cf6bfe1e2f35e78f93d439c6e3b1bfcc 100644 (file)
@@ -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() 
index 0aab0a25a3a007d99282e3975a404ee35f376059..1d97bf9e7a8c1ed94c365366926b3f252bbcd57a 100644 (file)
@@ -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.
index 2609d26f237f6ba2794bb97b0a386a72df8abce9..fb370c36e50ea787567d96908b4522a15d02ea4d 100644 (file)
@@ -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 );