[pypy-commit] pypy keys_with_hash: iteritems_with_hash()

arigo noreply at buildbot.pypy.org
Tue Sep 1 12:11:23 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: keys_with_hash
Changeset: r79345:9d075ff7b6f1
Date: 2015-09-01 11:56 +0200
http://bitbucket.org/pypy/pypy/changeset/9d075ff7b6f1/

Log:	iteritems_with_hash()

diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -403,18 +403,22 @@
             return self.dictdef.read_key()
         elif variant == 'values':
             return self.dictdef.read_value()
-        elif variant == 'items':
+        elif variant == 'items' or variant == 'items_with_hash':
             s_key   = self.dictdef.read_key()
             s_value = self.dictdef.read_value()
             if (isinstance(s_key, SomeImpossibleValue) or
                 isinstance(s_value, SomeImpossibleValue)):
                 return s_ImpossibleValue
-            else:
+            elif variant == 'items':
                 return SomeTuple((s_key, s_value))
-        if variant == 'keys_with_hash':
-            return SomeTuple((self.dictdef.read_key(), s_Int))
-        else:
-            raise ValueError
+            elif variant == 'items_with_hash':
+                return SomeTuple((s_key, s_value, s_Int))
+        elif variant == 'keys_with_hash':
+            s_key = self.dictdef.read_key()
+            if isinstance(s_key, SomeImpossibleValue):
+                return s_ImpossibleValue
+            return SomeTuple((s_key, s_Int))
+        raise ValueError(variant)
 
     def method_get(self, key, dfl):
         self.dictdef.generalize_key(key)
@@ -455,6 +459,9 @@
     def method_iterkeys_with_hash(self):
         return SomeIterator(self, 'keys_with_hash')
 
+    def method_iteritems_with_hash(self):
+        return SomeIterator(self, 'items_with_hash')
+
     def method_clear(self):
         pass
 
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -805,6 +805,17 @@
         return _iterkeys_with_hash_untranslated(d)
     return d.iterkeys_with_hash()
 
+def _iteritems_with_hash_untranslated(d):
+    for k, v in d.iteritems():
+        yield (k, v, _expected_hash(d, k))
+
+ at specialize.call_location()
+def iteritems_with_hash(d):
+    """Iterates (key, value, keyhash) triples without recomputing the hash."""
+    if not we_are_translated():
+        return _iteritems_with_hash_untranslated(d)
+    return d.iteritems_with_hash()
+
 @specialize.call_location()
 def contains_with_hash(d, key, h):
     """Same as 'key in d'.  The extra argument is the hash.  Use this only
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
@@ -606,6 +606,20 @@
     r = interpret(f, [29])
     assert r == 0.0
 
+def test_iteritems_with_hash():
+    def f(i):
+        d = {i+.0: 5, i+.5: 6}
+        total = 0
+        for k, v, h in iteritems_with_hash(d):
+            total += k * h * v
+        total -= (i + 0.0) * compute_hash(i + 0.0) * 5
+        total -= (i + 0.5) * compute_hash(i + 0.5) * 6
+        return total
+
+    assert f(29) == 0.0
+    r = interpret(f, [29])
+    assert r == 0.0
+
 def test_contains_with_hash():
     def f(i):
         d = {i+.5: 5}
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -339,6 +339,10 @@
         hop.exception_cannot_occur()
         return DictIteratorRepr(self, "keys_with_hash").newiter(hop)
 
+    def rtype_method_iteritems_with_hash(self, hop):
+        hop.exception_cannot_occur()
+        return DictIteratorRepr(self, "items_with_hash").newiter(hop)
+
     def rtype_method_clear(self, hop):
         v_dict, = hop.inputargs(self)
         hop.exception_cannot_occur()
diff --git a/rpython/rtyper/rdict.py b/rpython/rtyper/rdict.py
--- a/rpython/rtyper/rdict.py
+++ b/rpython/rtyper/rdict.py
@@ -80,7 +80,7 @@
         hop.exception_is_here()
         v_index = hop.gendirectcall(self._ll_dictnext, v_iter)
         if ((variant == 'items' and hop.r_result.lowleveltype != lltype.Void) or
-             variant == 'keys_with_hash'):
+             variant == 'keys_with_hash' or variant == 'items_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)
@@ -99,22 +99,32 @@
             c_key = hop.inputconst(lltype.Void, 'key')
             v_key = hop.genop('getinteriorfield', [v_entries, v_index, c_key],
                               resulttype=KEY)
-        if variant == 'values' or variant == 'items':
+        if (variant == 'values' or variant == 'items'
+                                or variant == 'items_with_hash'):
             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_with_hash' or variant == 'items_with_hash':
+            v_hash = 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':
             return self.r_dict.recast_value(hop.llops, v_value)
+        elif variant == 'keys_with_hash':
+            ITEM0 = v_result.concretetype.TO.item0
+            if ITEM0 != v_key.concretetype:
+                v_key = hop.genop('cast_pointer', [v_key], resulttype=ITEM0)
+            c_item0 = hop.inputconst(lltype.Void, 'item0')
+            c_item1 = hop.inputconst(lltype.Void, 'item1')
+            hop.genop('setfield', [v_result, c_item0, v_key])
+            hop.genop('setfield', [v_result, c_item1, v_hash])
+            return v_result
         elif hop.r_result.lowleveltype == lltype.Void:
             return hop.inputconst(lltype.Void, None)
         else:
-            assert variant == 'items' or variant == 'keys_with_hash'
+            assert variant == 'items' or variant == 'items_with_hash'
             ITEM0 = v_result.concretetype.TO.item0
             ITEM1 = v_result.concretetype.TO.item1
             if ITEM0 != v_key.concretetype:
@@ -125,4 +135,7 @@
             c_item1 = hop.inputconst(lltype.Void, 'item1')
             hop.genop('setfield', [v_result, c_item0, v_key])
             hop.genop('setfield', [v_result, c_item1, v_value])
+            if variant == 'items_with_hash':
+                c_item2 = hop.inputconst(lltype.Void, 'item2')
+                hop.genop('setfield', [v_result, c_item2, v_hash])
             return v_result


More information about the pypy-commit mailing list