[pypy-commit] pypy share-mapdict-methods: - try to reduce duplication of methods by putting a lot of the methods that
cfbolz
pypy.commits at gmail.com
Wed Apr 27 11:22:10 EDT 2016
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: share-mapdict-methods
Changeset: r83990:a1a3b6a39592
Date: 2016-04-27 18:13 +0300
http://bitbucket.org/pypy/pypy/changeset/a1a3b6a39592/
Log: - try to reduce duplication of methods by putting a lot of the
methods that mapdicts defines into W_Root. That way, the methods
aren't duplicated into every user-defined subclass.
- only inline five fields into the user-defined subclasses of
object, and all new-style classes
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -5,7 +5,7 @@
from rpython.rlib import jit, types
from rpython.rlib.debug import make_sure_not_resized
from rpython.rlib.objectmodel import (we_are_translated, newlist_hint,
- compute_unique_id, specialize)
+ compute_unique_id, specialize, import_from_mixin)
from rpython.rlib.signature import signature
from rpython.rlib.rarithmetic import r_uint, SHRT_MIN, SHRT_MAX, \
INT_MIN, INT_MAX, UINT_MAX, USHRT_MAX
@@ -16,6 +16,8 @@
from pypy.interpreter.argument import Arguments
from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary
+from pypy.objspace.std.basemapdictobject import RootObjectMapdictMixin
+
__all__ = ['ObjSpace', 'OperationError', 'W_Root']
@@ -30,8 +32,9 @@
__slots__ = ('__weakref__',)
user_overridden_class = False
- def getdict(self, space):
- return None
+ # a lot of the default functionality assumes mapdict now.
+ # import those methods
+ import_from_mixin(RootObjectMapdictMixin)
def getdictvalue(self, space, attr):
w_dict = self.getdict(space)
@@ -46,29 +49,18 @@
return True
return False
- def deldictvalue(self, space, attr):
- w_dict = self.getdict(space)
- if w_dict is not None:
- try:
- space.delitem(w_dict, space.wrap(attr))
- return True
- except OperationError, ex:
- if not ex.match(space, space.w_KeyError):
- raise
- return False
+ # deldictvalue, getdict, setdict are mixed in from basemapdictobject
+ # def deldictvalue(self, space, attrname):
+ # def getdict(self, space):
+ # def setdict(self, space, w_dict):
- def setdict(self, space, w_dict):
- raise oefmt(space.w_TypeError,
- "attribute '__dict__' of %T objects is not writable",
- self)
# to be used directly only by space.type implementations
def getclass(self, space):
return space.gettypeobject(self.typedef)
- def setclass(self, space, w_subtype):
- raise OperationError(space.w_TypeError,
- space.wrap("__class__ assignment: only for heap types"))
+ # setclass is mixed in from basemapdictobject
+ # def setclass(self, space, w_cls):
def user_setup(self, space, w_subtype):
raise NotImplementedError("only for interp-level user subclasses "
@@ -106,14 +98,10 @@
return space.wrap("<%s at 0x%s%s>" % (info, addrstring,
moreinfo))
- def getslotvalue(self, index):
- raise NotImplementedError
-
- def setslotvalue(self, index, w_val):
- raise NotImplementedError
-
- def delslotvalue(self, index):
- raise NotImplementedError
+ # mixed in from basemapdictobject are: getslotvalue, setslotvalue, delslotvalue
+ # def getslotvalue(self, index):
+ # def setslotvalue(self, index, w_val):
+ # def delslotvalue(self, slotindex):
def descr_call_mismatch(self, space, opname, RequiredClass, args):
if RequiredClass is None:
@@ -125,15 +113,10 @@
# used by _weakref implemenation
- def getweakref(self):
- return None
-
- def setweakref(self, space, weakreflifeline):
- raise oefmt(space.w_TypeError,
- "cannot create weak reference to '%T' object", self)
-
- def delweakref(self):
- pass
+ # mixed in from basemapdictobject are: getweakref, setweakref, delweakref
+ # def getweakref(self):
+ # def setweakref(self, space, weakreflifeline):
+ # def delweakref(self):
def clear_all_weakrefs(self):
"""Call this at the beginning of interp-level __del__() methods
@@ -171,19 +154,6 @@
self.__already_enqueued_for_destruction += (callback,)
space.user_del_action.register_callback(self, callback, descrname)
- # hooks that the mapdict implementations needs:
- def _get_mapdict_map(self):
- return None
- def _set_mapdict_map(self, map):
- raise NotImplementedError
- def _mapdict_read_storage(self, index):
- raise NotImplementedError
- def _mapdict_write_storage(self, index, value):
- raise NotImplementedError
- def _mapdict_storage_length(self):
- raise NotImplementedError
- def _set_mapdict_storage_and_map(self, storage, map):
- raise NotImplementedError
# -------------------------------------------------------------------
diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -362,6 +362,26 @@
""")
assert seen == [1]
+ def test_mapdict_number_of_slots(self):
+ space = self.space
+ a, b, c = space.unpackiterable(space.appexec([], """():
+ class A(object):
+ pass
+ a = A()
+ a.x = 1
+ class B:
+ pass
+ b = B()
+ b.x = 1
+ class C(int):
+ pass
+ c = C(1)
+ c.x = 1
+ return a, b, c
+ """), 3)
+ assert not hasattr(a, "storage")
+ assert not hasattr(b, "storage")
+ assert hasattr(c, "storage")
class AppTestTypeDef:
@@ -423,3 +443,4 @@
def f():
return x
assert f.__closure__[0].cell_contents is x
+
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -124,22 +124,23 @@
def _getusercls(config, cls, wants_del, reallywantdict=False):
from rpython.rlib import objectmodel
+ from pypy.objspace.std.objectobject import W_ObjectObject
+ from pypy.module.__builtin__.interp_classobj import W_InstanceObject
from pypy.objspace.std.mapdict import (BaseUserClassMapdict,
- MapdictDictSupport, MapdictWeakrefSupport,
- _make_storage_mixin_size_n)
+ MapdictDictSupport,
+ _make_storage_mixin_size_n, MapdictStorageMixin)
typedef = cls.typedef
name = cls.__name__ + "User"
- mixins_needed = [BaseUserClassMapdict, _make_storage_mixin_size_n()]
+ mixins_needed = [BaseUserClassMapdict]
+ if cls is W_ObjectObject or cls is W_InstanceObject:
+ mixins_needed.append(_make_storage_mixin_size_n())
+ else:
+ mixins_needed.append(MapdictStorageMixin)
if reallywantdict or not typedef.hasdict:
# the type has no dict, mapdict to provide the dict
mixins_needed.append(MapdictDictSupport)
name += "Dict"
- if not typedef.weakrefable:
- # the type does not support weakrefs yet, mapdict to provide weakref
- # support
- mixins_needed.append(MapdictWeakrefSupport)
- name += "Weakrefable"
if wants_del:
name += "Del"
parent_destructor = getattr(cls, '__del__', None)
diff --git a/pypy/objspace/std/basemapdictobject.py b/pypy/objspace/std/basemapdictobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/basemapdictobject.py
@@ -0,0 +1,192 @@
+# this file contains the shared objspace method implementation that are
+# imported into W_Root. All W_Root objects have these methods, but most of them
+# really only make sense for user-defined subclasses. It is however important
+# that they are shared by all subclasses of W_Root.
+
+
+DICT = 0
+SPECIAL = 1
+INVALID = 2
+SLOTS_STARTING_FROM = 3
+
+
+class RootObjectMapdictMixin(object):
+ # hooks that the mapdict implementations needs.
+ # these will be overridden in user-defined subclasses
+
+ def _get_mapdict_map(self):
+ # if this method returns None, there is no map, thus the class is no
+ # user-defined subclass
+ return None
+
+ def _set_mapdict_map(self, map):
+ raise NotImplementedError
+
+ def _mapdict_read_storage(self, index):
+ raise NotImplementedError
+
+ def _mapdict_write_storage(self, index, value):
+ raise NotImplementedError
+
+ def _mapdict_storage_length(self):
+ raise NotImplementedError
+
+ def _set_mapdict_storage_and_map(self, storage, map):
+ raise NotImplementedError
+
+ def _mapdict_init_empty(self, map):
+ raise NotImplementedError
+
+ # ____________________________________________________________
+ # objspace interface
+
+
+ # class handling
+
+ # getclass is not done here, it makes sense to really specialize this per class
+
+ def setclass(self, space, w_cls):
+ from pypy.interpreter.error import OperationError
+ map = self._get_mapdict_map()
+ if map is None:
+ raise OperationError(space.w_TypeError,
+ space.wrap("__class__ assignment: only for heap types"))
+ new_obj = map.set_terminator(self, w_cls.terminator)
+ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
+
+
+ # dict handling
+
+ # getdictvalue and setdictvalue are not done here, for performance reasons
+
+ def deldictvalue(self, space, attrname):
+ from pypy.interpreter.error import OperationError
+ map = self._get_mapdict_map()
+ if map is None:
+ # check whether it has a dict and use that
+ w_dict = self.getdict(space)
+ if w_dict is not None:
+ try:
+ space.delitem(w_dict, space.wrap(attrname))
+ return True
+ except OperationError, ex:
+ if not ex.match(space, space.w_KeyError):
+ raise
+ return False
+ new_obj = map.delete(self, attrname, DICT)
+ if new_obj is None:
+ return False
+ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
+ return True
+
+ def getdict(self, space):
+ from pypy.objspace.std.mapdict import MapDictStrategy
+ from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+ from pypy.objspace.std.dictmultiobject import W_DictObject
+ map = self._get_mapdict_map()
+ if map is None:
+ return None
+ terminator = map.terminator
+ if not terminator.has_dict:
+ return None
+ w_dict = map.read(self, "dict", SPECIAL)
+ if w_dict is not None:
+ assert isinstance(w_dict, W_DictMultiObject)
+ return w_dict
+
+ strategy = space.fromcache(MapDictStrategy)
+ storage = strategy.erase(self)
+ w_dict = W_DictObject(space, strategy, storage)
+ flag = map.write(self, "dict", SPECIAL, w_dict)
+ assert flag
+ return w_dict
+
+ def setdict(self, space, w_dict):
+ from pypy.interpreter.error import OperationError, oefmt
+ from pypy.objspace.std.mapdict import MapDictStrategy
+ from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+ map = self._get_mapdict_map()
+ if map is None or not map.terminator.has_dict:
+ raise oefmt(space.w_TypeError,
+ "attribute '__dict__' of %T objects is not writable",
+ self)
+ terminator = map.terminator
+ if not space.isinstance_w(w_dict, space.w_dict):
+ raise OperationError(space.w_TypeError,
+ space.wrap("setting dictionary to a non-dict"))
+ assert isinstance(w_dict, W_DictMultiObject)
+ w_olddict = self.getdict(space)
+ assert isinstance(w_olddict, W_DictMultiObject)
+ # The old dict has got 'self' as dstorage, but we are about to
+ # change self's ("dict", SPECIAL) attribute to point to the
+ # new dict. If the old dict was using the MapDictStrategy, we
+ # have to force it now: otherwise it would remain an empty
+ # shell that continues to delegate to 'self'.
+ if type(w_olddict.get_strategy()) is MapDictStrategy:
+ w_olddict.get_strategy().switch_to_object_strategy(w_olddict)
+ flag = self._get_mapdict_map().write(self, "dict", SPECIAL, w_dict)
+ assert flag
+
+
+ # slots
+
+ def getslotvalue(self, slotindex):
+ map = self._get_mapdict_map()
+ if map is None:
+ # not a user-defined subclass
+ raise NotImplementedError
+ index = SLOTS_STARTING_FROM + slotindex
+ return map.read(self, "slot", index)
+
+ def setslotvalue(self, slotindex, w_value):
+ map = self._get_mapdict_map()
+ if map is None:
+ # not a user-defined subclass
+ raise NotImplementedError
+ index = SLOTS_STARTING_FROM + slotindex
+ map.write(self, "slot", index, w_value)
+
+ def delslotvalue(self, slotindex):
+ map = self._get_mapdict_map()
+ if map is None:
+ # not a user-defined subclass
+ raise NotImplementedError
+ index = SLOTS_STARTING_FROM + slotindex
+ new_obj = map.delete(self, "slot", index)
+ if new_obj is None:
+ return False
+ self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
+ return True
+
+
+ # weakrefs
+
+ def getweakref(self):
+ from pypy.module._weakref.interp__weakref import WeakrefLifeline
+ map = self._get_mapdict_map()
+ if map is None:
+ return None # not a user-defined subclass
+ lifeline = map.read(self, "weakref", SPECIAL)
+ if lifeline is None:
+ return None
+ assert isinstance(lifeline, WeakrefLifeline)
+ return lifeline
+ getweakref._cannot_really_call_random_things_ = True
+
+ def setweakref(self, space, weakreflifeline):
+ from pypy.module._weakref.interp__weakref import WeakrefLifeline
+ map = self._get_mapdict_map()
+ if map is None:
+ # not a user-defined subclass
+ raise oefmt(space.w_TypeError,
+ "cannot create weak reference to '%T' object", self)
+ assert isinstance(weakreflifeline, WeakrefLifeline)
+ map.write(self, "weakref", SPECIAL, weakreflifeline)
+ setweakref._cannot_really_call_random_things_ = True
+
+ def delweakref(self):
+ map = self._get_mapdict_map()
+ if map is None:
+ return
+ map.write(self, "weakref", SPECIAL, None)
+ delweakref._cannot_really_call_random_things_ = True
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
@@ -10,6 +10,8 @@
W_DictObject,
)
from pypy.objspace.std.typeobject import MutableCell
+from pypy.objspace.std.basemapdictobject import (DICT, SPECIAL,
+ SLOTS_STARTING_FROM, INVALID)
erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage item")
@@ -277,7 +279,7 @@
def copy(self, obj):
result = Object()
result.space = self.space
- result._init_empty(self)
+ result._mapdict_init_empty(self)
return result
def length(self):
@@ -286,7 +288,7 @@
def set_terminator(self, obj, terminator):
result = Object()
result.space = self.space
- result._init_empty(terminator)
+ result._mapdict_init_empty(terminator)
return result
def remove_dict_entries(self, obj):
@@ -297,6 +299,9 @@
class DictTerminator(Terminator):
_immutable_fields_ = ['devolved_dict_terminator']
+
+ has_dict = True
+
def __init__(self, space, w_cls):
Terminator.__init__(self, space, w_cls)
self.devolved_dict_terminator = DevolvedDictTerminator(space, w_cls)
@@ -304,11 +309,13 @@
def materialize_r_dict(self, space, obj, dict_w):
result = Object()
result.space = space
- result._init_empty(self.devolved_dict_terminator)
+ result._mapdict_init_empty(self.devolved_dict_terminator)
return result
class NoDictTerminator(Terminator):
+ has_dict = False
+
def _write_terminator(self, obj, name, index, w_value):
if index == DICT:
return False
@@ -316,6 +323,8 @@
class DevolvedDictTerminator(Terminator):
+ has_dict = True
+
def _read_terminator(self, obj, name, index):
if index == DICT:
space = self.space
@@ -417,11 +426,6 @@
def __repr__(self):
return "<PlainAttribute %s %s %s %r>" % (self.name, self.index, self.storageindex, self.back)
-def _become(w_obj, new_obj):
- # this is like the _become method, really, but we cannot use that due to
- # RPython reasons
- w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
-
class MapAttrCache(object):
def __init__(self, space):
SIZE = 1 << space.config.objspace.std.methodcachesizeexp
@@ -445,11 +449,6 @@
# ____________________________________________________________
# object implementation
-DICT = 0
-SPECIAL = 1
-INVALID = 2
-SLOTS_STARTING_FROM = 3
-
# a little bit of a mess of mixin classes that implement various pieces of
# objspace user object functionality in terms of mapdict
@@ -457,16 +456,13 @@
# everything that's needed to use mapdict for a user subclass at all.
# This immediately makes slots possible.
- # assumes presence of _init_empty, _mapdict_read_storage,
+ # assumes presence of _mapdict_init_empty, _mapdict_read_storage,
# _mapdict_write_storage, _mapdict_storage_length,
# _set_mapdict_storage_and_map
# _____________________________________________
# methods needed for mapdict
- def _become(self, new_obj):
- self._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
-
def _get_mapdict_map(self):
return jit.promote(self.map)
def _set_mapdict_map(self, map):
@@ -480,59 +476,13 @@
def getclass(self, space):
return self._get_mapdict_map().terminator.w_cls
- def setclass(self, space, w_cls):
- new_obj = self._get_mapdict_map().set_terminator(self, w_cls.terminator)
- self._become(new_obj)
-
def user_setup(self, space, w_subtype):
from pypy.module.__builtin__.interp_classobj import W_InstanceObject
self.space = space
assert (not self.typedef.hasdict or
isinstance(w_subtype.terminator, NoDictTerminator) or
self.typedef is W_InstanceObject.typedef)
- self._init_empty(w_subtype.terminator)
-
-
- # methods needed for slots
-
- def getslotvalue(self, slotindex):
- index = SLOTS_STARTING_FROM + slotindex
- return self._get_mapdict_map().read(self, "slot", index)
-
- def setslotvalue(self, slotindex, w_value):
- index = SLOTS_STARTING_FROM + slotindex
- self._get_mapdict_map().write(self, "slot", index, w_value)
-
- def delslotvalue(self, slotindex):
- index = SLOTS_STARTING_FROM + slotindex
- new_obj = self._get_mapdict_map().delete(self, "slot", index)
- if new_obj is None:
- return False
- self._become(new_obj)
- return True
-
-
-class MapdictWeakrefSupport(object):
- # stuff used by the _weakref implementation
-
- def getweakref(self):
- from pypy.module._weakref.interp__weakref import WeakrefLifeline
- lifeline = self._get_mapdict_map().read(self, "weakref", SPECIAL)
- if lifeline is None:
- return None
- assert isinstance(lifeline, WeakrefLifeline)
- return lifeline
- getweakref._cannot_really_call_random_things_ = True
-
- def setweakref(self, space, weakreflifeline):
- from pypy.module._weakref.interp__weakref import WeakrefLifeline
- assert isinstance(weakreflifeline, WeakrefLifeline)
- self._get_mapdict_map().write(self, "weakref", SPECIAL, weakreflifeline)
- setweakref._cannot_really_call_random_things_ = True
-
- def delweakref(self):
- self._get_mapdict_map().write(self, "weakref", SPECIAL, None)
- delweakref._cannot_really_call_random_things_ = True
+ self._mapdict_init_empty(w_subtype.terminator)
class MapdictDictSupport(object):
@@ -545,61 +495,9 @@
def setdictvalue(self, space, attrname, w_value):
return self._get_mapdict_map().write(self, attrname, DICT, w_value)
- def deldictvalue(self, space, attrname):
- new_obj = self._get_mapdict_map().delete(self, attrname, DICT)
- if new_obj is None:
- return False
- self._become(new_obj)
- return True
-
- def getdict(self, space):
- return _obj_getdict(self, space)
-
- def setdict(self, space, w_dict):
- _obj_setdict(self, space, w_dict)
-
-# a couple of helpers for the classes above, factored out to reduce
-# the translated code size
-
- at objectmodel.dont_inline
-def _obj_getdict(self, space):
- terminator = self._get_mapdict_map().terminator
- assert isinstance(terminator, DictTerminator) or isinstance(terminator, DevolvedDictTerminator)
- w_dict = self._get_mapdict_map().read(self, "dict", SPECIAL)
- if w_dict is not None:
- assert isinstance(w_dict, W_DictMultiObject)
- return w_dict
-
- strategy = space.fromcache(MapDictStrategy)
- storage = strategy.erase(self)
- w_dict = W_DictObject(space, strategy, storage)
- flag = self._get_mapdict_map().write(self, "dict", SPECIAL, w_dict)
- assert flag
- return w_dict
-
- at objectmodel.dont_inline
-def _obj_setdict(self, space, w_dict):
- from pypy.interpreter.error import OperationError
- terminator = self._get_mapdict_map().terminator
- assert isinstance(terminator, DictTerminator) or isinstance(terminator, DevolvedDictTerminator)
- if not space.isinstance_w(w_dict, space.w_dict):
- raise OperationError(space.w_TypeError,
- space.wrap("setting dictionary to a non-dict"))
- assert isinstance(w_dict, W_DictMultiObject)
- w_olddict = self.getdict(space)
- assert isinstance(w_olddict, W_DictMultiObject)
- # The old dict has got 'self' as dstorage, but we are about to
- # change self's ("dict", SPECIAL) attribute to point to the
- # new dict. If the old dict was using the MapDictStrategy, we
- # have to force it now: otherwise it would remain an empty
- # shell that continues to delegate to 'self'.
- if type(w_olddict.get_strategy()) is MapDictStrategy:
- w_olddict.get_strategy().switch_to_object_strategy(w_olddict)
- flag = self._get_mapdict_map().write(self, "dict", SPECIAL, w_dict)
- assert flag
class MapdictStorageMixin(object):
- def _init_empty(self, map):
+ def _mapdict_init_empty(self, map):
from rpython.rlib.debug import make_sure_not_resized
self.map = map
self.storage = make_sure_not_resized([None] * map.size_estimate())
@@ -622,7 +520,6 @@
objectmodel.import_from_mixin(MapdictStorageMixin)
objectmodel.import_from_mixin(BaseUserClassMapdict)
- objectmodel.import_from_mixin(MapdictWeakrefSupport)
class Object(W_Root):
@@ -630,7 +527,6 @@
objectmodel.import_from_mixin(MapdictStorageMixin)
objectmodel.import_from_mixin(BaseUserClassMapdict)
- objectmodel.import_from_mixin(MapdictWeakrefSupport)
objectmodel.import_from_mixin(MapdictDictSupport)
@@ -643,7 +539,7 @@
rangenmin1 = unroll.unrolling_iterable(range(nmin1))
valnmin1 = "_value%s" % nmin1
class subcls(object):
- def _init_empty(self, map):
+ def _mapdict_init_empty(self, map):
for i in rangenmin1:
setattr(self, "_value%s" % i, None)
setattr(self, valnmin1, erase_item(None))
@@ -731,7 +627,7 @@
def get_empty_storage(self):
w_result = Object()
terminator = self.space.fromcache(get_terminator_for_dicts)
- w_result._init_empty(terminator)
+ w_result._mapdict_init_empty(terminator)
return self.erase(w_result)
def switch_to_object_strategy(self, w_dict):
@@ -811,7 +707,7 @@
def clear(self, w_dict):
w_obj = self.unerase(w_dict.dstorage)
new_obj = w_obj._get_mapdict_map().remove_dict_entries(w_obj)
- _become(w_obj, new_obj)
+ w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
def popitem(self, w_dict):
curr = self.unerase(w_dict.dstorage)._get_mapdict_map().search(DICT)
@@ -833,10 +729,10 @@
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)
+def materialize_r_dict(space, w_obj, dict_w):
+ map = w_obj._get_mapdict_map()
+ new_obj = map.materialize_r_dict(space, w_obj, dict_w)
+ w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
class MapDictIteratorKeys(BaseKeyIterator):
def __init__(self, space, strategy, dictimplementation):
More information about the pypy-commit
mailing list