From 51f3ef9da082435f063d2e78de1dd20fa65cf0de Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sat, 20 Dec 2008 13:14:23 +0000 Subject: Issue #3106: Speedup some comparisons. This also removes the last call to Py_CmpToRich from the codebase (in longobject.c). --- Misc/NEWS | 2 + Objects/longobject.c | 39 ++++++++++++++-- Objects/unicodeobject.c | 122 +++++++++++++++++++++--------------------------- 3 files changed, 90 insertions(+), 73 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 9274a83..98dae61 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ What's New in Python 3.1 alpha 0 Core and Builtins ----------------- +- Issue #3106: Speedup some comparisons (str/str and int/int). + - Issue #2183: Simplify and optimize bytecode for list, dict and set comprehensions. Original patch for list comprehensions by Neal Norwitz. diff --git a/Objects/longobject.c b/Objects/longobject.c index 677221a..362d0ad 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2232,14 +2232,45 @@ long_compare(PyLongObject *a, PyLongObject *b) return sign < 0 ? -1 : sign > 0 ? 1 : 0; } +#define TEST_COND(cond) \ + ((cond) ? Py_True : Py_False) + static PyObject * long_richcompare(PyObject *self, PyObject *other, int op) { - PyObject *result; + int result; + PyObject *v; CHECK_BINOP(self, other); - result = Py_CmpToRich(op, long_compare((PyLongObject*)self, - (PyLongObject*)other)); - return result; + if (self == other) + result = 0; + else + result = long_compare((PyLongObject*)self, (PyLongObject*)other); + /* Convert the return value to a Boolean */ + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result == -1); + break; + case Py_GT: + v = TEST_COND(result == 1); + break; + default: + PyErr_BadArgument(); + return NULL; + } + Py_INCREF(v); + return v; } static long diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6f64a07..38c3385 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6508,81 +6508,65 @@ PyUnicode_CompareWithASCIIString(PyObject* uni, const char* str) return 0; } + +#define TEST_COND(cond) \ + ((cond) ? Py_True : Py_False) + PyObject *PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) { int result; - - result = PyUnicode_Compare(left, right); - if (result == -1 && PyErr_Occurred()) - goto onError; - - /* Convert the return value to a Boolean */ - switch (op) { - case Py_EQ: - result = (result == 0); - break; - case Py_NE: - result = (result != 0); - break; - case Py_LE: - result = (result <= 0); - break; - case Py_GE: - result = (result >= 0); - break; - case Py_LT: - result = (result == -1); - break; - case Py_GT: - result = (result == 1); - break; - } - return PyBool_FromLong(result); - - onError: - - /* Standard case - - Type errors mean that PyUnicode_FromObject() could not convert - one of the arguments (usually the right hand side) to Unicode, - ie. we can't handle the comparison request. However, it is - possible that the other object knows a comparison method, which - is why we return Py_NotImplemented to give the other object a - chance. - - */ - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; + + if (PyUnicode_Check(left) && PyUnicode_Check(right)) { + PyObject *v; + if (((PyUnicodeObject *) left)->length != + ((PyUnicodeObject *) right)->length) { + if (op == Py_EQ) { + Py_INCREF(Py_False); + return Py_False; + } + if (op == Py_NE) { + Py_INCREF(Py_True); + return Py_True; + } + } + if (left == right) + result = 0; + else + result = unicode_compare((PyUnicodeObject *)left, + (PyUnicodeObject *)right); + + /* Convert the return value to a Boolean */ + switch (op) { + case Py_EQ: + v = TEST_COND(result == 0); + break; + case Py_NE: + v = TEST_COND(result != 0); + break; + case Py_LE: + v = TEST_COND(result <= 0); + break; + case Py_GE: + v = TEST_COND(result >= 0); + break; + case Py_LT: + v = TEST_COND(result == -1); + break; + case Py_GT: + v = TEST_COND(result == 1); + break; + default: + PyErr_BadArgument(); + return NULL; + } + Py_INCREF(v); + return v; } - if (op != Py_EQ && op != Py_NE) - return NULL; - - /* Equality comparison. - - This is a special case: we silence any PyExc_UnicodeDecodeError - and instead turn it into a PyErr_UnicodeWarning. - - */ - if (!PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) - return NULL; - PyErr_Clear(); - if (PyErr_WarnEx(PyExc_UnicodeWarning, - (op == Py_EQ) ? - "equal comparison " - "failed to convert both arguments to str - " - "interpreting them as being unequal" - : - "Unicode unequal comparison " - "failed to convert both arguments to str - " - "interpreting them as being unequal", - 1) < 0) - return NULL; - result = (op == Py_NE); - return PyBool_FromLong(result); + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } int PyUnicode_Contains(PyObject *container, -- cgit v0.12