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