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:
Guido van Rossum 2002-08-16 07:04:56 +00:00
parent 8e829200b1
commit c7903a13d2

View file

@ -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;
} }