https://github.com/python/cpython/commit/880696af1aff6f4170fbacdfb8aa73a84be73da5
commit: 880696af1aff6f4170fbacdfb8aa73a84be73da5
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-03T22:15:45Z
summary:
gh-158585: Use PyBytesWriter in io.BufferedReader.readline() (#158615)
Replace a list of bytes object with PyBytesWriter.
files:
M Modules/_io/bufferedio.c
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 2cc3774e75c9dad..d6318af1263d9c6 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1205,109 +1205,115 @@ _io__Buffered_readinto1_impl(buffered *self,
Py_buffer *buffer)
static PyObject *
_buffered_readline(buffered *self, Py_ssize_t limit)
{
- PyObject *res = NULL;
- PyObject *chunks = NULL;
- Py_ssize_t n;
- const char *start, *s, *end;
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self);
CHECK_CLOSED(self, "readline of closed file")
/* First, try to find a line in the buffer. This can run unlocked because
the calls to the C API are simple enough that they can't trigger
any thread switch. */
- n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
- if (limit >= 0 && n > limit)
+ Py_ssize_t n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
+ if (limit >= 0 && n > limit) {
n = limit;
- start = self->buffer + self->pos;
- s = memchr(start, '\n', n);
+ }
+ const char *start = self->buffer + self->pos;
+ const char *s = memchr(start, '\n', n);
if (s != NULL) {
- res = PyBytes_FromStringAndSize(start, s - start + 1);
- if (res != NULL)
- self->pos += s - start + 1;
- goto end_unlocked;
+ n = s - start + 1;
+ PyObject *res = PyBytes_FromStringAndSize(start, n);
+ if (res == NULL) {
+ return NULL;
+ }
+ self->pos += n;
+ return res;
}
+
if (n == limit) {
- res = PyBytes_FromStringAndSize(start, n);
- if (res != NULL)
- self->pos += n;
- goto end_unlocked;
+ PyObject *res = PyBytes_FromStringAndSize(start, n);
+ if (res == NULL) {
+ return NULL;
+ }
+ self->pos += n;
+ return res;
}
- if (!ENTER_BUFFERED(self))
- goto end_unlocked;
+ PyBytesWriter *writer = NULL;
+ int locked = 0;
+ if (!ENTER_BUFFERED(self)) {
+ goto error;
+ }
+ locked = 1;
/* Now we try to get some more from the raw stream */
- chunks = PyList_New(0);
- if (chunks == NULL)
- goto end;
+ writer = PyBytesWriter_Create(0);
+ if (writer == NULL) {
+ goto error;
+ }
+
if (n > 0) {
- res = PyBytes_FromStringAndSize(start, n);
- if (res == NULL)
- goto end;
- if (PyList_Append(chunks, res) < 0) {
- Py_CLEAR(res);
- goto end;
+ if (PyBytesWriter_WriteBytes(writer, start, n) < 0) {
+ goto error;
}
- Py_CLEAR(res);
self->pos += n;
- if (limit >= 0)
+ if (limit >= 0) {
limit -= n;
+ }
}
if (self->writable) {
- PyObject *r = buffered_flush_and_rewind_unlocked(self);
- if (r == NULL)
- goto end;
- Py_DECREF(r);
+ PyObject *res = buffered_flush_and_rewind_unlocked(self);
+ if (res == NULL) {
+ goto error;
+ }
+ Py_DECREF(res);
}
for (;;) {
_bufferedreader_reset_buf(self);
n = _bufferedreader_fill_buffer(self);
- if (n == -1)
- goto end;
- if (n <= 0)
+ if (n == -1) {
+ goto error;
+ }
+ if (n <= 0) {
break;
- if (limit >= 0 && n > limit)
+ }
+ if (limit >= 0 && n > limit) {
n = limit;
+ }
start = self->buffer;
- end = start + n;
+ const char *end = start + n;
s = start;
while (s < end) {
if (*s++ == '\n') {
- res = PyBytes_FromStringAndSize(start, s - start);
- if (res == NULL)
- goto end;
+ if (PyBytesWriter_WriteBytes(writer, start, s - start) < 0) {
+ goto error;
+ }
self->pos = s - start;
goto found;
}
}
- res = PyBytes_FromStringAndSize(start, n);
- if (res == NULL)
- goto end;
+
+ if (PyBytesWriter_WriteBytes(writer, start, n) < 0) {
+ goto error;
+ }
if (n == limit) {
self->pos = n;
break;
}
- if (PyList_Append(chunks, res) < 0) {
- Py_CLEAR(res);
- goto end;
- }
- Py_CLEAR(res);
- if (limit >= 0)
+ if (limit >= 0) {
limit -= n;
+ }
}
-found:
- if (res != NULL && PyList_Append(chunks, res) < 0) {
- Py_CLEAR(res);
- goto end;
- }
- Py_XSETREF(res, PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty),
chunks));
-end:
+found:
LEAVE_BUFFERED(self)
-end_unlocked:
- Py_XDECREF(chunks);
- return res;
+ return PyBytesWriter_Finish(writer);
+
+error:
+ PyBytesWriter_Discard(writer);
+ if (locked) {
+ LEAVE_BUFFERED(self)
+ }
+ return NULL;
}
/*[clinic input]
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]