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++/9424


Hi,

this is a fix along the lines suggested by Pétur: sgetn is
used only when a next sputn cannot possibly fail since the
corresponding _M_out_buf_size() is sufficiently large.
Otherwise, we fall back to an always correct
one-char-at-a-time loop.

Note that, in fact, in the former "fast" case, there is
an overhead due to the __builtin_alloca call which is not
present in the latter: it may be well possible that the
latter loop it's actually faster than the former
__builtin_alloca-sgetn-sputn sequence, when, say, less than
~10 chars have to be copied, and the condition could be
profitably changed from:

if (__size > 1)

to, say

if (__size > 10)

That's why I have not special cased the loop to a series of
a few (ugly) 'if' which would be in fact equivalent to it
when 'if (__size > 1)' is the condition.

Therefore, I plan to conduct some benchmarks...

Shall we commit the fix to the trunk? (tested x86-linux)

Paolo.

////////////
2003-02-27  Paolo Carlini <pcarlini at unitus dot it>
	    Petur Runolfsson  <peturr02 at ru dot is>

	PR libstdc++/9424
	* include/bits/streambuf.tcc (__copy_streambufs): Use
	sgetn-sputn only when sputn cannot fail, otherwise fall back
	to safe snextc-sputc.
	* testsuite/27_io/streambuf_members.cc (test11, test12): Add.
diff -urN libstdc++-v3-orig/include/bits/streambuf.tcc libstdc++-v3/include/bits/streambuf.tcc
--- libstdc++-v3-orig/include/bits/streambuf.tcc	2003-02-22 21:16:20.000000000 +0100
+++ libstdc++-v3/include/bits/streambuf.tcc	2003-02-27 15:14:48.000000000 +0100
@@ -193,6 +193,9 @@
       streamsize __ret = 0;
       streamsize __bufsize = __sbin->in_avail();
       streamsize __xtrct;
+      const typename _Traits::off_type __size_opt =
+	__sbin->_M_buf_size_opt > 0 ? __sbin->_M_buf_size_opt : 1;
+
       try 
 	{
 	  while (__bufsize != -1)
@@ -208,13 +211,36 @@
 		}
  	      else 
 		{
-		  size_t __size =
-		    __sbin->_M_buf_size_opt > 0 ? __sbin->_M_buf_size_opt : 1;
-		  _CharT* __buf =
-		    static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT) * __size));
-		  streamsize __charsread = __sbin->sgetn(__buf, __size);
-		  __xtrct = __sbout->sputn(__buf, __charsread);
-		  __ret += __xtrct;
+		  streamsize __charsread;
+		  const streamsize __size =
+		    std::min(__size_opt, __sbout->_M_out_buf_size());
+		  if (__size > 1)
+		    {
+		      _CharT* __buf =
+			static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
+							      * __size));
+		      // Since the next sputn cannot fail sgetn can be
+		      // safely used.
+		      __charsread = __sbin->sgetn(__buf, __size);
+		      __xtrct = __sbout->sputn(__buf, __charsread);
+		      __ret += __xtrct;
+		    }
+		  else
+		    {
+		      __xtrct = __charsread = 0;
+		      int_type __c = __sbin->sgetc();
+		      while (!_Traits::eq_int_type(__c, _Traits::eof()))
+			{
+			  ++__charsread;
+			  if (_Traits::eq_int_type(__sbout->sputc(_Traits::to_char_type(__c)),
+						   _Traits::eof()))
+			    break;
+			  ++__xtrct;
+			  ++__ret;
+			  __c = __sbin->snextc();
+			}
+		    }		      
+
 		  if (__xtrct != __charsread)
 		    break;
 		}
diff -urN libstdc++-v3-orig/testsuite/27_io/streambuf_members.cc libstdc++-v3/testsuite/27_io/streambuf_members.cc
--- libstdc++-v3-orig/testsuite/27_io/streambuf_members.cc	2003-02-11 10:59:19.000000000 +0100
+++ libstdc++-v3/testsuite/27_io/streambuf_members.cc	2003-02-27 15:16:56.000000000 +0100
@@ -431,6 +431,91 @@
   VERIFY( buf.result() == "Bad Moon Rising" );
 }
 
+// libstdc++/9424
+class Outbuf_2 : public std::streambuf
+{
+  char buf[1];
+
+public:
+  Outbuf_2()
+  {
+    setp(buf, buf + 1);
+  }
+
+  int_type overflow(int_type c)
+  {
+    int_type eof = traits_type::eof();
+    
+    if (pptr() < epptr())
+      {
+	if (traits_type::eq_int_type(c, eof))
+	  return traits_type::not_eof(c);
+	
+	*pptr() = traits_type::to_char_type(c);
+	pbump(1);
+	return c;
+      }
+
+    return eof;
+  }
+};
+
+class Inbuf_2 : public std::streambuf
+{
+  static const char buf[];
+  const char* current;
+  int size;
+
+public:
+  Inbuf_2()
+  {
+    current = buf;
+    size = std::strlen(buf);
+  }
+  
+  int_type underflow()
+  {
+    if (current < buf + size)
+      return traits_type::to_int_type(*current);
+    return traits_type::eof();
+  }
+  
+  int_type uflow()
+  {
+    if (current < buf + size)
+      return traits_type::to_int_type(*current++);
+    return traits_type::eof();
+  }
+};
+
+const char Inbuf_2::buf[] = "Atteivlis";
+
+// <1>
+void test11()
+{
+  bool test = true;
+
+  Inbuf_2 inbuf1;
+  std::istream is(&inbuf1);
+  Outbuf_2 outbuf1;
+  is >> &outbuf1;
+  VERIFY( inbuf1.sgetc() == 't' );
+  VERIFY( is.good() );
+}
+
+// <2>
+void test12()
+{ 
+  bool test = true;
+ 
+  Outbuf_2 outbuf2;
+  std::ostream os (&outbuf2);
+  Inbuf_2 inbuf2;
+  os << &inbuf2;
+  VERIFY( inbuf2.sgetc() == 't' );
+  VERIFY( os.good() );
+}
+
 int main() 
 {
   test01();
@@ -445,5 +530,7 @@
 
   test09();
   test10();
+  test11();
+  test12();
   return 0;
 }

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