Skip to content

Commit 161d695

Browse files
committed
Issue #21377: PyBytes_Concat() now tries to concatenate in-place when the first argument has a reference count of 1.
Patch by Nikolaus Rath.
1 parent 991fd28 commit 161d695

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Release date: TBA
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #21377: PyBytes_Concat() now tries to concatenate in-place when the
14+
first argument has a reference count of 1. Patch by Nikolaus Rath.
15+
1316
- Issue #20355: -W command line options now have higher priority than the
1417
PYTHONWARNINGS environment variable. Patch by Arfrever.
1518

Objects/bytesobject.c

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,17 +2781,52 @@ PyTypeObject PyBytes_Type = {
27812781
void
27822782
PyBytes_Concat(PyObject **pv, PyObject *w)
27832783
{
2784-
PyObject *v;
27852784
assert(pv != NULL);
27862785
if (*pv == NULL)
27872786
return;
27882787
if (w == NULL) {
27892788
Py_CLEAR(*pv);
27902789
return;
27912790
}
2792-
v = bytes_concat(*pv, w);
2793-
Py_DECREF(*pv);
2794-
*pv = v;
2791+
2792+
if (Py_REFCNT(*pv) == 1 && PyBytes_CheckExact(*pv)) {
2793+
/* Only one reference, so we can resize in place */
2794+
size_t oldsize;
2795+
Py_buffer wb;
2796+
2797+
wb.len = -1;
2798+
if (_getbuffer(w, &wb) < 0) {
2799+
PyErr_Format(PyExc_TypeError, "can't concat %.100s to %.100s",
2800+
Py_TYPE(w)->tp_name, Py_TYPE(*pv)->tp_name);
2801+
Py_CLEAR(*pv);
2802+
return;
2803+
}
2804+
2805+
oldsize = PyBytes_GET_SIZE(*pv);
2806+
if (oldsize > PY_SSIZE_T_MAX - wb.len) {
2807+
PyErr_NoMemory();
2808+
goto error;
2809+
}
2810+
if (_PyBytes_Resize(pv, oldsize + wb.len) < 0)
2811+
goto error;
2812+
2813+
memcpy(PyBytes_AS_STRING(*pv) + oldsize, wb.buf, wb.len);
2814+
PyBuffer_Release(&wb);
2815+
return;
2816+
2817+
error:
2818+
PyBuffer_Release(&wb);
2819+
Py_CLEAR(*pv);
2820+
return;
2821+
}
2822+
2823+
else {
2824+
/* Multiple references, need to create new object */
2825+
PyObject *v;
2826+
v = bytes_concat(*pv, w);
2827+
Py_DECREF(*pv);
2828+
*pv = v;
2829+
}
27952830
}
27962831

27972832
void

0 commit comments

Comments
 (0)