Author: Armin Rigo <[email protected]>
Branch:
Changeset: r90061:63aaa4e32c86
Date: 2017-02-12 09:24 +0100
http://bitbucket.org/pypy/pypy/changeset/63aaa4e32c86/
Log: Move OrderedDict.popitem() to interp-level as an attempt to increase
its multi-threaded resistence
diff --git a/lib-python/2.7/collections.py b/lib-python/2.7/collections.py
--- a/lib-python/2.7/collections.py
+++ b/lib-python/2.7/collections.py
@@ -33,6 +33,10 @@
from __pypy__ import reversed_dict as _reversed_dict
except ImportError:
_reversed_dict = None # don't have ordered dicts
+try:
+ from __pypy__ import dict_popitem_first as _dict_popitem_first
+except ImportError:
+ _dict_popitem_first = None
try:
from thread import get_ident as _get_ident
@@ -44,6 +48,17 @@
### OrderedDict
################################################################################
+if _dict_popitem_first is None:
+ def _dict_popitem_first(self):
+ it = dict.iteritems(self)
+ try:
+ k, v = it.next()
+ except StopIteration:
+ raise KeyError('dictionary is empty')
+ dict.__delitem__(self, k)
+ return (k, v)
+
+
class OrderedDict(dict):
'''Dictionary that remembers insertion order.
@@ -68,12 +83,7 @@
if last:
return dict.popitem(self)
else:
- it = dict.__iter__(self)
- try:
- k = it.next()
- except StopIteration:
- raise KeyError('dictionary is empty')
- return (k, self.pop(k))
+ return _dict_popitem_first(self)
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -79,6 +79,7 @@
'add_memory_pressure' : 'interp_magic.add_memory_pressure',
'newdict' : 'interp_dict.newdict',
'reversed_dict' : 'interp_dict.reversed_dict',
+ 'dict_popitem_first' : 'interp_dict.dict_popitem_first',
'delitem_if_value_is' : 'interp_dict.delitem_if_value_is',
'move_to_end' : 'interp_dict.move_to_end',
'strategy' : 'interp_magic.strategy', # dict,set,list
diff --git a/pypy/module/__pypy__/interp_dict.py
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -45,6 +45,14 @@
raise OperationError(space.w_TypeError, space.w_None)
return w_obj.nondescr_reversed_dict(space)
+def dict_popitem_first(space, w_obj):
+ """Interp-level implementation of OrderedDict.popitem(last=False).
+ """
+ from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+ if not isinstance(w_obj, W_DictMultiObject):
+ raise OperationError(space.w_TypeError, space.w_None)
+ return w_obj.nondescr_popitem_first(space)
+
def delitem_if_value_is(space, w_obj, w_key, w_value):
"""Atomic equivalent to: 'if dict.get(key) is value: del dict[key]'.
diff --git a/pypy/objspace/std/dictmultiobject.py
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -338,6 +338,15 @@
for i in range(len(keys_w)):
self.setitem(keys_w[i], values_w[i])
+ def nondescr_popitem_first(self, space):
+ """Not exposed directly to app-level, but via __pypy__.popitem_first().
+ """
+ w_key, w_value = self.iteritems().next_item()
+ if w_key is None:
+ raise oefmt(space.w_KeyError, "popitem(): dictionary is empty")
+ self.delitem(w_key)
+ return space.newtuple([w_key, w_value])
+
def descr_clear(self, space):
"""D.clear() -> None. Remove all items from D."""
self.clear()
@@ -604,8 +613,7 @@
has_iterreversed = False
has_move_to_end = False
- # no 'getiterreversed' and no 'move_to_end': no default
- # implementation available
+ # ^^^ no default implementation available for these methods
def rev_update1_dict_dict(self, w_dict, w_updatedict):
iteritems = self.iteritems(w_dict)
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py
b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -267,10 +267,22 @@
d = {1: 2, 3: 4, 5: 6}
it = __pypy__.reversed_dict(d)
key = it.next()
- assert key in [1, 3, 5]
+ assert key in [1, 3, 5] # on CPython, dicts are not ordered
del d[key]
raises(RuntimeError, it.next)
+ def test_dict_popitem_first(self):
+ import __pypy__
+ d = {"a": 5}
+ assert __pypy__.dict_popitem_first(d) == ("a", 5)
+ raises(KeyError, __pypy__.dict_popitem_first, d)
+
+ def kwdict(**k):
+ return k
+ d = kwdict(a=55)
+ assert __pypy__.dict_popitem_first(d) == ("a", 55)
+ raises(KeyError, __pypy__.dict_popitem_first, d)
+
def test_delitem_if_value_is(self):
import __pypy__
class X:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit