[pypy-svn] r68351 - in pypy/branch/gc-hash/pypy/rlib: . test

arigo at codespeak.net arigo at codespeak.net
Mon Oct 12 19:47:12 CEST 2009


Author: arigo
Date: Mon Oct 12 19:47:12 2009
New Revision: 68351

Modified:
   pypy/branch/gc-hash/pypy/rlib/objectmodel.py
   pypy/branch/gc-hash/pypy/rlib/test/test_objectmodel.py
Log:
Update the docstring of compute_hash() & friends,
to only promize to work on RPython-level objects.
Tests.


Modified: pypy/branch/gc-hash/pypy/rlib/objectmodel.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rlib/objectmodel.py	(original)
+++ pypy/branch/gc-hash/pypy/rlib/objectmodel.py	Mon Oct 12 19:47:12 2009
@@ -136,12 +136,9 @@
 
 def compute_hash(x):
     """RPython equivalent of hash(x), where 'x' is an immutable
-    RPython-level or low-level object.  For strings or unicodes it
-    computes the hash as in Python.  For tuples it calls compute_hash()
-    recursively.  For instances it uses compute_identity_hash().
-    For low-level objects it returns the hash of the original RPython-
-    level object, if any, or just compute_identity_hash() otherwise.
-    It cannot be used on llmemory.GCREF.
+    RPython-level.  For strings or unicodes it computes the hash as
+    in Python.  For tuples it calls compute_hash() recursively.
+    For instances it uses compute_identity_hash().
 
     Note that this can return 0 or -1 too.
 
@@ -170,9 +167,9 @@
     """RPython equivalent of object.__hash__(x).  This returns the
     so-called 'identity hash', which is the non-overridable default hash
     of Python.  Can be called for any RPython-level object that turns
-    into a GC object, or for any low-level GC object, including
-    llmemory.GCREF.  The value is not guaranteed to be the same before
-    and after translation, except for RPython instances on the lltypesystem.
+    into a GC object, but not NULL.  The value is not guaranteed to be the
+    same before and after translation, except for RPython instances on the
+    lltypesystem.
     """
     result = object.__hash__(x)
     try:
@@ -206,14 +203,13 @@
     from pypy.rlib.rarithmetic import intmask
     length = len(s)
     if length == 0:
-        x = 0
-    else:
-        x = ord(s[0]) << 7
-        i = 0
-        while i < length:
-            x = (1000003*x) ^ ord(s[i])
-            i += 1
-        x ^= length
+        return 0
+    x = ord(s[0]) << 7
+    i = 0
+    while i < length:
+        x = (1000003*x) ^ ord(s[i])
+        i += 1
+    x ^= length
     return intmask(x)
 
 def _hash_float(f):
@@ -222,12 +218,13 @@
     except the fact that the integer case is not treated specially.
     In RPython, floats cannot be used with ints in dicts, anyway.
     """
+    from pypy.rlib.rarithmetic import intmask
     v, expo = math.frexp(f)
     v *= TAKE_NEXT
     hipart = int(v)
     v = (v - float(hipart)) * TAKE_NEXT
     x = hipart + int(v) + (expo << 15)
-    return x
+    return intmask(x)
 TAKE_NEXT = float(2**31)
 
 def _hash_tuple(t):
