[pypy-commit] pypy speedup-unpackiterable: a major refactor - try to have different classes for iterkeys/itervalues/iteritems

fijal noreply at buildbot.pypy.org
Fri Jul 13 01:25:49 CEST 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: speedup-unpackiterable
Changeset: r56051:b08585390218
Date: 2012-07-13 01:25 +0200
http://bitbucket.org/pypy/pypy/changeset/b08585390218/

Log:	a major refactor - try to have different classes for
	iterkeys/itervalues/iteritems

diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -4,7 +4,7 @@
 """
 
 from pypy.interpreter.baseobjspace import W_Root
-from pypy.objspace.std.dictmultiobject import IteratorImplementation
+from pypy.objspace.std.dictmultiobject import create_itertor_classes
 from pypy.objspace.std.dictmultiobject import DictStrategy, _never_equal_to_string
 from pypy.objspace.std.dictmultiobject import ObjectDictStrategy
 from pypy.rlib import jit, rerased
@@ -124,9 +124,6 @@
         w_res = self.getdictvalue_no_unwrapping(w_dict, key)
         return unwrap_cell(w_res)
 
-    def iter(self, w_dict):
-        return ModuleDictIteratorImplementation(self.space, self, w_dict)
-
     def w_keys(self, w_dict):
         space = self.space
         l = self.unerase(w_dict.dstorage).keys()
@@ -161,15 +158,15 @@
         w_dict.strategy = strategy
         w_dict.dstorage = strategy.erase(d_new)
 
-class ModuleDictIteratorImplementation(IteratorImplementation):
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(
-            self, space, strategy, dictimplementation)
-        dict_w = strategy.unerase(dictimplementation.dstorage)
-        self.iterator = dict_w.iteritems()
+    def getiterkeys(self, w_dict):
+        return self.unerase(w_dict.dstorage).iterkeys()
+    def getitervalues(self, w_dict):
+        return self.unerase(w_dict.dstorage).itervalues()
+    def getiteritems(self, w_dict):
+        return self.unerase(w_dict.dstorage).iteritems()
+    def wrapkey(space, key):
+        return space.wrap(key)
+    def wrapvalue(space, value):
+        return unwrap_cell(value)
 
-    def next_entry(self):
-        for key, cell in self.iterator:
-            return (self.space.wrap(key), unwrap_cell(cell))
-        else:
-            return None, None
+create_itertor_classes(ModuleDictStrategy)
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
@@ -7,8 +7,10 @@
 from pypy.interpreter.argument import Signature
 from pypy.interpreter.error import OperationError, operationerrfmt
 
-from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize
+from pypy.rlib.objectmodel import r_dict, we_are_translated, specialize,\
+     newlist_hint
 from pypy.rlib.debug import mark_dict_non_null
+from pypy.tool.sourcetools import func_with_new_name
 
 from pypy.rlib import rerased
 
@@ -94,7 +96,7 @@
     dict_methods = "setitem setitem_str getitem \
                     getitem_str delitem length \
                     clear w_keys values \
-                    items iter setdefault \
+                    items iterkeys itervalues iteritems setdefault \
                     popitem listview_str listview_int \
                     view_as_kwargs".split()
 
@@ -118,30 +120,30 @@
         raise NotImplementedError
 
     def w_keys(self, w_dict):
-        iterator = self.iter(w_dict)
-        result = []
+        iterator = self.iterkeys(w_dict)
+        result = newlist_hint(self.length(w_dict))
         while 1:
-            w_key, w_value = iterator.next()
+            w_key = iterator.next_key()
             if w_key is not None:
                 result.append(w_key)
             else:
                 return self.space.newlist(result)
 
     def values(self, w_dict):
-        iterator = self.iter(w_dict)
-        result = []
+        iterator = self.itervalues(w_dict)
+        result = newlist_hint(self.length(w_dict))
         while 1:
-            w_key, w_value = iterator.next()
+            w_value = iterator.next_value()
             if w_value is not None:
                 result.append(w_value)
             else:
                 return result
 
     def items(self, w_dict):
-        iterator = self.iter(w_dict)
-        result = []
+        iterator = self.iteritems(w_dict)
+        result = newlist_hint(self.length(w_dict))
         while 1:
-            w_key, w_value = iterator.next()
+            w_key, w_value = iterator.next_item()
             if w_key is not None:
                 result.append(self.space.newtuple([w_key, w_value]))
             else:
@@ -153,8 +155,8 @@
         # will take longer and longer.  But all interesting strategies
         # provide a better one.
         space = self.space
-        iterator = self.iter(w_dict)
-        w_key, w_value = iterator.next()
+        iterator = self.iteritems(w_dict)
+        w_key, w_value = iterator.next_item()
         self.delitem(w_dict, w_key)
         return (w_key, w_value)
 
@@ -253,9 +255,6 @@
     def length(self, w_dict):
         return 0
 
-    def iter(self, w_dict):
-        return EmptyIteratorImplementation(self.space, self, w_dict)
-
     def clear(self, w_dict):
         return
 
@@ -265,31 +264,32 @@
     def view_as_kwargs(self, w_dict):
         return ([], [])
 
-registerimplementation(W_DictMultiObject)
+    # ---------- iterator interface ----------------
 
-# DictImplementation lattice
-# XXX fix me
+    def getiterkeys(self, w_dict):
+        return iter([None])
+    getitervalues = getiterkeys
+    def getiteritems(self, w_dict):
+        return iter([(None, None)])
 
 # Iterator Implementation base classes
 
-class IteratorImplementation(object):
-    def __init__(self, space, strategy, implementation):
-        self.space = space
-        self.strategy = strategy
-        self.dictimplementation = implementation
-        self.len = implementation.length()
-        self.pos = 0
-
+def _new_next(TP):
+    if TP == 'key' or TP == 'value':
+        EMPTY = None
+    else:
+        EMPTY = None, None
+    
     def next(self):
         if self.dictimplementation is None:
-            return None, None
+            return EMPTY
         if self.len != self.dictimplementation.length():
             self.len = -1   # Make this error state sticky
             raise OperationError(self.space.w_RuntimeError,
                      self.space.wrap("dictionary changed size during iteration"))
         # look for the next entry
         if self.pos < self.len:
-            result = self.next_entry()
+            result = getattr(self, 'next_' + TP + '_entry')()
             self.pos += 1
             if self.strategy is self.dictimplementation.strategy:
                 return result      # common case
@@ -298,31 +298,112 @@
                 # length of the dict.  The (key, value) pair in 'result'
                 # might be out-of-date.  We try to explicitly look up
                 # the key in the dict.
+                if TP == 'key':
+                    return result[0]
                 w_key = result[0]
                 w_value = self.dictimplementation.getitem(w_key)
                 if w_value is None:
                     self.len = -1   # Make this error state sticky
                     raise OperationError(self.space.w_RuntimeError,
                         self.space.wrap("dictionary changed during iteration"))
-                return (w_key, w_value)
+                if TP == 'value':
+                    return w_value
+                elif TP == 'item':
+                    return (w_key, w_value)
+                else:
+                    assert False # unreachable code
         # no more entries
         self.dictimplementation = None
-        return None, None
+        return EMPTY
+    return func_with_new_name(next, 'next_' + TP)
 
-    def next_entry(self):
-        """ Purely abstract method
-        """
-        raise NotImplementedError
+class BaseIteratorImplementation(object):
+    def __init__(self, space, strategy, implementation):
+        self.space = space
+        self.strategy = strategy
+        self.dictimplementation = implementation
+        self.len = implementation.length()
+        self.pos = 0
 
     def length(self):
         if self.dictimplementation is not None:
             return self.len - self.pos
         return 0
 
-class EmptyIteratorImplementation(IteratorImplementation):
-    def next(self):
-        return (None, None)
+class BaseKeyIterator(BaseIteratorImplementation):
+    next_key = _new_next('key')
 
+class BaseValueIterator(BaseIteratorImplementation):
+    next_value = _new_next('value')
+
+class BaseItemIterator(BaseIteratorImplementation):
+    next_item = _new_next('item')
+
+def create_itertor_classes(dictimpl, override_next_item=None):
+    if not hasattr(dictimpl, 'wrapkey'):
+        wrapkey = lambda space, key : key
+    else:
+        wrapkey = dictimpl.wrapkey.im_func
+    if not hasattr(dictimpl, 'wrapvalue'):
+        wrapvalue = lambda space, key : key
+    else:
+        wrapvalue = dictimpl.wrapvalue.im_func
+    
+    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)
+            else:
+                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)
+            else:
+                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:
+            def next_item_entry(self):
+                for key, value in self.iterator:
+                    return (wrapkey(self.space, key),
+                            wrapvalue(self.space, value))
+                else:
+                    return None, None
+
+    def iterkeys(self, w_dict):
+        return IterClassKeys(self.space, self, w_dict)
+
+    def itervalues(self, w_dict):
+        return IterClassValues(self.space, self, w_dict)
+
+    def iteritems(self, w_dict):
+        return IterClassItems(self.space, self, w_dict)
+    dictimpl.iterkeys = iterkeys
+    dictimpl.itervalues = itervalues
+    dictimpl.iteritems = iteritems
+
+create_itertor_classes(EmptyDictStrategy)
+
+registerimplementation(W_DictMultiObject)
+
+# DictImplementation lattice
+# XXX fix me
 
 
 # concrete subclasses of the above
@@ -429,6 +510,15 @@
         w_dict.strategy = strategy
         w_dict.dstorage = strategy.erase(d_new)
 
+    # --------------- iterator interface -----------------
+
+    def getiterkeys(self, w_dict):
+        return self.unerase(w_dict.dstorage).iterkeys()
+    def getitervalues(self, w_dict):
+        return self.unerase(w_dict.dstorage).itervalues()
+    def getiteritems(self, w_dict):
+        return self.unerase(w_dict.dstorage).iteritems()
+
 class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy):
 
     erase, unerase = rerased.new_erasing_pair("object")
@@ -452,12 +542,10 @@
     def _never_equal_to(self, w_lookup_type):
         return False
 
-    def iter(self, w_dict):
-        return ObjectIteratorImplementation(self.space, self, w_dict)
-
     def w_keys(self, w_dict):
         return self.space.newlist(self.unerase(w_dict.dstorage).keys())
 
+create_itertor_classes(ObjectDictStrategy)
 
 class StringDictStrategy(AbstractTypedStrategy, DictStrategy):
 
@@ -502,44 +590,14 @@
     def listview_str(self, w_dict):
         return self.unerase(w_dict.dstorage).keys()
 
-    def iter(self, w_dict):
-        return StrIteratorImplementation(self.space, self, w_dict)
-
     def w_keys(self, w_dict):
         return self.space.newlist_str(self.listview_str(w_dict))
 
+    def wrapkey(space, key):
+        return space.wrap(key)
 
-class _WrappedIteratorMixin(object):
-    _mixin_ = True
+create_itertor_classes(StringDictStrategy)
 
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(self, space, strategy, dictimplementation)
-        self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems()
-
-    def next_entry(self):
-        # note that this 'for' loop only runs once, at most
-        for key, w_value in self.iterator:
-            return self.space.wrap(key), w_value
-        else:
-            return None, None
-
-class _UnwrappedIteratorMixin:
-    _mixin_ = True
-
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(self, space, strategy, dictimplementation)
-        self.iterator = strategy.unerase(dictimplementation.dstorage).iteritems()
-
-    def next_entry(self):
-        # note that this 'for' loop only runs once, at most
-        for w_key, w_value in self.iterator:
-            return w_key, w_value
-        else:
-            return None, None
-
-
-class StrIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation):
-    pass
 
 class IntDictStrategy(AbstractTypedStrategy, DictStrategy):
     erase, unerase = rerased.new_erasing_pair("int")
@@ -567,19 +625,15 @@
                 space.is_w(w_lookup_type, space.w_unicode)
                 )
 
-    def iter(self, w_dict):
-        return IntIteratorImplementation(self.space, self, w_dict)
-
     def listview_int(self, w_dict):
         return self.unerase(w_dict.dstorage).keys()
 
+    def wrapkey(space, key):
+        return space.wrap(key)
+
     # XXX there is no space.newlist_int yet to implement w_keys more efficiently
 
-class IntIteratorImplementation(_WrappedIteratorMixin, IteratorImplementation):
-    pass
-
-class ObjectIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation):
-    pass
+create_itertor_classes(IntDictStrategy)
 
 init_signature = Signature(['seq_or_map'], None, 'kwargs')
 init_defaults = [None]
@@ -605,9 +659,9 @@
                 w_dict.setitem(w_key, w_value)
 
 def update1_dict_dict(space, w_dict, w_data):
-    iterator = w_data.iter()
+    iterator = w_data.iteritems()
     while 1:
-        w_key, w_value = iterator.next()
+        w_key, w_value = iterator.next_item()
         if w_key is None:
             break
         w_dict.setitem(w_key, w_value)
@@ -657,7 +711,7 @@
 dict_has_key__DictMulti_ANY = contains__DictMulti_ANY
 
 def iter__DictMulti(space, w_dict):
-    return W_DictMultiIterObject(space, w_dict.iter(), KEYSITER)
+    return W_DictMultiIterKeysObject(space, w_dict.iterkeys())
 
 def eq__DictMulti_DictMulti(space, w_left, w_right):
     if space.is_w(w_left, w_right):
@@ -665,9 +719,9 @@
 
     if w_left.length() != w_right.length():
         return space.w_False
-    iteratorimplementation = w_left.iter()
+    iteratorimplementation = w_left.iteritems()
     while 1:
-        w_key, w_val = iteratorimplementation.next()
+        w_key, w_val = iteratorimplementation.next_item()
         if w_key is None:
             break
         w_rightval = w_right.getitem(w_key)
@@ -682,9 +736,9 @@
     returns the smallest key in acontent for which b's value is different or absent and this value """
     w_smallest_diff_a_key = None
     w_its_value = None
-    iteratorimplementation = w_a.iter()
+    iteratorimplementation = w_a.iteritems()
     while 1:
-        w_key, w_val = iteratorimplementation.next()
+        w_key, w_val = iteratorimplementation.next_item()
         if w_key is None:
             break
         if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)):
@@ -735,13 +789,13 @@
     return space.newlist(w_self.values())
 
 def dict_iteritems__DictMulti(space, w_self):
-    return W_DictMultiIterObject(space, w_self.iter(), ITEMSITER)
+    return W_DictMultiIterItemsObject(space, w_self.iteritems())
 
 def dict_iterkeys__DictMulti(space, w_self):
-    return W_DictMultiIterObject(space, w_self.iter(), KEYSITER)
+    return W_DictMultiIterKeysObject(space, w_self.iterkeys())
 
 def dict_itervalues__DictMulti(space, w_self):
-    return W_DictMultiIterObject(space, w_self.iter(), VALUESITER)
+    return W_DictMultiIterValuesObject(space, w_self.itervalues())
 
 def dict_viewitems__DictMulti(space, w_self):
     return W_DictViewItemsObject(space, w_self)
@@ -794,38 +848,73 @@
 # Iteration
 
 
-KEYSITER = 0
-ITEMSITER = 1
-VALUESITER = 2
-
-class W_DictMultiIterObject(W_Object):
+class W_DictMultiIterKeysObject(W_Object):
     from pypy.objspace.std.dicttype import dictiter_typedef as typedef
 
