Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 51f3ef9

Browse files
committed
Issue #3106: Speedup some comparisons. This also removes the last call
to Py_CmpToRich from the codebase (in longobject.c).
1 parent c9928cc commit 51f3ef9

3 files changed

Lines changed: 90 additions & 73 deletions

File tree

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ What's New in Python 3.1 alpha 0
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #3106: Speedup some comparisons (str/str and int/int).
16+
1517
- Issue #2183: Simplify and optimize bytecode for list, dict and set
1618
comprehensions. Original patch for list comprehensions by Neal Norwitz.
1719

Objects/longobject.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,14 +2232,45 @@ long_compare(PyLongObject *a, PyLongObject *b)
22322232
return sign < 0 ? -1 : sign > 0 ? 1 : 0;
22332233
}
22342234

2235+
#define TEST_COND(cond) \
2236+
((cond) ? Py_True : Py_False)
2237+
22352238
static PyObject *
22362239
long_richcompare(PyObject *self, PyObject *other, int op)
22372240
{
2238-
PyObject *result;
2241+
int result;
2242+
PyObject *v;
22392243
CHECK_BINOP(self, other);
2240-
result = Py_CmpToRich(op, long_compare((PyLongObject*)self,
2241-
(PyLongObject*)other));
2242-
return result;
2244+
if (self == other)
2245+
result = 0;
2246+
else
2247+
result = long_compare((PyLongObject*)self, (PyLongObject*)other);
2248+
/* Convert the return value to a Boolean */
2249+
switch (op) {
2250+
case Py_EQ:
2251+
v = TEST_COND(result == 0);
2252+
break;
2253+
case Py_NE:
2254+
v = TEST_COND(result != 0);
2255+
break;
2256+
case Py_LE:
2257+
v = TEST_COND(result <= 0);
2258+
break;
2259+
case Py_GE:
2260+
v = TEST_COND(result >= 0);
2261+
break;
2262+
case Py_LT:
2263+
v = TEST_COND(result == -1);
2264+
break;
2265+
case Py_GT:
2266+
v = TEST_COND(result == 1);
2267+
break;
2268+
default:
2269+
PyErr_BadArgument();
2270+
return NULL;
2271+
}
2272+
Py_INCREF(v);
2273+
return v;
22432274
}
22442275

22452276
static long

Objects/unicodeobject.c

Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -6508,81 +6508,65 @@ PyUnicode_CompareWithASCIIString(PyObject* uni, const char* str)
65086508
return 0;
65096509
}
65106510

6511+
6512+
#define TEST_COND(cond) \
6513+
((cond) ? Py_True : Py_False)
6514+
65116515
PyObject *PyUnicode_RichCompare(PyObject *left,
65126516
PyObject *right,
65136517
int op)
65146518
{
65156519
int result;
6516-
6517-
result = PyUnicode_Compare(left, right);
6518-
if (result == -1 && PyErr_Occurred())
6519-
goto onError;
6520-
6521-
/* Convert the return value to a Boolean */
6522-
switch (op) {
6523-
case Py_EQ:
6524-
result = (result == 0);
6525-
break;
6526-
case Py_NE:
6527-
result = (result != 0);
6528-
break;
6529-
case Py_LE:
6530-
result = (result <= 0);
6531-
break;
6532-
case Py_GE:
6533-
result = (result >= 0);
6534-
break;
6535-
case Py_LT:
6536-
result = (result == -1);
6537-
break;
6538-
case Py_GT:
6539-
result = (result == 1);
6540-
break;
6541-
}
6542-
return PyBool_FromLong(result);
6543-
6544-
onError:
6545-
6546-
/* Standard case
6547-
6548-
Type errors mean that PyUnicode_FromObject() could not convert
6549-
one of the arguments (usually the right hand side) to Unicode,
6550-
ie. we can't handle the comparison request. However, it is
6551-
possible that the other object knows a comparison method, which
6552-
is why we return Py_NotImplemented to give the other object a
6553-
chance.
6554-
6555-
*/
6556-
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
6557-
PyErr_Clear();
6558-
Py_INCREF(Py_NotImplemented);
6559-
return Py_NotImplemented;
6520+
6521+
if (PyUnicode_Check(left) && PyUnicode_Check(right)) {
6522+
PyObject *v;
6523+
if (((PyUnicodeObject *) left)->length !=
6524+
((PyUnicodeObject *) right)->length) {
6525+
if (op == Py_EQ) {
6526+
Py_INCREF(Py_False);
6527+
return Py_False;
6528+
}
6529+
if (op == Py_NE) {
6530+
Py_INCREF(Py_True);
6531+
return Py_True;
6532+
}
6533+
}
6534+
if (left == right)
6535+
result = 0;
6536+
else
6537+
result = unicode_compare((PyUnicodeObject *)left,
6538+
(PyUnicodeObject *)right);
6539+
6540+
/* Convert the return value to a Boolean */
6541+
switch (op) {
6542+
case Py_EQ:
6543+
v = TEST_COND(result == 0);
6544+
break;
6545+
case Py_NE:
6546+
v = TEST_COND(result != 0);
6547+
break;
6548+
case Py_LE:
6549+
v = TEST_COND(result <= 0);
6550+
break;
6551+
case Py_GE:
6552+
v = TEST_COND(result >= 0);
6553+
break;
6554+
case Py_LT:
6555+
v = TEST_COND(result == -1);
6556+
break;
6557+
case Py_GT:
6558+
v = TEST_COND(result == 1);
6559+
break;
6560+
default:
6561+
PyErr_BadArgument();
6562+
return NULL;
6563+
}
6564+
Py_INCREF(v);
6565+
return v;
65606566
}
6561-
if (op != Py_EQ && op != Py_NE)
6562-
return NULL;
6563-
6564-
/* Equality comparison.
6565-
6566-
This is a special case: we silence any PyExc_UnicodeDecodeError
6567-
and instead turn it into a PyErr_UnicodeWarning.
6568-
6569-
*/
6570-
if (!PyErr_ExceptionMatches(PyExc_UnicodeDecodeError))
6571-
return NULL;
6572-
PyErr_Clear();
6573-
if (PyErr_WarnEx(PyExc_UnicodeWarning,
6574-
(op == Py_EQ) ?
6575-
"equal comparison "
6576-
"failed to convert both arguments to str - "
6577-
"interpreting them as being unequal"
6578-
:
6579-
"Unicode unequal comparison "
6580-
"failed to convert both arguments to str - "
6581-
"interpreting them as being unequal",
6582-
1) < 0)
6583-
return NULL;
6584-
result = (op == Py_NE);
6585-
return PyBool_FromLong(result);
6567+
6568+
Py_INCREF(Py_NotImplemented);
6569+
return Py_NotImplemented;
65866570
}
65876571

65886572
int PyUnicode_Contains(PyObject *container,

0 commit comments

Comments
 (0)