From ec2fe78d47a938c61985f56611112ec8a85d09a3 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 6 Jun 2008 21:47:51 +0000 Subject: Issue 3501: Make heapq support both __le__ and __lt__. --- Modules/_heapqmodule.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c index ad2fd70..aa5bbb1 100644 --- a/Modules/_heapqmodule.c +++ b/Modules/_heapqmodule.c @@ -8,6 +8,25 @@ annotated by Fran #include "Python.h" +/* Older implementations of heapq used Py_LE for comparisons. Now, it uses + Py_LT so it will match min(), sorted(), and bisect(). Unfortunately, some + client code (Twisted for example) relied on Py_LE, so this little function + restores compatability by trying both. +*/ +static int +cmp_lt(PyObject *x, PyObject *y) +{ + int cmp; + cmp = PyObject_RichCompareBool(x, y, Py_LT); + if (cmp == -1 && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + cmp = PyObject_RichCompareBool(y, x, Py_LE); + if (cmp != -1) + cmp = 1 - cmp; + } + return cmp; +} + static int _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) { @@ -28,7 +47,7 @@ _siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) while (pos > startpos){ parentpos = (pos - 1) >> 1; parent = PyList_GET_ITEM(heap, parentpos); - cmp = PyObject_RichCompareBool(newitem, parent, Py_LT); + cmp = cmp_lt(newitem, parent); if (cmp == -1) { Py_DECREF(newitem); return -1; @@ -68,10 +87,9 @@ _siftup(PyListObject *heap, Py_ssize_t pos) /* Set childpos to index of smaller child. */ rightpos = childpos + 1; if (rightpos < endpos) { - cmp = PyObject_RichCompareBool( + cmp = cmp_lt( PyList_GET_ITEM(heap, childpos), - PyList_GET_ITEM(heap, rightpos), - Py_LT); + PyList_GET_ITEM(heap, rightpos)); if (cmp == -1) { Py_DECREF(newitem); return -1; @@ -214,7 +232,7 @@ heappushpop(PyObject *self, PyObject *args) return item; } - cmp = PyObject_RichCompareBool(PyList_GET_ITEM(heap, 0), item, Py_LT); + cmp = cmp_lt(PyList_GET_ITEM(heap, 0), item); if (cmp == -1) return NULL; if (cmp == 0) { @@ -313,7 +331,7 @@ nlargest(PyObject *self, PyObject *args) else goto sortit; } - cmp = PyObject_RichCompareBool(sol, elem, Py_LT); + cmp = cmp_lt(sol, elem); if (cmp == -1) { Py_DECREF(elem); goto fail; @@ -368,7 +386,7 @@ _siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) while (pos > startpos){ parentpos = (pos - 1) >> 1; parent = PyList_GET_ITEM(heap, parentpos); - cmp = PyObject_RichCompareBool(parent, newitem, Py_LT); + cmp = cmp_lt(parent, newitem); if (cmp == -1) { Py_DECREF(newitem); return -1; @@ -408,10 +426,9 @@ _siftupmax(PyListObject *heap, Py_ssize_t pos) /* Set childpos to index of smaller child. */ rightpos = childpos + 1; if (rightpos < endpos) { - cmp = PyObject_RichCompareBool( + cmp = cmp_lt( PyList_GET_ITEM(heap, rightpos), - PyList_GET_ITEM(heap, childpos), - Py_LT); + PyList_GET_ITEM(heap, childpos)); if (cmp == -1) { Py_DECREF(newitem); return -1; @@ -484,7 +501,7 @@ nsmallest(PyObject *self, PyObject *args) else goto sortit; } - cmp = PyObject_RichCompareBool(elem, los, Py_LT); + cmp = cmp_lt(elem, los); if (cmp == -1) { Py_DECREF(elem); goto fail; -- cgit v0.12