Commit 3486a98d authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #9971: Write an optimized implementation of BufferedReader.readinto().

Patch by John O'Connor.
parent e9c7d6c3
...@@ -794,6 +794,12 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): ...@@ -794,6 +794,12 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
self.assertEqual(b, b"gf") self.assertEqual(b, b"gf")
self.assertEqual(bufio.readinto(b), 0) self.assertEqual(bufio.readinto(b), 0)
self.assertEqual(b, b"gf") self.assertEqual(b, b"gf")
rawio = self.MockRawIO((b"abc", None))
bufio = self.tp(rawio)
self.assertEqual(bufio.readinto(b), 2)
self.assertEqual(b, b"ab")
self.assertEqual(bufio.readinto(b), 1)
self.assertEqual(b, b"cb")
def test_readlines(self): def test_readlines(self):
def bufio(): def bufio():
......
...@@ -645,6 +645,7 @@ Neal Norwitz ...@@ -645,6 +645,7 @@ Neal Norwitz
Michal Nowikowski Michal Nowikowski
Steffen Daode Nurpmeso Steffen Daode Nurpmeso
Nigel O'Brian Nigel O'Brian
John O'Connor
Kevin O'Connor Kevin O'Connor
Tim O'Malley Tim O'Malley
Pascal Oberndoerfer Pascal Oberndoerfer
......
...@@ -142,6 +142,10 @@ Core and Builtins ...@@ -142,6 +142,10 @@ Core and Builtins
Library Library
------- -------
- Issue #9971: Write an optimized implementation of BufferedReader.readinto().
Patch by John O'Connor.
- Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError. - Issue #1028: Tk returns invalid Unicode null in %A: UnicodeDecodeError.
With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused
IDLE to exit. Converted to valid Unicode null in PythonCmd(). IDLE to exit. Converted to valid Unicode null in PythonCmd().
......
...@@ -596,7 +596,8 @@ static PyObject * ...@@ -596,7 +596,8 @@ static PyObject *
_bufferedreader_read_fast(buffered *self, Py_ssize_t); _bufferedreader_read_fast(buffered *self, Py_ssize_t);
static PyObject * static PyObject *
_bufferedreader_read_generic(buffered *self, Py_ssize_t); _bufferedreader_read_generic(buffered *self, Py_ssize_t);
static Py_ssize_t
_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len);
/* /*
* Helpers * Helpers
...@@ -912,23 +913,75 @@ end: ...@@ -912,23 +913,75 @@ end:
static PyObject * static PyObject *
buffered_readinto(buffered *self, PyObject *args) buffered_readinto(buffered *self, PyObject *args)
{ {
Py_buffer buf;
Py_ssize_t n, written = 0, remaining;
PyObject *res = NULL; PyObject *res = NULL;
CHECK_INITIALIZED(self) CHECK_INITIALIZED(self)
/* TODO: use raw.readinto() instead! */ if (!PyArg_ParseTuple(args, "w*:readinto", &buf))
if (self->writable) {
if (!ENTER_BUFFERED(self))
return NULL; return NULL;
n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
if (n > 0) {
if (n >= buf.len) {
memcpy(buf.buf, self->buffer + self->pos, buf.len);
self->pos += buf.len;
res = PyLong_FromSsize_t(buf.len);
goto end_unlocked;
}
memcpy(buf.buf, self->buffer + self->pos, n);
self->pos += n;
written = n;
}
if (!ENTER_BUFFERED(self))
goto end_unlocked;
if (self->writable) {
res = _bufferedwriter_flush_unlocked(self, 0); res = _bufferedwriter_flush_unlocked(self, 0);
LEAVE_BUFFERED(self)
if (res == NULL) if (res == NULL)
goto end; goto end;
Py_DECREF(res); Py_CLEAR(res);
}
_bufferedreader_reset_buf(self);
self->pos = 0;
for (remaining = buf.len - written;
remaining > 0;
written += n, remaining -= n) {
/* If remaining bytes is larger than internal buffer size, copy
* directly into caller's buffer. */
if (remaining > self->buffer_size) {
n = _bufferedreader_raw_read(self, buf.buf + written, remaining);
}
else {
n = _bufferedreader_fill_buffer(self);
if (n > 0) {
if (n > remaining)
n = remaining;
memcpy(buf.buf + written, self->buffer + self->pos, n);
self->pos += n;
continue; /* short circuit */
}
}
if (n == 0 || (n == -2 && written > 0))
break;
if (n < 0) {
if (n == -2) {
Py_INCREF(Py_None);
res = Py_None;
}
goto end;
} }
res = bufferediobase_readinto((PyObject *)self, args); }
res = PyLong_FromSsize_t(written);
end: end:
LEAVE_BUFFERED(self);
end_unlocked:
PyBuffer_Release(&buf);
return res; return res;
} }
...@@ -1573,6 +1626,7 @@ static PyMethodDef bufferedreader_methods[] = { ...@@ -1573,6 +1626,7 @@ static PyMethodDef bufferedreader_methods[] = {
{"read", (PyCFunction)buffered_read, METH_VARARGS}, {"read", (PyCFunction)buffered_read, METH_VARARGS},
{"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
{"read1", (PyCFunction)buffered_read1, METH_VARARGS}, {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
{"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
{"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
{"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
{"tell", (PyCFunction)buffered_tell, METH_NOARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment