[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