From c7903a13d2dc58d2f239a4d3bb29703199b450e4 Mon Sep 17 00:00:00 2001
From: Guido van Rossum <guido@python.org>
Date: Fri, 16 Aug 2002 07:04:56 +0000
Subject: 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.
---
 Python/bltinmodule.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 83931d9..660abeb 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -122,7 +122,7 @@ Note that classes are callable, as are instances with a __call__() method.");
 static PyObject *
 builtin_filter(PyObject *self, PyObject *args)
 {
-	PyObject *func, *seq, *result, *it;
+	PyObject *func, *seq, *result, *it, *arg;
 	int len;   /* guess for result list size */
 	register int j;
 
@@ -151,6 +151,11 @@ builtin_filter(PyObject *self, PyObject *args)
 	if (len < 0)
 		len = 8;  /* arbitrary */
 
+	/* Pre-allocate argument list tuple. */
+	arg = PyTuple_New(1);
+	if (arg == NULL)
+		goto Fail_arg;
+
 	/* Get a result list. */
 	if (PyList_Check(seq) && seq->ob_refcnt == 1) {
 		/* Eww - can modify the list in-place. */
@@ -166,7 +171,7 @@ builtin_filter(PyObject *self, PyObject *args)
 	/* Build the result list. */
 	j = 0;
 	for (;;) {
-		PyObject *item, *good;
+		PyObject *item;
 		int ok;
 
 		item = PyIter_Next(it);
@@ -177,24 +182,20 @@ builtin_filter(PyObject *self, PyObject *args)
 		}
 
 		if (func == Py_None) {
-			good = item;
-			Py_INCREF(good);
+			ok = PyObject_IsTrue(item);
 		}
 		else {
-			PyObject *arg = Py_BuildValue("(O)", item);
-			if (arg == NULL) {
-				Py_DECREF(item);
-				goto Fail_result_it;
-			}
-			good = PyEval_CallObject(func, arg);
-			Py_DECREF(arg);
+			PyObject *good;
+			PyTuple_SET_ITEM(arg, 0, item);
+			good = PyObject_Call(func, arg, NULL);
+			PyTuple_SET_ITEM(arg, 0, NULL);
 			if (good == NULL) {
 				Py_DECREF(item);
 				goto Fail_result_it;
 			}
+			ok = PyObject_IsTrue(good);
+			Py_DECREF(good);
 		}
-		ok = PyObject_IsTrue(good);
-		Py_DECREF(good);
 		if (ok) {
 			if (j < len)
 				PyList_SET_ITEM(result, j, item);
@@ -216,12 +217,15 @@ builtin_filter(PyObject *self, PyObject *args)
 		goto Fail_result_it;
 
 	Py_DECREF(it);
+	Py_DECREF(arg);
 	return result;
 
 Fail_result_it:
 	Py_DECREF(result);
 Fail_it:
 	Py_DECREF(it);
+Fail_arg:
+	Py_DECREF(arg);
 	return NULL;
 }
 
-- 
cgit v0.12

