diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py index a41970d8f3f55a..ce1c515ccabe08 100644 --- a/Lib/test/seq_tests.py +++ b/Lib/test/seq_tests.py @@ -250,6 +250,38 @@ def __eq__(self, other): checklast = self.type2test([StopCompares(), 1]) self.assertRaises(DoNotTestEq, checklast.__contains__, 1) + def check_compare_id(self, a, b): + self.assertTrue(a == a) + self.assertFalse(a != a) + self.assertTrue(b == b) + self.assertFalse(b != b) + self.assertTrue(a == b) + self.assertFalse(a != b) + self.assertFalse(a < a) + self.assertFalse(b < b) + self.assertFalse(a < b) + self.assertFalse(a > b) + self.assertFalse(b < a) + self.assertFalse(b > a) + + def test_compare_nan(self): + nan = float("nan") + a = self.type2test([nan]) + b = self.type2test([nan]) + self.check_compare_id(a, b) + + def test_compare_decimal_nan(self): + import decimal + nan = decimal.Decimal("NaN") + a = self.type2test([nan]) + b = self.type2test([nan]) + self.check_compare_id(a, b) + + def test_compare_signed_zero(self): + a = self.type2test([0.0]) + b = self.type2test([-0.0]) + self.check_compare_id(a, b) + def test_len(self): self.assertEqual(len(self.type2test()), 0) self.assertEqual(len(self.type2test([])), 0) diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 169ac69701da11..397ec1ca6d6198 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -666,18 +666,28 @@ tuple_richcompare(PyObject *v, PyObject *w, int op) if (!PyTuple_Check(v) || !PyTuple_Check(w)) Py_RETURN_NOTIMPLEMENTED; + /* Fast path based on identity: if both objects are the same tuple + * object, we return immediately without comparing items. Elements that + * are not equal to themselves are therefore treated as equal here. + */ + if (v == w) { + Py_RETURN_RICHCOMPARE(0, 0, op); + } + vt = (PyTupleObject *)v; wt = (PyTupleObject *)w; vlen = Py_SIZE(vt); wlen = Py_SIZE(wt); - /* Note: the corresponding code for lists has an "early out" test - * here when op is EQ or NE and the lengths differ. That pays there, - * but Tim was unable to find any real code where EQ/NE tuple - * compares don't have the same length, so testing for it here would - * have cost without benefit. - */ + if (vlen != wlen) { + switch (op) { + case Py_EQ: + Py_RETURN_FALSE; + case Py_NE: + Py_RETURN_TRUE; + } + } /* Search for the first index where items are different. * Note that because tuples are immutable, it's safe to reuse