[pypy-commit] pypy all_ordered_dicts: Trying to finish this, using a slightly sub-efficient __iter__() method.

arigo noreply at buildbot.pypy.org
Mon Dec 22 12:19:54 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: all_ordered_dicts
Changeset: r75055:c07c71e5d2be
Date: 2014-12-22 12:19 +0100
http://bitbucket.org/pypy/pypy/changeset/c07c71e5d2be/

Log:	Trying to finish this, using a slightly sub-efficient __iter__()
	method. Too bad I suppose; the speed-up gained by using the
	simplified OrderedDict class should largely make up for it.

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
@@ -29,25 +29,33 @@
 ################################################################################
 
 class OrderedDict(dict):
-    'Dictionary that remembers insertion order'
-    # An inherited dict maps keys to values.
-    # The inherited dict provides __getitem__, __len__, __contains__, and get.
-    # The remaining methods are order-aware.
-    # Big-O running times for all methods are the same as regular dictionaries.
+    '''Dictionary that remembers insertion order.
 
-    # XXX FIX THIS COMMENT
-    # The internal self.__map dict maps keys to links in a doubly linked list.
-    # The circular doubly linked list starts and ends with a sentinel element.
-    # The sentinel element never gets deleted (this simplifies the algorithm).
-    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
+    In PyPy all dicts are ordered anyway.  This is mostly useful as a
+    placeholder to mean "this dict must be ordered even on CPython.'''
 
     def __iter__(self):
-        for x in self._pypy_mut_safe_iter():
-            yield x
+        # This method allows some concurrent changes to the dictionary
+        # while iterating.  The annoying part is that the exact allowed
+        # changes are messy to define and different than CPython's own
+        # messy definition (which the docs have nothing to say about).
+        # For now, we'll suppose it is good enough.  Precisely: we
+        # iterate over the list of keys grabbed at the start; we return
+        # all keys that are still in the dictionary at the time we
+        # reach them.  This is a simple rule, but if a key is deleted
+        # and re-added, this method will return it in its old position,
+        # which is arguably wrong.  Also, any newly-added key is never
+        # returned, unlike CPython (which usually returns them, but not
+        # always).
+        for k in dict.keys(self):
+            if k in self:
+                yield k
 
     def __reversed__(self):
         'od.__reversed__() <==> reversed(od)'
-        return XXX
+        for k in reversed(dict.keys(self)):
+            if k in self:
+                yield k
 
     def iterkeys(self):
         'od.iterkeys() -> an iterator over the keys in od'
@@ -71,9 +79,11 @@
         if last:
             return dict.popitem(self)
         else:
-            if not self:
+            it = dict.__iter__(self)
+            try:
+                k = it.next()
+            except StopIteration:
                 raise KeyError('dictionary is empty')
-            k = iter(self).next()
             return (k, self.pop(k))
 
     def __repr__(self, _repr_running={}):


More information about the pypy-commit mailing list