-    _immutable_fields_ = ["iteratorimplementation", "itertype"]
+    _immutable_fields_ = ["iteratorimplementation"]
 
-    def __init__(w_self, space, iteratorimplementation, itertype):
+    ignore_for_isinstance_cache = True
+
+    def __init__(w_self, space, iteratorimplementation):
         w_self.space = space
         w_self.iteratorimplementation = iteratorimplementation
-        w_self.itertype = itertype
 
-registerimplementation(W_DictMultiIterObject)
+registerimplementation(W_DictMultiIterKeysObject)
 
-def iter__DictMultiIterObject(space, w_dictiter):
+class W_DictMultiIterValuesObject(W_Object):
+    from pypy.objspace.std.dicttype import dictiter_typedef as typedef
+
+    _immutable_fields_ = ["iteratorimplementation"]
+
+    ignore_for_isinstance_cache = True
+
+    def __init__(w_self, space, iteratorimplementation):
+        w_self.space = space
+        w_self.iteratorimplementation = iteratorimplementation
+
+registerimplementation(W_DictMultiIterValuesObject)
+
+class W_DictMultiIterItemsObject(W_Object):
+    from pypy.objspace.std.dicttype import dictiter_typedef as typedef
+
+    _immutable_fields_ = ["iteratorimplementation"]
+
+    ignore_for_isinstance_cache = True
+
+    def __init__(w_self, space, iteratorimplementation):
+        w_self.space = space
+        w_self.iteratorimplementation = iteratorimplementation
+
+registerimplementation(W_DictMultiIterItemsObject)
+
+def iter__DictMultiIterKeysObject(space, w_dictiter):
     return w_dictiter
 
-def next__DictMultiIterObject(space, w_dictiter):
+def next__DictMultiIterKeysObject(space, w_dictiter):
     iteratorimplementation = w_dictiter.iteratorimplementation
-    w_key, w_value = iteratorimplementation.next()
+    w_key = iteratorimplementation.next_key()
     if w_key is not None:
-        itertype = w_dictiter.itertype
-        if itertype == KEYSITER:
-            return w_key
-        elif itertype == VALUESITER:
-            return w_value
-        elif itertype == ITEMSITER:
-            return space.newtuple([w_key, w_value])
-        else:
-            assert 0, "should be unreachable"
+        return w_key
+    raise OperationError(space.w_StopIteration, space.w_None)
+
+def iter__DictMultiIterValuesObject(space, w_dictiter):
+    return w_dictiter
+
+def next__DictMultiIterValuesObject(space, w_dictiter):
+    iteratorimplementation = w_dictiter.iteratorimplementation
+    w_value = iteratorimplementation.next_value()
+    if w_value is not None:
+        return w_value
+    raise OperationError(space.w_StopIteration, space.w_None)
+
+def iter__DictMultiIterItemsObject(space, w_dictiter):
+    return w_dictiter
+
+def next__DictMultiIterItemsObject(space, w_dictiter):
+    iteratorimplementation = w_dictiter.iteratorimplementation
+    w_key, w_value = iteratorimplementation.next_item()
+    if w_key is not None:
+        return space.newtuple([w_key, w_value])
     raise OperationError(space.w_StopIteration, space.w_None)
 
 # ____________________________________________________________
