aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects/typeobject.c
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-05-23 13:33:13 +0000
committerMark Dickinson <dickinsm@gmail.com>2010-05-23 13:33:13 +0000
commitdc787d2055a7b562b64ca91b8f1af6d49fa39f1c (patch)
treef6a3868e8134c25c662868f19306bfea76b0ab45 /Objects/typeobject.c
parent03721133a68814696e3eee75b1eb09f5016ff078 (diff)
downloadcpython-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.c26
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 *