diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-05-23 13:33:13 +0000 |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-05-23 13:33:13 +0000 |
commit | dc787d2055a7b562b64ca91b8f1af6d49fa39f1c (patch) | |
tree | f6a3868e8134c25c662868f19306bfea76b0ab45 /Objects/typeobject.c | |
parent | 03721133a68814696e3eee75b1eb09f5016ff078 (diff) | |
download | cpython-dc787d2055a7b562b64ca91b8f1af6d49fa39f1c.tar.gz cpython-dc787d2055a7b562b64ca91b8f1af6d49fa39f1c.zip |
Issue #8188: Introduce a new scheme for computing hashes of numbers
(instances of int, float, complex, decimal.Decimal and
fractions.Fraction) that makes it easy to maintain the invariant that
hash(x) == hash(y) whenever x and y have equal value.
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r-- | Objects/typeobject.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 369bac6bb97..adfb0ec0674 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4921,6 +4921,7 @@ slot_tp_hash(PyObject *self) PyObject *func, *res; static PyObject *hash_str; long h; + int overflow; func = lookup_method(self, "__hash__", &hash_str); @@ -4937,14 +4938,27 @@ slot_tp_hash(PyObject *self) Py_DECREF(func); if (res == NULL) return -1; - if (PyLong_Check(res)) + + if (!PyLong_Check(res)) { + PyErr_SetString(PyExc_TypeError, + "__hash__ method should return an integer"); + return -1; + } + /* Transform the PyLong `res` to a C long `h`. For an existing + hashable Python object x, hash(x) will always lie within the range + of a C long. Therefore our transformation must preserve values + that already lie within this range, to ensure that if x.__hash__() + returns hash(y) then hash(x) == hash(y). */ + h = PyLong_AsLongAndOverflow(res, &overflow); + if (overflow) + /* res was not within the range of a C long, so we're free to + use any sufficiently bit-mixing transformation; + long.__hash__ will do nicely. */ h = PyLong_Type.tp_hash(res); - else - h = PyLong_AsLong(res); Py_DECREF(res); - if (h == -1 && !PyErr_Occurred()) - h = -2; - return h; + if (h == -1 && !PyErr_Occurred()) + h = -2; + return h; } static PyObject * |