Author: Ronan Lamy <[email protected]>
Branch:
Changeset: r86451:eeb7fd8a6676
Date: 2016-08-23 16:27 +0100
http://bitbucket.org/pypy/pypy/changeset/eeb7fd8a6676/
Log: Make sure that hash(x) == x.__hash__() for int, long
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -362,11 +362,10 @@
return _new_int(space, w_inttype, w_x, w_base)
def descr_hash(self, space):
- # unlike CPython, we don't special-case the value -1 in most of
- # our hash functions, so there is not much sense special-casing
- # it here either. Make sure this is consistent with the hash of
- # floats and longs.
- return self.int(space)
+ # For compatibility with CPython, we special-case -1
+ h = self.intval
+ h -= (h == -1) # No explicit condition, to avoid JIT bridges
+ return wrapint(space, h)
def _int(self, space):
return self.int(space)
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -130,7 +130,12 @@
descr_repr = _make_descr_unaryop('repr')
descr_str = _make_descr_unaryop('str')
- descr_hash = _make_descr_unaryop('hash')
+
+ def descr_hash(self, space):
+ h = self.asbigint().hash()
+ h -= (h == -1)
+ return space.newint(h)
+
descr_oct = _make_descr_unaryop('oct')
descr_hex = _make_descr_unaryop('hex')
@@ -387,12 +392,12 @@
def _make_generic_descr_binop(opname):
if opname not in COMMUTATIVE_OPS:
raise Exception("Not supported")
-
+
methname = opname + '_' if opname in ('and', 'or') else opname
descr_rname = 'descr_r' + opname
op = getattr(rbigint, methname)
intop = getattr(rbigint, "int_" + methname)
-
+
@func_renamer('descr_' + opname)
def descr_binop(self, space, w_other):
if isinstance(w_other, W_AbstractIntObject):
@@ -412,7 +417,7 @@
return W_LongObject(op(w_other.asbigint(), self.num))
return descr_binop, descr_rbinop
-
+
descr_add, descr_radd = _make_generic_descr_binop('add')
descr_sub, descr_rsub = _make_generic_descr_binop_noncommutative('sub')
descr_mul, descr_rmul = _make_generic_descr_binop('mul')
@@ -454,12 +459,12 @@
except OverflowError: # b too big
raise oefmt(space.w_OverflowError, "shift count too large")
return W_LongObject(self.num.lshift(shift))
-
+
def _int_lshift(self, space, w_other):
if w_other < 0:
raise oefmt(space.w_ValueError, "negative shift count")
return W_LongObject(self.num.lshift(w_other))
-
+
descr_lshift, descr_rlshift = _make_descr_binop(_lshift, _int_lshift)
def _rshift(self, space, w_other):
@@ -470,7 +475,7 @@
except OverflowError: # b too big # XXX maybe just return 0L instead?
raise oefmt(space.w_OverflowError, "shift count too large")
return newlong(space, self.num.rshift(shift))
-
+
def _int_rshift(self, space, w_other):
if w_other < 0:
raise oefmt(space.w_ValueError, "negative shift count")
@@ -485,7 +490,7 @@
raise oefmt(space.w_ZeroDivisionError,
"long division or modulo by zero")
return newlong(space, z)
-
+
def _floordiv(self, space, w_other):
try:
z = self.num.floordiv(w_other.asbigint())
@@ -505,7 +510,7 @@
raise oefmt(space.w_ZeroDivisionError,
"long division or modulo by zero")
return newlong(space, z)
-
+
def _int_mod(self, space, w_other):
try:
z = self.num.int_mod(w_other)
diff --git a/pypy/objspace/std/test/test_intobject.py
b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -295,7 +295,11 @@
assert self.space.unwrap(result) == hex(x)
-class AppTestInt:
+class AppTestInt(object):
+ def test_hash(self):
+ assert hash(-1) == (-1).__hash__() == -2
+ assert hash(-2) == (-2).__hash__() == -2
+
def test_conjugate(self):
assert (1).conjugate() == 1
assert (-1).conjugate() == -1
@@ -454,11 +458,11 @@
return None
inst = a()
raises(TypeError, int, inst)
- assert inst.ar == True
+ assert inst.ar == True
class b(object):
- pass
- raises((AttributeError,TypeError), int, b())
+ pass
+ raises((AttributeError,TypeError), int, b())
def test_special_long(self):
class a(object):
diff --git a/pypy/objspace/std/test/test_longobject.py
b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -228,7 +228,7 @@
def test_hash(self):
# ints have the same hash as equal longs
for i in range(-4, 14):
- assert hash(i) == hash(long(i))
+ assert hash(i) == hash(long(i)) == long(i).__hash__()
# might check too much -- it's ok to change the hashing algorithm
assert hash(123456789L) == 123456789
assert hash(1234567890123456789L) in (
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit