Commit 53710aa5 authored by Joseph Weston's avatar Joseph Weston
Browse files

simplify implementation of integer hash on Python 3

The more complicated implementation that we had previously,
(which was copied not-quite-verbatim from
https://github.com/python/cpython/blob/master/Objects/longobject.c#L3031)
is not necessary because hashing for integers is just the integer
itself modulo _PyHASH_MODULUS (being careful with the sign).
parent 798ee0cd
...@@ -811,34 +811,14 @@ fail: ...@@ -811,34 +811,14 @@ fail:
// the only documentation for this is in the Python sourcecode // the only documentation for this is in the Python sourcecode
const Py_hash_t HASH_IMAG = _PyHASH_IMAG; const Py_hash_t HASH_IMAG = _PyHASH_IMAG;
Py_hash_t hash(long x_) Py_hash_t hash(long x)
{ {
int negative = x_ < 0; // For integers the hash is just the integer itself modulo _PyHASH_MODULUS
unsigned long x = (negative ? -x_ : x_); // except for the singular case of -1.
// x is the absolute value of x_. // define 'sign' of the correct width to avoid overflow
Py_hash_t sign = x < 0 ? -1 : 1;
if (x < PyLong_BASE) { Py_hash_t result = sign * ((sign * x) % _PyHASH_MODULUS);
if (negative) return result == -1 ? -2 : result;
return x == 1 ? -2 : -long(x);
else
return x;
}
// PyLong_SHIFT is 15 for 32-bit architectures and 30 for 64-bit. So a
// long contains at most 3 digits. Therefore, a starting value of n = 2 is
// sufficient.
Py_uhash_t r = 0;
for (int n = 2; n >= 0; --n) {
unsigned dig = (x >> (n * PyLong_SHIFT)) & PyLong_MASK;
if (r == 0 && dig == 0) continue;
r = ((r << PyLong_SHIFT) & _PyHASH_MODULUS) |
(r >> (_PyHASH_BITS - PyLong_SHIFT));
r += dig;
if (r >= _PyHASH_MODULUS) r -= _PyHASH_MODULUS;
}
if (negative) r = -r;
if (r == Py_uhash_t(-1)) r = Py_uhash_t(-2);
return r;
} }
#else #else
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment