]> granicus.if.org Git - python/commitdiff
Issue #21377: PyBytes_Concat() now tries to concatenate in-place when the first argum...
authorAntoine Pitrou <solipsis@pitrou.net>
Thu, 1 May 2014 12:36:20 +0000 (14:36 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Thu, 1 May 2014 12:36:20 +0000 (14:36 +0200)
Patch by Nikolaus Rath.

Misc/NEWS
Objects/bytesobject.c

index 883a392850d9529b176e3533d43661122ce6671f..480f46a9fffd38f56f48c8de2dba468a589dd3e3 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index b93b9ef10d3f8d5bc5d39e02752205a34e44d4bc..b8bfd24e8ed296634e82342d3bb024ed041cf6ca 100644 (file)
@@ -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