[pypy-commit] pypy default: further optimize RStringIO by splitting write into fast/slow helper functions. the fast path is now truly as fast as StringBuilder alone.

bdkearns noreply at buildbot.pypy.org
Sat Mar 23 07:58:30 CET 2013


Author: Brian Kearns <bdkearns at gmail.com>
Branch: 
Changeset: r62689:e0174cd99015
Date: 2013-03-23 01:33 -0400
http://bitbucket.org/pypy/pypy/changeset/e0174cd99015/

Log:	further optimize RStringIO by splitting write into fast/slow helper
	functions. the fast path is now truly as fast as StringBuilder
	alone.

diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py
--- a/rpython/rlib/rStringIO.py
+++ b/rpython/rlib/rStringIO.py
@@ -58,41 +58,44 @@
         # Idea: for the common case of a sequence of write() followed
         # by only getvalue(), self.bigbuffer remains empty.  It is only
         # used to handle the more complicated cases.
-        p = self.pos
-        if p != AT_END:    # slow or semi-fast paths
-            assert p >= 0
-            endp = p + len(buffer)
-            if self.bigbuffer is not None and len(self.bigbuffer) >= endp:
-                # semi-fast path: the write is entirely inside self.bigbuffer
-                for i in range(len(buffer)):
-                    self.bigbuffer[p + i] = buffer[i]
-                self.pos = endp
-                return
-            else:
-                # slow path: collect all data into self.bigbuffer and
-                # handle the various cases
-                self.copy_into_bigbuffer()
-                fitting = len(self.bigbuffer) - p
-                if fitting > 0:
-                    # the write starts before the end of the data
-                    fitting = min(len(buffer), fitting)
-                    for i in range(fitting):
-                        self.bigbuffer[p+i] = buffer[i]
-                    if len(buffer) > fitting:
-                        # the write extends beyond the end of the data
-                        self.bigbuffer += buffer[fitting:]
-                        endp = AT_END
-                    self.pos = endp
-                    return
-                else:
-                    # the write starts at or beyond the end of the data
-                    self.bigbuffer += '\x00' * (-fitting)
-                    self.pos = AT_END      # fall-through to the fast path
-        # Fast path.
+        if self.pos == AT_END:
+            self._fast_write(buffer)
+        else:
+            self._slow_write(buffer)
+
+    def _fast_write(self, buffer):
         if self.strings is None:
             self.strings = StringBuilder()
         self.strings.append(buffer)
 
+    def _slow_write(self, buffer):
+        p = self.pos
+        assert p >= 0
+        endp = p + len(buffer)
+        if self.bigbuffer is not None and len(self.bigbuffer) >= endp:
+            # semi-fast path: the write is entirely inside self.bigbuffer
+            for i in range(len(buffer)):
+                self.bigbuffer[p + i] = buffer[i]
+        else:
+            # slow path: collect all data into self.bigbuffer and
+            # handle the various cases
+            self.copy_into_bigbuffer()
+            fitting = len(self.bigbuffer) - p
+            if fitting > 0:
+                # the write starts before the end of the data
+                fitting = min(len(buffer), fitting)
+                for i in range(fitting):
+                    self.bigbuffer[p + i] = buffer[i]
+                if len(buffer) > fitting:
+                    # the write extends beyond the end of the data
+                    self.bigbuffer += buffer[fitting:]
+                    endp = AT_END
+            else:
+                # the write starts at or beyond the end of the data
+                self.bigbuffer += '\x00' * (-fitting) + buffer
+                endp = AT_END
+        self.pos = endp
+
     def seek(self, position, mode=0):
         if mode == 1:
             if self.pos == AT_END:


More information about the pypy-commit mailing list