@@ -237,10 +234,11 @@
     that nested tuples are very uncommon in RPython, making the case
     unlikely.
     """
+    from pypy.rlib.rarithmetic import intmask
     x = 0x345678
     for item in t:
         y = compute_hash(item)
-        x = (1000003 * x) ^ y
+        x = intmask((1000003 * x) ^ y)
     return x
 
 # ----------

Modified: pypy/branch/gc-hash/pypy/rlib/test/test_objectmodel.py
==============================================================================
--- pypy/branch/gc-hash/pypy/rlib/test/test_objectmodel.py	(original)
+++ pypy/branch/gc-hash/pypy/rlib/test/test_objectmodel.py	Mon Oct 12 19:47:12 2009
@@ -141,6 +141,45 @@
     py.test.raises(TypeError, "s1 < s2")
     py.test.raises(TypeError, "hash(s1)")
 
+def test_compute_hash():
+    from pypy.rlib.objectmodel import _hash_string, _hash_float, _hash_tuple
+    assert compute_hash("Hello") == _hash_string("Hello")
+    assert compute_hash(7) == 7
+    assert compute_hash(-3.5) == _hash_float(-3.5)
+    assert compute_hash(None) == 0
+    assert compute_hash(("world", None, 7)) == _hash_tuple(("world", None, 7))
+    #
+    class Foo(object):
+        def __hash__(self):
+            return 42
+    foo = Foo()
+    h = compute_hash(foo)
+    assert h == object.__hash__(foo)
+    assert h == getattr(foo, '__precomputed_identity_hash')
+    assert compute_hash(None) == 0
+
+def test_compute_identity_hash():
+    class Foo(object):
+        def __hash__(self):
+            return 42
+    foo = Foo()
+    h = compute_identity_hash(foo)
+    assert h == object.__hash__(foo)
+    assert h == getattr(foo, '__precomputed_identity_hash')
+
+def test_compute_unique_id():
+    class Foo(object):
+        pass
+    foo = Foo()
+    assert compute_unique_id(foo) == id(foo)
+
+def test_current_object_addr_as_int():
+    from pypy.rlib.rarithmetic import intmask
+    class Foo(object):
+        pass
+    foo = Foo()
+    assert current_object_addr_as_int(foo) == intmask(id(foo))
+
 class BaseTestObjectModel(BaseRtypingTest):
 
     def test_we_are_translated(self):
@@ -270,6 +309,27 @@
         res = self.interpret(g, [3])
         assert res == 77
 
+    def test_compute_hash(self):
+        class Foo(object):
+            pass
+        def f(i):
+            assert compute_hash(i) == compute_hash(42)
+            assert compute_hash(i+1.0) == compute_hash(43.0)
+            assert compute_hash("Hello" + str(i)) == compute_hash("Hello42")
+            if i == 42:
+                p = None
+            else:
+                p = Foo()
+            assert compute_hash(p) == compute_hash(None)
+            assert (compute_hash(("world", None, i, 7.5)) ==
+                    compute_hash(("world", None, 42, 7.5)))
+            q = Foo()
+            assert compute_hash(q) == compute_identity_hash(q)
+            return i*2
+        res = self.interpret(f, [42])
+        assert res == 84
+
+
 class TestLLtype(BaseTestObjectModel, LLRtypeMixin):
 
     def test_rtype_keepalive(self):
@@ -283,6 +343,33 @@
         res = self.interpret(f, [])
         assert res == 1
 
+    def test_compute_hash_across_translation(self):
+        class Foo(object):
+            pass
+        q = Foo()
+
+        def f(i):
+            assert compute_hash(i) == h_42
+            assert compute_hash(i+1.0) == h_43_dot_0
+            assert compute_hash("Hello" + str(i)) == h_Hello42
+            if i == 42:
+                p = None
+            else:
+                p = Foo()
+            assert compute_hash(p) == h_None
+            assert compute_hash(("world", None, i, 7.5)) == h_tuple
+            assert compute_hash(q) == h_q
+            return i*2
+        h_42       = compute_hash(42)
+        h_43_dot_0 = compute_hash(43.0)
+        h_Hello42  = compute_hash("Hello42")
+        h_None     = compute_hash(None)
+        h_tuple    = compute_hash(("world", None, 42, 7.5))
+        h_q        = compute_hash(q)
+        
+        res = self.interpret(f, [42])
+        assert res == 84
+
 
 class TestOOtype(BaseTestObjectModel, OORtypeMixin):
     pass



More information about the Pypy-commit mailing list