Author: Brian Kearns <bdkea...@gmail.com>
Branch: use-file-star-for-file
Changeset: r73579:01b77e9f28ef
Date: 2014-09-17 11:55 -0400
http://bitbucket.org/pypy/pypy/changeset/01b77e9f28ef/

Log:    rewrite fgets loop more like cpython

diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -52,8 +52,6 @@
 BUFSIZ = config['BUFSIZ']
 EOF = config['EOF']
 
-BASE_LINE_SIZE = 100
-
 NEWLINE_UNKNOWN = 0
 NEWLINE_CR = 1
 NEWLINE_LF = 2
@@ -446,56 +444,66 @@
             rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
         return s.build()
 
-    def _get_line_fgets_single(self, raw_buf):
+    def _get_line_fgets(self):
         ll_file = self._ll_file
-        for i in range(BASE_LINE_SIZE):
-            raw_buf[i] = '\n'
 
-        result = c_fgets(raw_buf, BASE_LINE_SIZE, ll_file)
-        if not result:
-            c_clearerr(ll_file)
-            if self._signal_checker is not None:
-                self._signal_checker()
-            return 0
+        s = None
+        buffersize = 100
+        remainsize = buffersize
+        raw_buf, gc_buf = rffi.alloc_buffer(remainsize)
+        try:
+            while True:
+                for i in range(remainsize):
+                    raw_buf[i] = '\n'
 
-        # Assume that fgets() works as documented, and additionally
-        # never writes beyond the final \0, which the CPython
-        # fileobject.c says appears to be the case everywhere.
-        # The only case where the buffer was not big enough is the
-        # case where the buffer is full, ends with \0, and doesn't
-        # end with \n\0.
+                p = c_fgets(raw_buf, remainsize, ll_file)
+                if not p:
+                    c_clearerr(ll_file)
+                    if self._signal_checker is not None:
+                        self._signal_checker()
+                    p = 0
+                    break
 
-        p = 0
-        while raw_buf[p] != '\n':
-            p += 1
-            if p == BASE_LINE_SIZE:
-                # fgets read whole buffer without finding newline
-                return -1
-        # p points to first \n
+                # Assume that fgets() works as documented, and additionally
+                # never writes beyond the final \0, which the CPython
+                # fileobject.c says appears to be the case everywhere.
+                # The only case where the buffer was not big enough is the
+                # case where the buffer is full, ends with \0, and doesn't
+                # end with \n\0.
 
-        if p + 1 < BASE_LINE_SIZE and raw_buf[p + 1] == '\0':
-            # \n followed by \0, fgets read and found newline
-            return p + 1
-        else:
-            # \n not followed by \0, fgets read but didnt find newline
-            assert p > 0 and raw_buf[p - 1] == '\0'
-            return p - 1
+                p = 0
+                while raw_buf[p] != '\n':
+                    p += 1
+                    if p == remainsize:
+                        # fgets read whole buffer without finding newline
+                        p = -1
+                        break
 
-    def _get_line_fgets(self):
-        # XXX use buffer size logic from cpython
-        with rffi.scoped_alloc_buffer(BASE_LINE_SIZE) as buf:
-            c = self._get_line_fgets_single(buf.raw)
-            if c >= 0:
-                return buf.str(c)
+                if p != -1:
+                    # p points to first \n
+                    if p + 1 < remainsize and raw_buf[p + 1] == '\0':
+                        # \n followed by \0, fgets read and found newline
+                        p += 1
+                    else:
+                        # \n not followed by \0, fgets read but didnt find 
newline
+                        assert p > 0 and raw_buf[p - 1] == '\0'
+                        p -= 1
+                    break
 
-            # this is the rare case: the line is longer than BASE_LINE_SIZE
-            s = StringBuilder()
-            while True:
-                s.append_charpsize(buf.raw, BASE_LINE_SIZE - 1)
-                c = self._get_line_fgets_single(buf.raw)
-                if c >= 0:
-                    break
-            s.append_charpsize(buf.raw, c)
+                # fgets overwrote all the newlines (entire buffer)
+                assert raw_buf[remainsize - 1] == '\0'
+                if s is None:
+                    s = StringBuilder()
+                s.append_charpsize(raw_buf, remainsize - 1)
+                buffersize += buffersize >> 2
+                remainsize = buffersize - s.getlength()
+                rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
+                raw_buf, gc_buf = rffi.alloc_buffer(remainsize)
+            if s is None:
+                return rffi.str_from_buffer(raw_buf, gc_buf, remainsize, p)
+            s.append_charpsize(raw_buf, p)
+        finally:
+            rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
         return s.build()
 
     def _get_line_getc(self, raw_buf, remainsize, state):
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to