Author: Armin Rigo <ar...@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)) + +@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit