mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
bpo-47009: Streamline list.append for the common case (GH-31864)
This commit is contained in:
parent
f877b40e3f
commit
a0ea7a116c
4 changed files with 41 additions and 27 deletions
|
@ -37,6 +37,24 @@ struct _Py_list_state {
|
||||||
|
|
||||||
#define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item)
|
#define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item)
|
||||||
|
|
||||||
|
extern int
|
||||||
|
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem);
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_PyList_AppendTakeRef(PyListObject *self, PyObject *newitem)
|
||||||
|
{
|
||||||
|
assert(self != NULL && newitem != NULL);
|
||||||
|
assert(PyList_Check(self));
|
||||||
|
Py_ssize_t len = PyList_GET_SIZE(self);
|
||||||
|
Py_ssize_t allocated = self->allocated;
|
||||||
|
assert((size_t)len + 1 < PY_SSIZE_T_MAX);
|
||||||
|
if (allocated > len) {
|
||||||
|
PyList_SET_ITEM(self, len, newitem);
|
||||||
|
Py_SET_SIZE(self, len + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _PyList_AppendTakeRefListResize(self, newitem);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improved the performance of :meth:`list.append()` and list comprehensions by optimizing for the common case, where no resize is needed. Patch by Dennis Sweeney.
|
|
@ -301,26 +301,27 @@ PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
|
||||||
return ins1((PyListObject *)op, where, newitem);
|
return ins1((PyListObject *)op, where, newitem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/* internal, used by _PyList_AppendTakeRef */
|
||||||
app1(PyListObject *self, PyObject *v)
|
int
|
||||||
|
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
|
||||||
{
|
{
|
||||||
Py_ssize_t n = PyList_GET_SIZE(self);
|
Py_ssize_t len = PyList_GET_SIZE(self);
|
||||||
|
assert(self->allocated == -1 || self->allocated == len);
|
||||||
assert (v != NULL);
|
if (list_resize(self, len + 1) < 0) {
|
||||||
assert((size_t)n + 1 < PY_SSIZE_T_MAX);
|
Py_DECREF(newitem);
|
||||||
if (list_resize(self, n+1) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
Py_INCREF(v);
|
PyList_SET_ITEM(self, len, newitem);
|
||||||
PyList_SET_ITEM(self, n, v);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PyList_Append(PyObject *op, PyObject *newitem)
|
PyList_Append(PyObject *op, PyObject *newitem)
|
||||||
{
|
{
|
||||||
if (PyList_Check(op) && (newitem != NULL))
|
if (PyList_Check(op) && (newitem != NULL)) {
|
||||||
return app1((PyListObject *)op, newitem);
|
Py_INCREF(newitem);
|
||||||
|
return _PyList_AppendTakeRef((PyListObject *)op, newitem);
|
||||||
|
}
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -844,9 +845,10 @@ static PyObject *
|
||||||
list_append(PyListObject *self, PyObject *object)
|
list_append(PyListObject *self, PyObject *object)
|
||||||
/*[clinic end generated code: output=7c096003a29c0eae input=43a3fe48a7066e91]*/
|
/*[clinic end generated code: output=7c096003a29c0eae input=43a3fe48a7066e91]*/
|
||||||
{
|
{
|
||||||
if (app1(self, object) == 0)
|
if (_PyList_AppendTakeRef(self, Py_NewRef(object)) < 0) {
|
||||||
Py_RETURN_NONE;
|
return NULL;
|
||||||
return NULL;
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
|
@ -963,9 +965,7 @@ list_extend(PyListObject *self, PyObject *iterable)
|
||||||
Py_SET_SIZE(self, Py_SIZE(self) + 1);
|
Py_SET_SIZE(self, Py_SIZE(self) + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int status = app1(self, item);
|
if (_PyList_AppendTakeRef(self, item) < 0)
|
||||||
Py_DECREF(item); /* append creates a new ref */
|
|
||||||
if (status < 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2213,10 +2213,7 @@ handle_eval_breaker:
|
||||||
TARGET(LIST_APPEND) {
|
TARGET(LIST_APPEND) {
|
||||||
PyObject *v = POP();
|
PyObject *v = POP();
|
||||||
PyObject *list = PEEK(oparg);
|
PyObject *list = PEEK(oparg);
|
||||||
int err;
|
if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0)
|
||||||
err = PyList_Append(list, v);
|
|
||||||
Py_DECREF(v);
|
|
||||||
if (err != 0)
|
|
||||||
goto error;
|
goto error;
|
||||||
PREDICT(JUMP_BACKWARD_QUICK);
|
PREDICT(JUMP_BACKWARD_QUICK);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
@ -5044,14 +5041,12 @@ handle_eval_breaker:
|
||||||
DEOPT_IF(!PyList_Check(list), PRECALL);
|
DEOPT_IF(!PyList_Check(list), PRECALL);
|
||||||
STAT_INC(PRECALL, hit);
|
STAT_INC(PRECALL, hit);
|
||||||
SKIP_CALL();
|
SKIP_CALL();
|
||||||
PyObject *arg = TOP();
|
PyObject *arg = POP();
|
||||||
int err = PyList_Append(list, arg);
|
if (_PyList_AppendTakeRef((PyListObject *)list, arg) < 0) {
|
||||||
if (err) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
Py_DECREF(arg);
|
|
||||||
Py_DECREF(list);
|
Py_DECREF(list);
|
||||||
STACK_SHRINK(2);
|
STACK_SHRINK(1);
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
SET_TOP(Py_None);
|
SET_TOP(Py_None);
|
||||||
Py_DECREF(callable);
|
Py_DECREF(callable);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue