diff -r fccc4a5007e5 Lib/io.py --- a/Lib/io.py Wed May 07 04:48:42 2008 +0200 +++ b/Lib/io.py Thu May 08 03:58:58 2008 +0200 @@ -893,8 +893,12 @@ """ raw._checkReadable() _BufferedIOMixin.__init__(self, raw) + self.buffer_size = buffer_size + self._reset_read_buf() + + def _reset_read_buf(self): self._read_buf = b"" - self.buffer_size = buffer_size + self._read_pos = 0 def read(self, n=None): """Read n bytes. @@ -904,25 +908,43 @@ mode. If n is negative, read until EOF or until read() would block. """ + nodata_val = b"" + empty_values = (b"", None) + buf = self._read_buf + pos = self._read_pos if n is None: - n = -1 - nodata_val = b"" - while n < 0 or len(self._read_buf) < n: - to_read = max(self.buffer_size, - n if n is not None else 2*len(self._read_buf)) - current = self.raw.read(to_read) - if current in (b"", None): + self._reset_read_buf() + # Strip consumed bytes at the beginning when it is cheaper + l = [buf[pos:]] + current_size = 0 + while True: + current = self.raw.read( + max(self.buffer_size, 2 * current_size)) + if current in empty_values: + nodata_val = current + break + current_size += len(current) + l.append(current) + return b"".join(l) or nodata_val + # A length is specified + if n <= len(buf) - pos: + out = buf[pos:pos+n] + self._read_pos = pos + n + return out + l = [buf[pos:]] + avail = len(buf) - pos + while avail < n: + current = self.raw.read(max(self.buffer_size, n)) + if current in empty_values: nodata_val = current break - self._read_buf += current - if self._read_buf: - if n < 0: - n = len(self._read_buf) - out = self._read_buf[:n] - self._read_buf = self._read_buf[n:] - else: - out = nodata_val - return out + avail += len(current) + l.append(current) + n = min(n, avail) + buf = b"".join(l) + self._read_buf = buf[n:] + self._read_pos = 0 + return buf[:n] if buf else nodata_val def peek(self, n=0): """Returns buffered bytes without advancing the position. @@ -932,13 +954,14 @@ than self.buffer_size. """ want = min(n, self.buffer_size) - have = len(self._read_buf) + have = len(self._read_buf) - self._read_pos if have < want: to_read = self.buffer_size - have current = self.raw.read(to_read) if current: - self._read_buf += current - return self._read_buf + self._read_buf = current + self._read_pos = 0 + return self._read_buf[self._read_pos:] def read1(self, n): """Reads up to n bytes, with at most one read() system call.""" @@ -947,16 +970,16 @@ if n <= 0: return b"" self.peek(1) - return self.read(min(n, len(self._read_buf))) + return self.read(min(n, len(self._read_buf) - self._read_pos)) def tell(self): - return self.raw.tell() - len(self._read_buf) + return self.raw.tell() - len(self._read_buf) + self._read_pos def seek(self, pos, whence=0): if whence == 1: - pos -= len(self._read_buf) + pos -= len(self._read_buf) - self._read_pos pos = self.raw.seek(pos, whence) - self._read_buf = b"" + self._reset_read_buf() return pos @@ -1125,14 +1148,14 @@ # First do the raw seek, then empty the read buffer, so that # if the raw seek fails, we don't lose buffered data forever. pos = self.raw.seek(pos, whence) - self._read_buf = b"" + self._reset_read_buf() return pos def tell(self): - if (self._write_buf): + if self._write_buf: return self.raw.tell() + len(self._write_buf) else: - return self.raw.tell() - len(self._read_buf) + return BufferedReader.tell(self) def truncate(self, pos=None): if pos is None: @@ -1142,8 +1165,6 @@ return BufferedWriter.truncate(self) def read(self, n=None): - if n is None: - n = -1 self.flush() return BufferedReader.read(self, n) @@ -1161,8 +1182,9 @@ def write(self, b): if self._read_buf: - self.raw.seek(-len(self._read_buf), 1) # Undo readahead - self._read_buf = b"" + # Undo readahead + self.raw.seek(self._read_pos - len(self._read_buf), 1) + self._reset_read_buf() return BufferedWriter.write(self, b)