@@ -860,7 +949,6 @@
 
 def all_contained_in(space, w_dictview, w_otherview):
     w_iter = space.iter(w_dictview)
-    assert isinstance(w_iter, W_DictMultiIterObject)
 
     while True:
         try:
diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py
--- a/pypy/objspace/std/dictproxyobject.py
+++ b/pypy/objspace/std/dictproxyobject.py
@@ -1,6 +1,6 @@
 from pypy.objspace.std.model import registerimplementation, W_Object
 from pypy.objspace.std.register_all import register_all
-from pypy.objspace.std.dictmultiobject import W_DictMultiObject, IteratorImplementation
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject, create_itertor_classes
 from pypy.objspace.std.dictmultiobject import DictStrategy
 from pypy.objspace.std.typeobject import unwrap_cell
 from pypy.interpreter.error import OperationError, operationerrfmt
@@ -81,9 +81,6 @@
     def length(self, w_dict):
         return len(self.unerase(w_dict.dstorage).dict_w)
 
-    def iter(self, w_dict):
-        return DictProxyIteratorImplementation(self.space, self, w_dict)
-
     def keys(self, w_dict):
         space = self.space
         return space.newlist_str(self.unerase(w_dict.dstorage).dict_w.keys())
@@ -106,15 +103,15 @@
         w_type.dict_w.clear()
         w_type.mutated(None)
 
