diff options
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/bytesobject.c | 43 |
2 files changed, 42 insertions, 4 deletions
@@ -10,6 +10,9 @@ Release date: TBA Core and Builtins ----------------- +- Issue #21377: PyBytes_Concat() now tries to concatenate in-place when the + first argument has a reference count of 1. Patch by Nikolaus Rath. + - Issue #20355: -W command line options now have higher priority than the PYTHONWARNINGS environment variable. Patch by Arfrever. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b93b9ef..b8bfd24 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2781,7 +2781,6 @@ PyTypeObject PyBytes_Type = { void PyBytes_Concat(PyObject **pv, PyObject *w) { - PyObject *v; assert(pv != NULL); if (*pv == NULL) return; @@ -2789,9 +2788,45 @@ PyBytes_Concat(PyObject **pv, PyObject *w) Py_CLEAR(*pv); return; } - v = bytes_concat(*pv, w); - Py_DECREF(*pv); - *pv = v; + + if (Py_REFCNT(*pv) == 1 && PyBytes_CheckExact(*pv)) { + /* Only one reference, so we can resize in place */ + size_t oldsize; + Py_buffer wb; + + wb.len = -1; + if (_getbuffer(w, &wb) < 0) { + PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s", + Py_TYPE(w)->tp_name, Py_TYPE(*pv)->tp_name); + Py_CLEAR(*pv); + return; + } + + oldsize = PyBytes_GET_SIZE(*pv); + if (oldsize > PY_SSIZE_T_MAX - wb.len) { + PyErr_NoMemory(); + goto error; + } + if (_PyBytes_Resize(pv, oldsize + wb.len) < 0) + goto error; + + memcpy(PyBytes_AS_STRING(*pv) + oldsize, wb.buf, wb.len); + PyBuffer_Release(&wb); + return; + + error: + PyBuffer_Release(&wb); + Py_CLEAR(*pv); + return; + } + + else { + /* Multiple references, need to create new object */ + PyObject *v; + v = bytes_concat(*pv, w); + Py_DECREF(*pv); + *pv = v; + } } void |