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