Author: Armin Rigo <[email protected]>
Branch: keys_with_hash
Changeset: r79326:d81cb45a927e
Date: 2015-08-31 17:13 +0200
http://bitbucket.org/pypy/pypy/changeset/d81cb45a927e/

Log:    iterkeys_with_hash()

diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -11,7 +11,7 @@
     SomeString, SomeChar, SomeList, SomeDict, SomeTuple, SomeImpossibleValue,
     SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod,
     SomeFloat, SomeIterator, SomePBC, SomeNone, SomeType, s_ImpossibleValue,
-    s_Bool, s_None, unionof, add_knowntypedata,
+    s_Bool, s_None, s_Int, unionof, add_knowntypedata,
     HarmlesslyBlocked, SomeWeakRef, SomeUnicodeString, SomeByteArray)
 from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue
 from rpython.annotator import builtin
@@ -409,6 +409,8 @@
                 return s_ImpossibleValue
             else:
                 return SomeTuple((s_key, s_value))
+        if variant == 'keys_with_hash':
+            return SomeTuple((self.dictdef.read_key(), s_Int))
         else:
             raise ValueError
 
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -788,6 +788,27 @@
         d = d.keys()
     return reversed(d)
 
+def iterkeys_with_hash(d):
+    """Iterates (key, hash) pairs without recomputing the hash."""
+    assert not we_are_translated()    # this code is only before translation
+    for k in d:
+        yield k, compute_hash(k)
+
+class Entry(ExtRegistryEntry):
+    _about_ = iterkeys_with_hash
+
+    def compute_result_annotation(self, s_d):
+        from rpython.annotator.model import SomeDict, SomeIterator, s_None
+        if isinstance(s_d, SomeDict):
+            return SomeIterator(s_d, 'keys_with_hash')
+        if s_None.contains(s_d):
+            return None
+        raise Exception("iterkeys_with_hash(x): x not a dict")
+
+    def specialize_call(self, hop):
+        from rpython.rtyper.lltypesystem.rdict import DictIteratorRepr
+        hop.exception_cannot_occur()
+        return DictIteratorRepr(hop.args_r[0], "keys_with_hash").newiter(hop)
 
 # ____________________________________________________________
 
diff --git a/rpython/rlib/test/test_objectmodel.py 
b/rpython/rlib/test/test_objectmodel.py
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -592,6 +592,22 @@
     r = interpret(f, [29])
     assert r == 1
 
+def test_iterkeys_with_hash():
+    def f(i):
+        d = {i+.0: 5, i+.5: 6}
+        total = 0
+        for k, h in iterkeys_with_hash(d):
+            print k, h
+            print compute_hash(k)
+            total += k * h
+        total -= (i + 0.0) * compute_hash(i + 0.0)
+        total -= (i + 0.5) * compute_hash(i + 0.5)
+        return total
+
+    assert f(29) == 0.0
+    r = interpret(f, [29])
+    assert r == 0.0
+
 def test_import_from_mixin():
     class M:    # old-style
         def f(self): pass
diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py
--- a/rpython/rtyper/rdict.py
+++ b/rpython/rtyper/rdict.py
@@ -79,7 +79,8 @@
         hop.has_implicit_exception(RuntimeError)
         hop.exception_is_here()
         v_index = hop.gendirectcall(self._ll_dictnext, v_iter)
-        if variant == 'items' and hop.r_result.lowleveltype != lltype.Void:
+        if ((variant == 'items' and hop.r_result.lowleveltype != lltype.Void) 
or
+             variant == 'keys_with_hash'):
             # this allocates the tuple for the result, directly in the function
             # where it will be used (likely).  This will let it be removed.
             c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype.TO)
@@ -98,11 +99,14 @@
             c_key = hop.inputconst(lltype.Void, 'key')
             v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key],
                               resulttype=KEY)
-        if variant != 'keys' and variant != 'reversed':
+        if variant == 'values' or variant == 'items':
             VALUE = ENTRIES.TO.OF.value
             c_value = hop.inputconst(lltype.Void, 'value')
             v_value = hop.genop('getinteriorfield', 
[v_entries,v_index,c_value],
                                 resulttype=VALUE)
+        elif variant == 'keys_with_hash':
+            v_value = hop.gendirectcall(ENTRIES.TO.hash, v_entries, v_index)
+        #
         if variant == 'keys' or variant == 'reversed':
             return self.r_dict.recast_key(hop.llops, v_key)
         elif variant == 'values':
@@ -110,7 +114,7 @@
         elif hop.r_result.lowleveltype == lltype.Void:
             return hop.inputconst(lltype.Void, None)
         else:
-            assert variant == 'items'
+            assert variant == 'items' or variant == 'keys_with_hash'
             ITEM0 = v_result.concretetype.TO.item0
             ITEM1 = v_result.concretetype.TO.item1
             if ITEM0 != v_key.concretetype:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to