-class DictProxyIteratorImplementation(IteratorImplementation):
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(
-            self, space, strategy, dictimplementation)
-        w_type = strategy.unerase(dictimplementation.dstorage)
-        self.iterator = w_type.dict_w.iteritems()
+    def getiterkeys(self, w_dict):
+        return self.unerase(w_dict.dstorage).dict_w.iterkeys()
+    def getitervalues(self, w_dict):
+        return self.unerase(w_dict.dstorage).dict_w.itervalues()
+    def getiteritems(self, w_dict):
+        return self.unerase(w_dict.dstorage).dict_w.iteritems()
+    def wrapkey(space, key):
+        return space.wrap(key)
+    def wrapvalue(space, value):
+        return unwrap_cell(space, value)
 
-    def next_entry(self):
-        for key, w_value in self.iterator:
-            return (self.space.wrap(key), unwrap_cell(self.space, w_value))
-        else:
-            return (None, None)
+create_itertor_classes(DictProxyStrategy)
diff --git a/pypy/objspace/std/identitydict.py b/pypy/objspace/std/identitydict.py
--- a/pypy/objspace/std/identitydict.py
+++ b/pypy/objspace/std/identitydict.py
@@ -5,8 +5,7 @@
 from pypy.rlib.debug import mark_dict_non_null
 from pypy.objspace.std.dictmultiobject import (AbstractTypedStrategy,
                                                DictStrategy,
-                                               IteratorImplementation,
-                                               _UnwrappedIteratorMixin)
+                                               create_itertor_classes)
 
 
 # this strategy is selected by EmptyDictStrategy.switch_to_correct_strategy
@@ -77,12 +76,7 @@
     def _never_equal_to(self, w_lookup_type):
         return False
 
-    def iter(self, w_dict):
-        return IdentityDictIteratorImplementation(self.space, self, w_dict)
-
     def w_keys(self, w_dict):
         return self.space.newlist(self.unerase(w_dict.dstorage).keys())
 
-
-class IdentityDictIteratorImplementation(_UnwrappedIteratorMixin, IteratorImplementation):
-    pass
+create_itertor_classes(IdentityDictStrategy)
diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py
--- a/pypy/objspace/std/kwargsdict.py
+++ b/pypy/objspace/std/kwargsdict.py
@@ -3,7 +3,7 @@
 
 from pypy.rlib import rerased, jit
 from pypy.objspace.std.dictmultiobject import (DictStrategy,
-                                               IteratorImplementation,
+                                               create_itertor_classes,
                                                ObjectDictStrategy,
                                                StringDictStrategy)
 
@@ -30,9 +30,6 @@
     def _never_equal_to(self, w_lookup_type):
         return False
 
-    def iter(self, w_dict):
-        return KwargsDictIterator(self.space, self, w_dict)
-
     def w_keys(self, w_dict):
         return self.space.newlist([self.space.wrap(key) for key in self.unerase(w_dict.dstorage)[0]])
 
@@ -147,19 +144,22 @@
     def view_as_kwargs(self, w_dict):
         return self.unerase(w_dict.dstorage)
 
