Author: Armin Rigo <[email protected]>
Branch:
Changeset: r89957:bfc27e0e9d42
Date: 2017-02-05 19:46 +0100
http://bitbucket.org/pypy/pypy/changeset/bfc27e0e9d42/
Log: Add objectmodel.delitem_if_value_is(), to be used next
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -575,6 +575,10 @@
pair(self, s_key).delitem()
method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror
+ def method_delitem_if_value_is(self, s_key, s_value):
+ pair(self, s_key).setitem(s_value)
+ pair(self, s_key).delitem()
+
class __extend__(SomeOrderedDict):
def method_move_to_end(self, s_key, s_last):
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -934,6 +934,20 @@
return
d.delitem_with_hash(key, h)
[email protected]_location()
+def delitem_if_value_is(d, key, value):
+ """Same as 'if d.get(key) is value: del d[key]'. It is safe even in
+ case 'd' is an r_dict and the lookup involves callbacks that might
+ release the GIL."""
+ if not we_are_translated():
+ try:
+ if d[key] is value:
+ del d[key]
+ except KeyError:
+ pass
+ return
+ d.delitem_if_value_is(key, value)
+
def _untranslated_move_to_end(d, key, last):
"NOT_RPYTHON"
value = d.pop(key)
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
@@ -7,7 +7,7 @@
resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
- fetch_translated_config, try_inline, move_to_end)
+ fetch_translated_config, try_inline, delitem_if_value_is, move_to_end)
from rpython.translator.translator import TranslationContext, graphof
from rpython.rtyper.test.tool import BaseRtypingTest
from rpython.rtyper.test.test_llinterp import interpret
@@ -661,6 +661,24 @@
f(29)
interpret(f, [27])
+def test_delitem_if_value_is():
+ class X:
+ pass
+ def f(i):
+ x42 = X()
+ x612 = X()
+ d = {i + .5: x42, i + .6: x612}
+ delitem_if_value_is(d, i + .5, x612)
+ assert (i + .5) in d
+ delitem_if_value_is(d, i + .5, x42)
+ assert (i + .5) not in d
+ delitem_if_value_is(d, i + .5, x612)
+ assert (i + .5) not in d
+ return 0
+
+ f(29)
+ interpret(f, [27])
+
def test_rdict_with_hash():
def f(i):
d = r_dict(strange_key_eq, strange_key_hash)
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
@@ -407,6 +407,12 @@
hop.exception_is_here()
hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash)
+ def rtype_method_delitem_if_value_is(self, hop):
+ v_dict, v_key, v_value = hop.inputargs(
+ self, self.key_repr, self.value_repr)
+ hop.exception_cannot_occur()
+ hop.gendirectcall(ll_dict_delitem_if_value_is, v_dict, v_key, v_value)
+
def rtype_method_move_to_end(self, hop):
v_dict, v_key, v_last = hop.inputargs(
self, self.key_repr, lltype.Bool)
@@ -821,6 +827,15 @@
raise KeyError
_ll_dict_del(d, hash, index)
+def ll_dict_delitem_if_value_is(d, key, value):
+ hash = d.keyhash(key)
+ index = d.lookup_function(d, key, hash, FLAG_LOOKUP)
+ if index < 0:
+ return
+ if d.entries[index].value != value:
+ return
+ _ll_dict_del(d, hash, index)
+
def _ll_dict_del_entry(d, index):
d.entries.mark_deleted(index)
d.num_live_items -= 1
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit