A patch to support L.count(value, cmp=None, key=None)
Ping
ping.nsr.yeh at gmail.com
Mon Jun 18 13:21:28 EDT 2007
Hi,
I patched Objects/listobject.c to support
L.count(value, cmp=None, key=None).
I tested it with the same script above by replacing slist
with built-in list. It worked correctly with this small
test. The patch is below (126 lines, I hope that's not
too big to be pasted here). This is the first time that
I modified CPython source, and I may very well make
mistakes in (lack of) reference counting or other things.
Comments and corrections are much appreciated!
Regards,
Ping
--- Objects/listobject.c.orig Sun Oct 29 05:39:10 2006
+++ Objects/listobject.c Tue Jun 19 01:04:30 2007
@@ -919,12 +919,12 @@
/* Comparison function. Takes care of calling a user-supplied
* comparison function (any callable Python object), which must not
be
- * NULL (use the ISLT macro if you don't know, or call
PyObject_RichCompareBool
- * with Py_LT if you know it's NULL).
- * Returns -1 on error, 1 if x < y, 0 if x >= y.
+ * NULL.
+ * Returns -9 on error, otherwise return the result of the user-
supplied
+ * comparison.
*/
static int
-islt(PyObject *x, PyObject *y, PyObject *compare)
+custom_compare(PyObject *x, PyObject *y, PyObject *compare)
{
PyObject *res;
PyObject *args;
@@ -936,7 +936,7 @@
*/
args = PyTuple_New(2);
if (args == NULL)
- return -1;
+ return -9;
Py_INCREF(x);
Py_INCREF(y);
PyTuple_SET_ITEM(args, 0, x);
@@ -944,16 +944,28 @@
res = PyObject_Call(compare, args, NULL);
Py_DECREF(args);
if (res == NULL)
- return -1;
+ return -9;
if (!PyInt_Check(res)) {
Py_DECREF(res);
PyErr_SetString(PyExc_TypeError,
"comparison function must return
int");
- return -1;
+ return -9;
}
i = PyInt_AsLong(res);
Py_DECREF(res);
- return i < 0;
+ return i;
+}
+
+/* "less-than" Comparison function. Calls custom_compare to do the
+ * actual comparison.
+ * Returns -1 on error, 1 if x < y, 0 if x >= y.
+ */
+static int
+islt(PyObject *x, PyObject *y, PyObject *compare)
+{
+ int res = custom_compare(x, y, compare);
+ if (res == -9) return -1;
+ return res < 0;
}
/* If COMPARE is NULL, calls PyObject_RichCompareBool with Py_LT,
else calls
@@ -2232,16 +2244,44 @@
}
static PyObject *
-listcount(PyListObject *self, PyObject *v)
+listcount(PyListObject *self, PyObject * args, PyObject *kwds)
{
+ PyObject *v = NULL; /* value for counting */
+ PyObject *compare = NULL;
+ PyObject *keyfunc = NULL;
+ static char *kwlist[] = {"value", "cmp", "key", 0};
+ PyObject *item;
Py_ssize_t count = 0;
Py_ssize_t i;
+ int cmp;
+
+ assert(self != NULL);
+ assert (PyList_Check(self));
+ if (args != NULL) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|
OO:count",
+ kwlist, &v, &compare, &keyfunc))
+ return NULL;
+ }
+ if (compare == Py_None)
+ compare = NULL;
+ if (keyfunc == Py_None)
+ keyfunc = NULL;
for (i = 0; i < self->ob_size; i++) {
- int cmp = PyObject_RichCompareBool(self->ob_item[i],
v, Py_EQ);
+ item = self->ob_item[i];
+ if (keyfunc != NULL) {
+ item = PyObject_CallFunctionObjArgs(keyfunc,
item,
+ NULL);
+ }
+
+ if (compare != NULL) {
+ cmp = custom_compare(item, v, compare);
+ } else {
+ cmp = PyObject_RichCompareBool(item, v,
Py_EQ);
+ }
if (cmp > 0)
count++;
- else if (cmp < 0)
+ else if (cmp == -9)
return NULL;
}
return PyInt_FromSsize_t(count);
@@ -2404,7 +2444,7 @@
PyDoc_STRVAR(index_doc,
"L.index(value, [start, [stop]]) -> integer -- return first index of
value");
PyDoc_STRVAR(count_doc,
-"L.count(value) -> integer -- return number of occurrences of
value");
+"L.count(value, cmp=None, key=None) -> integer -- return number of
occurrences of value [in the key] [with the cmp function].");
PyDoc_STRVAR(reverse_doc,
"L.reverse() -- reverse *IN PLACE*");
PyDoc_STRVAR(sort_doc,
@@ -2422,7 +2462,7 @@
{"pop", (PyCFunction)listpop, METH_VARARGS,
pop_doc},
{"remove", (PyCFunction)listremove, METH_O, remove_doc},
{"index", (PyCFunction)listindex, METH_VARARGS,
index_doc},
- {"count", (PyCFunction)listcount, METH_O, count_doc},
+ {"count", (PyCFunction)listcount, METH_VARARGS |
METH_KEYWORDS, count_doc},
{"reverse", (PyCFunction)listreverse, METH_NOARGS,
reverse_doc},
{"sort", (PyCFunction)listsort, METH_VARARGS |
METH_KEYWORDS, sort_doc},
{NULL, NULL} /* sentinel */
More information about the Python-list
mailing list