+    def getiterkeys(self, w_dict):
+        return self.unerase(w_dict.dstorage)[0]
+    def getitervalues(self, w_dict):
+        return self.unerase(w_dict.dstorage)[1]
+    def getiteritems(self, w_dict):
+        keys = self.unerase(w_dict.dstorage)[0]
+        return iter(range(len(keys)))
+    def wrapkey(space, key):
+        return space.wrap(key)
 
-class KwargsDictIterator(IteratorImplementation):
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(self, space, strategy, dictimplementation)
-        keys, values_w = strategy.unerase(self.dictimplementation.dstorage)
-        self.iterator = iter(range(len(keys)))
-        # XXX this potentially leaks
-        self.keys = keys
-        self.values_w = values_w
+def next_item(self):
+    for i in self.iterator:
+        keys, values_w = self.strategy.unerase(
+            self.dictimplementation.dstorage)
+        return self.space.wrap(keys[i]), values_w[i]
+    else:
+        return None, None
 
-    def next_entry(self):
-        # note that this 'for' loop only runs once, at most
-        for i in self.iterator:
-            return self.space.wrap(self.keys[i]), self.values_w[i]
-        else:
-            return None, None
+create_itertor_classes(KwargsDictStrategy, override_next_item=next_item)
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -5,7 +5,7 @@
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy
-from pypy.objspace.std.dictmultiobject import IteratorImplementation
+from pypy.objspace.std.dictmultiobject import BaseKeyIterator, BaseValueIterator, BaseItemIterator
 from pypy.objspace.std.dictmultiobject import _never_equal_to_string
 from pypy.objspace.std.objectobject import W_ObjectObject
 from pypy.objspace.std.typeobject import TypeCell
@@ -676,9 +676,6 @@
             res += 1
         return res
 
-    def iter(self, w_dict):
-        return MapDictIteratorImplementation(self.space, self, w_dict)
-
     def clear(self, w_dict):
         w_obj = self.unerase(w_dict.dstorage)
         new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj)
@@ -696,32 +693,83 @@
 
     # XXX could implement a more efficient w_keys based on space.newlist_str
 
+    def iterkeys(self, w_dict):
+        return MapDictIteratorKeys(self.space, self, w_dict)
+    def itervalues(self, w_dict):
+        return MapDictIteratorValues(self.space, self, w_dict)
+    def iteritems(self, w_dict):
+        return MapDictIteratorItems(self.space, self, w_dict)
+    
+
 def materialize_r_dict(space, obj, dict_w):
     map = obj._get_mapdict_map()
     new_obj = map.materialize_r_dict(space, obj, dict_w)
     _become(obj, new_obj)
 
-class MapDictIteratorImplementation(IteratorImplementation):
-    def __init__(self, space, strategy, dictimplementation):
-        IteratorImplementation.__init__(
-            self, space, strategy, dictimplementation)
-        w_obj = strategy.unerase(dictimplementation.dstorage)
-        self.w_obj = w_obj
-        self.orig_map = self.curr_map = w_obj._get_mapdict_map()
+class MapDictIteratorKeys(BaseKeyIterator):
+     def __init__(self, space, strategy, dictimplementation):
+         BaseKeyIterator.__init__(
+             self, space, strategy, dictimplementation)
+         w_obj = strategy.unerase(dictimplementation.dstorage)
+         self.w_obj = w_obj
+         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
 
