[pypy-commit] pypy all_ordered_dicts: Implement __pypy__.reversed_dict()

arigo noreply at buildbot.pypy.org
Tue Jan 13 18:40:58 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: all_ordered_dicts
Changeset: r75317:d6780844383e
Date: 2015-01-13 18:40 +0100
http://bitbucket.org/pypy/pypy/changeset/d6780844383e/

Log:	Implement __pypy__.reversed_dict()

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
@@ -78,6 +78,7 @@
         'newlist_hint'              : 'interp_magic.newlist_hint',
         'add_memory_pressure'       : 'interp_magic.add_memory_pressure',
         'newdict'                   : 'interp_dict.newdict',
+        'reversed_dict'             : 'interp_dict.reversed_dict',
         'strategy'                  : 'interp_magic.strategy',  # dict,set,list
         'set_debug'                 : 'interp_magic.set_debug',
         'locals_to_fast'            : 'interp_magic.locals_to_fast',
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
@@ -30,3 +30,9 @@
         return space.newdict(strdict=True)
     else:
         raise oefmt(space.w_TypeError, "unknown type of dict %s", type)
+
+def reversed_dict(space, w_obj):
+    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_reversed_dict(space)
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
@@ -258,6 +258,17 @@
         """D.itervalues() -> an iterator over the values of D"""
         return W_DictMultiIterValuesObject(space, self.itervalues())
 
+    def nondescr_reversed_dict(self, space):
+        """Not exposed directly to app-level, but via __pypy__.reversed_dict().
+        """
+        if self.strategy.getiterreversed is not None:
+            it = self.strategy.iterreversed(self)
+            return W_DictMultiIterKeysObject(space, it)
+        else:
+            # fall-back
+            w_keys = self.w_keys()
+            return space.call_method(w_keys, '__reversed__')
+
     def descr_viewitems(self, space):
         """D.viewitems() -> a set-like object providing a view on D's items"""
         return W_DictViewItemsObject(space, self)
@@ -501,6 +512,8 @@
     def getiteritems(self, w_dict):
         raise NotImplementedError
 
+    getiterreversed = None    # means no implementation is available
+
     def rev_update1_dict_dict(self, w_dict, w_updatedict):
         iteritems = self.iteritems(w_dict)
         while True:
@@ -621,6 +634,9 @@
     def getiteritems(self, w_dict):
         return iter([])
 
+    def getiterreversed(self, w_dict):
+        return iter([])
+
 
 # Iterator Implementation base classes
 
@@ -709,10 +725,6 @@
             'setitem_untyped_%s' % dictimpl.__name__)
 
     class IterClassKeys(BaseKeyIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getiterkeys(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
-
         def next_key_entry(self):
             for key in self.iterator:
                 return wrapkey(self.space, key)
@@ -720,10 +732,6 @@
                 return None
 
     class IterClassValues(BaseValueIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getitervalues(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
-
         def next_value_entry(self):
             for value in self.iterator:
                 return wrapvalue(self.space, value)
@@ -731,10 +739,6 @@
                 return None
 
     class IterClassItems(BaseItemIterator):
-        def __init__(self, space, strategy, impl):
-            self.iterator = strategy.getiteritems(impl)
-            BaseIteratorImplementation.__init__(self, space, strategy, impl)
-
         if override_next_item is not None:
             next_item_entry = override_next_item
         else:
@@ -746,13 +750,26 @@
                     return None, None
 
     def iterkeys(self, w_dict):
-        return IterClassKeys(self.space, self, w_dict)
+        it = IterClassKeys(self.space, self, w_dict)
+        it.iterator = self.getiterkeys(w_dict)
+        return it
 
     def itervalues(self, w_dict):
-        return IterClassValues(self.space, self, w_dict)
+        it = IterClassValues(self.space, self, w_dict)
+        it.iterator = self.getitervalues(w_dict)
+        return it
 
     def iteritems(self, w_dict):
-        return IterClassItems(self.space, self, w_dict)
+        it = IterClassItems(self.space, self, w_dict)
+        it.iterator = self.getiteritems(w_dict)
+        return it
+
+    if dictimpl.getiterreversed is not None:
+        def iterreversed(self, w_dict):
+            it = IterClassKeys(self.space, self, w_dict)
+            it.iterator = self.getiterreversed(w_dict)
+            return it
+        dictimpl.iterreversed = iterreversed
 
     @jit.look_inside_iff(lambda self, w_dict, w_updatedict:
                          w_dict_unrolling_heuristic(w_dict))
@@ -763,6 +780,7 @@
             # this is very similar to the general version, but the difference
             # is that it is specialized to call a specific next_item()
             iteritems = IterClassItems(self.space, self, w_dict)
+            iteritems.iterator = self.getiteritems(w_dict)
             w_key, w_value = iteritems.next_item()
             if w_key is None:
                 return
@@ -930,6 +948,9 @@
     def getiteritems(self, w_dict):
         return self.unerase(w_dict.dstorage).iteritems()
 
+    def getiterreversed(self, w_dict):
+        return objectmodel.reversed_dict(self.unerase(w_dict.dstorage))
+
     def prepare_update(self, w_dict, num_extra):
         objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage),
                                         num_extra)
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
@@ -254,6 +254,12 @@
             values.append(k)
         assert values == d.values()
 
+    def test_reversed_dict(self):
+        import __pypy__
+        for d in [{}, {1: 2, 3: 4, 5: 6}, {"a": 5, "b": 2, "c": 6}]:
+            assert list(__pypy__.reversed_dict(d)) == d.keys()[::-1]
+        raises(TypeError, __pypy__.reversed_dict, 42)
+
     def test_keys(self):
         d = {1: 2, 3: 4}
         kys = d.keys()
diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py
--- a/pypy/objspace/std/test/test_mapdict.py
+++ b/pypy/objspace/std/test/test_mapdict.py
@@ -700,6 +700,15 @@
         del a.x
         raises(AttributeError, "a.x")
 
+    def test_reversed_dict(self):
+        import __pypy__
+        class X(object):
+            pass
+        x = X(); x.a = 10; x.b = 20; x.c = 30
+        d = x.__dict__
+        assert list(__pypy__.reversed_dict(d)) == d.keys()[::-1]
+
+
 class AppTestWithMapDictAndCounters(object):
     spaceconfig = {"objspace.std.withmapdict": True,
                    "objspace.std.withmethodcachecounter": True}


More information about the pypy-commit mailing list