# HG changeset patch # Parent 2b79b4848f44ea7dfea85a7e9ae7f471483c7401 Make rawiobase_read() read directly to bytes object instead of copying. diff -r 2b79b4848f44 Lib/test/test_io.py --- a/Lib/test/test_io.py Thu Sep 13 17:27:15 2012 +0100 +++ b/Lib/test/test_io.py Mon Sep 17 21:13:33 2012 +0100 @@ -616,6 +616,7 @@ # readinto() internally). rawio = self.MockRawIOWithoutRead((b"abc", b"d", None, b"efg", None)) self.assertEqual(rawio.read(2), b"ab") + self.assertEqual(rawio.read(0), b"") self.assertEqual(rawio.read(2), b"c") self.assertEqual(rawio.read(2), b"d") self.assertEqual(rawio.read(2), None) @@ -623,6 +624,9 @@ self.assertEqual(rawio.read(2), b"g") self.assertEqual(rawio.read(2), None) self.assertEqual(rawio.read(2), b"") + rawio = self.MockRawIOWithoutRead((b"abc", b"d", b"efg")) + self.assertEqual(rawio.read(-1), b"abcdefg") + self.assertEqual(rawio.read(-1), b"") def test_types_have_dict(self): test = ( diff -r 2b79b4848f44 Modules/_io/iobase.c --- a/Modules/_io/iobase.c Thu Sep 13 17:27:15 2012 +0100 +++ b/Modules/_io/iobase.c Mon Sep 17 21:13:33 2012 +0100 @@ -781,8 +781,8 @@ static PyObject * rawiobase_read(PyObject *self, PyObject *args) { - Py_ssize_t n = -1; - PyObject *b, *res; + Py_ssize_t n = -1, view_refcount; + PyObject *b, *view, *res; if (!PyArg_ParseTuple(args, "|n:read", &n)) { return NULL; @@ -794,13 +794,19 @@ return _PyObject_CallMethodId(self, &PyId_readall, NULL); } - /* TODO: allocate a bytes object directly instead and manually construct - a writable memoryview pointing to it. */ - b = PyByteArray_FromStringAndSize(NULL, n); + b = PyBytes_FromStringAndSize(NULL, n); if (b == NULL) return NULL; - res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, b, NULL); + view = PyMemoryView_FromMemory(PyBytes_AS_STRING(b), n, PyBUF_WRITE); + if (view == NULL) { + Py_DECREF(b); + return NULL; + } + + res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, view, NULL); + view_refcount = Py_REFCNT(view); + Py_DECREF(view); if (res == NULL || res == Py_None) { Py_DECREF(b); return res; @@ -813,7 +819,21 @@ return NULL; } - res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n); + if (n == PyBytes_GET_SIZE(b)) + return b; + + if (n > PyBytes_GET_SIZE(b) || n < 0) { + Py_DECREF(b); + PyErr_SetString(PyExc_RuntimeError, "readinto() returned bad value"); + return NULL; + } + + if (view_refcount == 1 && Py_REFCNT(b) == 1) { + _PyBytes_Resize(&b, n); + return b; + } + + res = PyBytes_FromStringAndSize(PyBytes_AS_STRING(b), n); Py_DECREF(b); return res; }