-    def next_entry(self):
-        implementation = self.dictimplementation
-        assert isinstance(implementation.strategy, MapDictStrategy)
-        if self.orig_map is not self.w_obj._get_mapdict_map():
-            return None, None
-        if self.curr_map:
-            curr_map = self.curr_map.search(DICT)
-            if curr_map:
-                self.curr_map = curr_map.back
-                attr = curr_map.selector[0]
-                w_attr = self.space.wrap(attr)
-                return w_attr, self.w_obj.getdictvalue(self.space, attr)
-        return None, None
+     def next_key_entry(self):
+         implementation = self.dictimplementation
+         assert isinstance(implementation.strategy, MapDictStrategy)
+         if self.orig_map is not self.w_obj._get_mapdict_map():
+             return None
+         if self.curr_map:
+             curr_map = self.curr_map.search(DICT)
+             if curr_map:
+                 self.curr_map = curr_map.back
+                 attr = curr_map.selector[0]
+                 w_attr = self.space.wrap(attr)
+                 return w_attr
+         return None
+
+class MapDictIteratorValues(BaseValueIterator):
+     def __init__(self, space, strategy, dictimplementation):
+         BaseValueIterator.__init__(
+             self, space, strategy, dictimplementation)
+         w_obj = strategy.unerase(dictimplementation.dstorage)
+         self.w_obj = w_obj
+         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
+
+     def next_value_entry(self):
+         implementation = self.dictimplementation
+         assert isinstance(implementation.strategy, MapDictStrategy)
+         if self.orig_map is not self.w_obj._get_mapdict_map():
+             return None
+         if self.curr_map:
+             curr_map = self.curr_map.search(DICT)
+             if curr_map:
+                 self.curr_map = curr_map.back
+                 attr = curr_map.selector[0]
+                 return self.w_obj.getdictvalue(self.space, attr)
+         return None
+
+class MapDictIteratorItems(BaseItemIterator):
+     def __init__(self, space, strategy, dictimplementation):
+         BaseItemIterator.__init__(
+             self, space, strategy, dictimplementation)
+         w_obj = strategy.unerase(dictimplementation.dstorage)
+         self.w_obj = w_obj
+         self.orig_map = self.curr_map = w_obj._get_mapdict_map()
+
+     def next_item_entry(self):
+         implementation = self.dictimplementation
+         assert isinstance(implementation.strategy, MapDictStrategy)
+         if self.orig_map is not self.w_obj._get_mapdict_map():
+             return None, None
+         if self.curr_map:
+             curr_map = self.curr_map.search(DICT)
+             if curr_map:
+                 self.curr_map = curr_map.back
+                 attr = curr_map.selector[0]
+                 w_attr = self.space.wrap(attr)
+                 return w_attr, self.w_obj.getdictvalue(self.space, attr)
+         return None, None
 
 # ____________________________________________________________
 # Magic caching
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -102,7 +102,9 @@
             tupleobject.W_TupleObject: [],
             listobject.W_ListObject: [],
             dictmultiobject.W_DictMultiObject: [],
-            dictmultiobject.W_DictMultiIterObject: [],
+            dictmultiobject.W_DictMultiIterKeysObject: [],
+            dictmultiobject.W_DictMultiIterValuesObject: [],
+            dictmultiobject.W_DictMultiIterItemsObject: [],
             stringobject.W_StringObject: [],
             bytearrayobject.W_BytearrayObject: [],
             typeobject.W_TypeObject: [],
@@ -128,7 +130,9 @@
 
         self.imported_but_not_registered = {
             dictmultiobject.W_DictMultiObject: True, # XXXXXX
-            dictmultiobject.W_DictMultiIterObject: True,
+            dictmultiobject.W_DictMultiIterKeysObject: True,
+            dictmultiobject.W_DictMultiIterValuesObject: True,
+            dictmultiobject.W_DictMultiIterItemsObject: True,
             listobject.W_ListObject: True,
             stringobject.W_StringObject: True,
             tupleobject.W_TupleObject: True,
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
@@ -1035,10 +1035,10 @@
 
     def test_iter(self):
         self.fill_impl()
-        iteratorimplementation = self.impl.iter()
+        iteratorimplementation = self.impl.iteritems()
         items = []
         while 1:
-            item = iteratorimplementation.next()
+            item = iteratorimplementation.next_item()
             if item == (None, None):
                 break
             items.append(item)


More information about the pypy-commit mailing list