mirror of
https://github.com/python/cpython.git
synced 2025-09-21 16:10:33 +00:00
A nice little speed-up for filter():
- Use PyObject_Call() instead of PyEval_CallObject(), saves several layers of calls and checks. - Pre-allocate the argument tuple rather than calling Py_BuildValue() each time round the loop. - For filter(None, seq), avoid an INCREF and a DECREF.
This commit is contained in:
parent
8e829200b1
commit
c7903a13d2
1 changed files with 17 additions and 13 deletions
|
@ -122,7 +122,7 @@ Note that classes are callable, as are instances with a __call__() method.");
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_filter(PyObject *self, PyObject *args)
|
builtin_filter(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *func, *seq, *result, *it;
|
PyObject *func, *seq, *result, *it, *arg;
|
||||||
int len; /* guess for result list size */
|
int len; /* guess for result list size */
|
||||||
register int j;
|
register int j;
|
||||||
|
|
||||||
|
@ -151,6 +151,11 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
len = 8; /* arbitrary */
|
len = 8; /* arbitrary */
|
||||||
|
|
||||||
|
/* Pre-allocate argument list tuple. */
|
||||||
|
arg = PyTuple_New(1);
|
||||||
|
if (arg == NULL)
|
||||||
|
goto Fail_arg;
|
||||||
|
|
||||||
/* Get a result list. */
|
/* Get a result list. */
|
||||||
if (PyList_Check(seq) && seq->ob_refcnt == 1) {
|
if (PyList_Check(seq) && seq->ob_refcnt == 1) {
|
||||||
/* Eww - can modify the list in-place. */
|
/* Eww - can modify the list in-place. */
|
||||||
|
@ -166,7 +171,7 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
/* Build the result list. */
|
/* Build the result list. */
|
||||||
j = 0;
|
j = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
PyObject *item, *good;
|
PyObject *item;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
item = PyIter_Next(it);
|
item = PyIter_Next(it);
|
||||||
|
@ -177,24 +182,20 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func == Py_None) {
|
if (func == Py_None) {
|
||||||
good = item;
|
ok = PyObject_IsTrue(item);
|
||||||
Py_INCREF(good);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *arg = Py_BuildValue("(O)", item);
|
PyObject *good;
|
||||||
if (arg == NULL) {
|
PyTuple_SET_ITEM(arg, 0, item);
|
||||||
Py_DECREF(item);
|
good = PyObject_Call(func, arg, NULL);
|
||||||
goto Fail_result_it;
|
PyTuple_SET_ITEM(arg, 0, NULL);
|
||||||
}
|
|
||||||
good = PyEval_CallObject(func, arg);
|
|
||||||
Py_DECREF(arg);
|
|
||||||
if (good == NULL) {
|
if (good == NULL) {
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
goto Fail_result_it;
|
goto Fail_result_it;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ok = PyObject_IsTrue(good);
|
ok = PyObject_IsTrue(good);
|
||||||
Py_DECREF(good);
|
Py_DECREF(good);
|
||||||
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
if (j < len)
|
if (j < len)
|
||||||
PyList_SET_ITEM(result, j, item);
|
PyList_SET_ITEM(result, j, item);
|
||||||
|
@ -216,12 +217,15 @@ builtin_filter(PyObject *self, PyObject *args)
|
||||||
goto Fail_result_it;
|
goto Fail_result_it;
|
||||||
|
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
Py_DECREF(arg);
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
Fail_result_it:
|
Fail_result_it:
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
Fail_it:
|
Fail_it:
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
Fail_arg:
|
||||||
|
Py_DECREF(arg);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue