[Python-checkins] cpython: PyUnicode_Append() now works in-place when it's possible

victor.stinner python-checkins at python.org
Mon Oct 3 04:02:36 CEST 2011


http://hg.python.org/cpython/rev/c346f879afbc
changeset:   72601:c346f879afbc
user:        Victor Stinner <victor.stinner at haypocalc.com>
date:        Mon Oct 03 03:54:37 2011 +0200
summary:
  PyUnicode_Append() now works in-place when it's possible

files:
  Objects/unicodeobject.c |  85 ++++++++++++++++++++++++----
  1 files changed, 73 insertions(+), 12 deletions(-)


diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -9775,19 +9775,80 @@
 }
 
 void
-PyUnicode_Append(PyObject **pleft, PyObject *right)
-{
-    PyObject *new;
-    if (*pleft == NULL)
+PyUnicode_Append(PyObject **p_left, PyObject *right)
+{
+    PyObject *left, *res;
+
+    if (p_left == NULL) {
+        if (!PyErr_Occurred())
+            PyErr_BadInternalCall();
         return;
-    if (right == NULL || !PyUnicode_Check(*pleft)) {
-        Py_DECREF(*pleft);
-        *pleft = NULL;
-        return;
-    }
-    new = PyUnicode_Concat(*pleft, right);
-    Py_DECREF(*pleft);
-    *pleft = new;
+    }
+    left = *p_left;
+    if (right == NULL || !PyUnicode_Check(left)) {
+        if (!PyErr_Occurred())
+            PyErr_BadInternalCall();
+        goto error;
+    }
+
+    if (PyUnicode_CheckExact(left) && left != unicode_empty
+        && PyUnicode_CheckExact(right) && right != unicode_empty
+        && unicode_resizable(left)
+        && (_PyUnicode_KIND(right) <= _PyUnicode_KIND(left)
+            || _PyUnicode_WSTR(left) != NULL))
+    {
+        Py_ssize_t u_len, v_len, new_len, copied;
+
+        /* FIXME: don't make wstr string ready */
+        if (PyUnicode_READY(left))
+            goto error;
+        if (PyUnicode_READY(right))
+            goto error;
+
+        /* FIXME: support ascii+latin1, PyASCIIObject => PyCompactUnicodeObject */
+        if (PyUnicode_MAX_CHAR_VALUE(right) <= PyUnicode_MAX_CHAR_VALUE(left))
+        {
+            u_len = PyUnicode_GET_LENGTH(left);
+            v_len = PyUnicode_GET_LENGTH(right);
+            if (u_len > PY_SSIZE_T_MAX - v_len) {
+                PyErr_SetString(PyExc_OverflowError,
+                                "strings are too large to concat");
+                goto error;
+            }
+            new_len = u_len + v_len;
+
+            /* Now we own the last reference to 'left', so we can resize it
+             * in-place.
+             */
+            if (unicode_resize(&left, new_len) != 0) {
+                /* XXX if _PyUnicode_Resize() fails, 'left' has been
+                 * deallocated so it cannot be put back into
+                 * 'variable'.  The MemoryError is raised when there
+                 * is no value in 'variable', which might (very
+                 * remotely) be a cause of incompatibilities.
+                 */
+                goto error;
+            }
+            /* copy 'right' into the newly allocated area of 'left' */
+            copied = PyUnicode_CopyCharacters(left, u_len,
+                                              right, 0,
+                                              v_len);
+            assert(0 <= copied);
+            *p_left = left;
+            return;
+        }
+    }
+
+    res = PyUnicode_Concat(left, right);
+    if (res == NULL)
+        goto error;
+    Py_DECREF(left);
+    *p_left = res;
+    return;
+
+error:
+    Py_DECREF(*p_left);
+    *p_left = NULL;
 }
 
 void

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list