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

Reply via email to