[pypy-svn] r24780 - in pypy/dist/pypy: annotation rpython rpython/lltypesystem rpython/ootypesystem rpython/test

arigo at codespeak.net arigo at codespeak.net
Wed Mar 22 12:00:35 CET 2006


Author: arigo
Date: Wed Mar 22 12:00:31 2006
New Revision: 24780

Modified:
   pypy/dist/pypy/annotation/unaryop.py
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/ootypesystem/rclass.py
   pypy/dist/pypy/rpython/rclass.py
   pypy/dist/pypy/rpython/rfloat.py
   pypy/dist/pypy/rpython/rmodel.py
   pypy/dist/pypy/rpython/rstr.py
   pypy/dist/pypy/rpython/rtuple.py
   pypy/dist/pypy/rpython/test/test_rtuple.py
Log:
* improve hash(tuple) in RPython, based on CPython's algo.
* remove rtype_hash() everywhere and replace them with a
  generic implementation based on get_ll_hash_function().


Modified: pypy/dist/pypy/annotation/unaryop.py
==============================================================================
--- pypy/dist/pypy/annotation/unaryop.py	(original)
+++ pypy/dist/pypy/annotation/unaryop.py	Wed Mar 22 12:00:31 2006
@@ -246,6 +246,11 @@
     def getanyitem(tup):
         return unionof(*tup.items)
 
+    def hash(tup):
+        for s_item in tup.items:
+            s_item.hash()    # record that we need the hash of each item
+        return SomeInteger()
+
 
 class __extend__(SomeList):
 

Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Wed Mar 22 12:00:31 2006
@@ -377,12 +377,9 @@
     def create_instance(self):
         return malloc(self.object_type, flavor=self.getflavor()) # pick flavor
 
-    def get_ll_eq_function(self):
-        return ll_inst_eq
-
     def get_ll_hash_function(self):
         if self.classdef is None:
-            return None
+            raise TyperError, 'missing hash support flag in classdef'
         if self.rtyper.needs_hash_support(self.classdef):
             try:
                 return self._ll_hash_function
@@ -500,15 +497,6 @@
         else:
             return instance_repr.getfield(vinst, '__class__', hop.llops)
 
-    def rtype_hash(self, hop):
-        if self.classdef is None:
-            raise TyperError, "hash() not supported for this class"                        
-        if self.rtyper.needs_hash_support(self.classdef):
-            vinst, = hop.inputargs(self)
-            return hop.gendirectcall(ll_inst_hash, vinst)
-        else:
-            return self.rbase.rtype_hash(hop)
-
     def rtype_getattr(self, hop):
         attr = hop.args_s[1].const
         vinst, vattr = hop.inputargs(self, Void)
@@ -637,9 +625,6 @@
        cached = ins.hash_cache = id(ins)
     return cached
 
-def ll_inst_eq(ins1, ins2):
-    return ins1 == ins2
-
 def ll_inst_type(obj):
     if obj:
         return obj.typeptr

Modified: pypy/dist/pypy/rpython/ootypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rclass.py	Wed Mar 22 12:00:31 2006
@@ -328,6 +328,9 @@
                         graph=graph)
         ootype.addMethods(self.lowleveltype, {mangled: m})
 
+    def get_ll_hash_function(self):
+        return ll_inst_hash
+
     def rtype_getattr(self, hop):
         v_inst, _ = hop.inputargs(self, ootype.Void)
         s_inst = hop.args_s[0]
@@ -376,15 +379,6 @@
             cmeta = inputconst(ootype.Void, "meta")
             return hop.genop('oogetfield', [vinst, cmeta], resulttype=CLASSTYPE)
 
-    def rtype_hash(self, hop):
-        if self.classdef is None:
-            raise TyperError, "hash() not supported for this class"
-        if self.rtyper.needs_hash_support(self.classdef):
-            vinst, = hop.inputargs(self)
-            return hop.gendirectcall(ll_inst_hash, vinst)
-        else:
-            return self.baserepr.rtype_hash(hop)
-
     def rtype_id(self, hop):
         vinst, = hop.inputargs(self)
         return hop.genop('ooidentityhash', [vinst], resulttype=ootype.Signed)

Modified: pypy/dist/pypy/rpython/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/rclass.py	(original)
+++ pypy/dist/pypy/rpython/rclass.py	Wed Mar 22 12:00:31 2006
@@ -167,9 +167,6 @@
     def rtype_type(self, hop):
         pass
 
-    def rtype_hash(self, hop):
-        pass
-
     def rtype_getattr(self, hop):
         pass
 
@@ -182,6 +179,9 @@
     def ll_str(self, i):
         pass
 
+    def get_ll_eq_function(self):
+        return None    # defaults to compare by identity ('==' on pointers)
+
 # ____________________________________________________________
 
 def rtype_new_instance(rtyper, classdef, llops):

Modified: pypy/dist/pypy/rpython/rfloat.py
==============================================================================
--- pypy/dist/pypy/rpython/rfloat.py	(original)
+++ pypy/dist/pypy/rpython/rfloat.py	Wed Mar 22 12:00:31 2006
@@ -137,10 +137,6 @@
         from pypy.rpython.module.ll_strtod import ll_strtod_formatd
         return ll_strtod_formatd(percent_f, f)
 
-    def rtype_hash(_, hop):
-        v_flt, = hop.inputargs(float_repr)
-        return hop.gendirectcall(ll_hash_float, v_flt)
-
 percent_f = string_repr.convert_const("%f")
 
 TAKE_NEXT = float(2**31)
@@ -158,6 +154,8 @@
     v = (v - float(hipart)) * TAKE_NEXT
     x = hipart + int(v) + (expo << 15)
     return x
+ll_hash_float.cache_in_dict = True
+
 #
 # _________________________ Conversions _________________________
 

Modified: pypy/dist/pypy/rpython/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rmodel.py	(original)
+++ pypy/dist/pypy/rpython/rmodel.py	Wed Mar 22 12:00:31 2006
@@ -126,10 +126,19 @@
                     self, value))
         return value
 
-    def get_ll_eq_function(self): 
+    def get_ll_eq_function(self):
+        """Return an eq(x,y) function to use to compare two low-level
+        values of this Repr.
+        This can return None to mean that simply using '==' is fine.
+        """
         raise TyperError, 'no equality function for %r' % self
 
     def get_ll_hash_function(self):
+        """Return a hash(x) function for low-level values of this Repr.
+        As a hint, the function can have a flag 'cache_in_dict=True' if it
+        makes non-trivial computations and its result should be cached in
+        dictionary entries.
+        """
         raise TyperError, 'no hashing function for %r' % self
 
     def rtype_bltn_list(self, hop):
@@ -175,6 +184,11 @@
         # XXX
         return hop.genop('cast_ptr_to_int', [vobj], resulttype=Signed)
 
+    def rtype_hash(self, hop):
+        ll_hash = self.get_ll_hash_function()
+        v, = hop.inputargs(self)
+        return hop.gendirectcall(ll_hash, v)
+
     def rtype_iter(self, hop):
         r_iter = self.make_iterator_repr()
         return r_iter.newiter(hop)

Modified: pypy/dist/pypy/rpython/rstr.py
==============================================================================
--- pypy/dist/pypy/rpython/rstr.py	(original)
+++ pypy/dist/pypy/rpython/rstr.py	Wed Mar 22 12:00:31 2006
@@ -99,10 +99,6 @@
         v_chr = hop.gendirectcall(ll_stritem_nonneg, v_str, c_zero)
         return hop.genop('cast_char_to_int', [v_chr], resulttype=Signed)
 
-    def rtype_hash(_, hop):
-        v_str, = hop.inputargs(string_repr)
-        return hop.gendirectcall(ll_strhash, v_str)
-
     def rtype_method_startswith(_, hop):
         v_str, v_value = hop.inputargs(string_repr, string_repr)
         hop.exception_cannot_occur()

Modified: pypy/dist/pypy/rpython/rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/rtuple.py	(original)
+++ pypy/dist/pypy/rpython/rtuple.py	Wed Mar 22 12:00:31 2006
@@ -9,6 +9,7 @@
 from pypy.rpython.robject import PyObjRepr, pyobj_repr
 from pypy.rpython.lltypesystem.lltype import \
      Ptr, GcStruct, Void, Signed, malloc, typeOf, nullptr
+from pypy.rpython.rarithmetic import intmask
 
 # ____________________________________________________________
 #
@@ -56,6 +57,7 @@
         return ll_eq
 
 def gen_hash_function(items_r):
+    # based on CPython
     hash_funcs = [r_item.get_ll_hash_function() for r_item in items_r]
     key = tuple(hash_funcs)
     try:
@@ -64,18 +66,22 @@
         miniglobals = {}
         source = """
 def ll_hash(t):
-    retval = 0
+    retval = 0x345678
     %s
     return retval
 """
         body = []
+        mult = 1000003
         for i, hash_func in enumerate(hash_funcs):
             miniglobals['hash%d' % i] = hash_func
-            body.append("retval ^= hash%d(t.item%d)" % (i,i))
+            body.append("retval = (retval ^ hash%d(t.item%d)) * %d" %
+                        (i, i, mult))
+            mult = intmask(mult + 82520 + 2*len(items_r))
         body = ('\n'+' '*4).join(body)
         source = source % body
         exec source in miniglobals
         ll_hash = miniglobals['ll_hash']
+        ll_hash.cache_in_dict = True
         _gen_hash_function_cache[key] = ll_hash
         return ll_hash
 

Modified: pypy/dist/pypy/rpython/test/test_rtuple.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rtuple.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rtuple.py	Wed Mar 22 12:00:31 2006
@@ -200,3 +200,11 @@
 
     assert r_AB_tup.lowleveltype == r_BA_tup.lowleveltype
 
+
+def test_tuple_hash():
+    def f(i, j):
+        return hash((i, j))
+
+    res1 = interpret(f, [12, 27])
+    res2 = interpret(f, [27, 12])
+    assert res1 != res2



More information about the Pypy-commit mailing list