Author: Lukas Diekmann <lukas.diekm...@uni-duesseldorf.de> Branch: type-specialized-instances Changeset: r49522:b16fead0c3f3 Date: 2011-11-16 18:24 +0100 http://bitbucket.org/pypy/pypy/changeset/b16fead0c3f3/
Log: introduced IntAttribute 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 @@ -125,15 +125,15 @@ return None @jit.elidable - def _get_new_attr(self, name, index): - selector = name, index + def _get_new_attr(self, name, index, attrclass): + key = name, index, attrclass cache = self.cache_attrs if cache is None: cache = self.cache_attrs = {} - attr = cache.get(selector, None) + attr = cache.get(key, None) if attr is None: - attr = PlainAttribute(selector, self) - cache[selector] = attr + attr = attrclass(key, self) + cache[key] = attr return attr @jit.look_inside_iff(lambda self, obj, selector, w_value: @@ -141,8 +141,9 @@ jit.isconstant(selector[0]) and jit.isconstant(selector[1])) def add_attr(self, obj, selector, w_value): + attrclass = get_attrclass_from_value(self.space, w_value) # grumble, jit needs this - attr = self._get_new_attr(selector[0], selector[1]) + attr = self._get_new_attr(selector[0], selector[1], attrclass) oldattr = obj._get_mapdict_map() if not jit.we_are_jitted(): size_est = (oldattr._size_estimate + attr.size_estimate() @@ -264,8 +265,10 @@ terminator = terminator.devolved_dict_terminator return Terminator.set_terminator(self, obj, terminator) -class PlainAttribute(AbstractAttribute): +class AbstractStoredAttribute(AbstractAttribute): + _immutable_fields_ = ['selector', 'position', 'back'] + def __init__(self, selector, back): AbstractAttribute.__init__(self, back.space, back.terminator) self.selector = selector @@ -277,17 +280,6 @@ w_value = self.read(obj, self.selector) new_obj._get_mapdict_map().add_attr(new_obj, self.selector, w_value) - def read_attr(self, obj): - # XXX do the unerasing (and wrapping) here - erased = obj._mapdict_read_storage(self.position) - w_value = unerase_item(erased) - return w_value - - def write_attr(self, obj, w_value): - # XXX do the unerasing (and unwrapping) here - erased = erase_item(w_value) - obj._mapdict_write_storage(self.position, erased) - def delete(self, obj, selector): if selector == self.selector: # ok, attribute is deleted @@ -333,6 +325,41 @@ def __repr__(self): return "<PlainAttribute %s %s %r>" % (self.selector, self.position, self.back) +class PlainAttribute(AbstractStoredAttribute): + + erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage object item") + erase_item = staticmethod(erase_item) + unerase_item = staticmethod(unerase_item) + + def read_attr(self, obj): + erased = obj._mapdict_read_storage(self.position) + w_value = self.unerase_item(erased) + return w_value + + def write_attr(self, obj, w_value): + erased = self.erase_item(w_value) + obj._mapdict_write_storage(self.position, erased) + +class IntAttribute(AbstractStoredAttribute): + + erase_item, unerase_item = rerased.erase_int, rerased.unerase_int + erase_item = staticmethod(erase_item) + unerase_item = staticmethod(unerase_item) + + def read_attr(self, obj): + erased = obj._mapdict_read_storage(self.position) + value = self.unerase_item(erased) + return self.space.wrap(value) + + def write_attr(self, obj, w_value): + erased = self.erase_item(self.space.int_w(w_value)) + obj._mapdict_write_storage(self.position, erased) + +def get_attrclass_from_value(space, w_value): + if space.is_w(space.type(w_value), space.w_int): + return IntAttribute + return PlainAttribute + def _become(w_obj, new_obj): # this is like the _become method, really, but we cannot use that due to # RPython reasons @@ -524,7 +551,6 @@ memo_get_subclass_of_correct_size._annspecialcase_ = "specialize:memo" _subclass_cache = {} -erase_item, unerase_item = rerased.new_erasing_pair("mapdict storage item") erase_list, unerase_list = rerased.new_erasing_pair("mapdict storage list") def _make_subclass_size_n(supercls, n): 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 @@ -5,12 +5,14 @@ space = FakeSpace() class Class(object): - def __init__(self, hasdict=True): + def __init__(self, hasdict=True, sp=None): self.hasdict = True + if sp is None: + sp = space if hasdict: - self.terminator = DictTerminator(space, self) + self.terminator = DictTerminator(sp, self) else: - self.terminator = NoDictTerminator(space, self) + self.terminator = NoDictTerminator(sp, self) def instantiate(self, sp=None): if sp is None: @@ -24,10 +26,10 @@ hasdict = False def erase_storage_items(items): - return [erase_item(item) for item in items] + return [IntAttribute.erase_item(item) for item in items] def unerase_storage_items(storage): - return [unerase_item(item) for item in storage] + return [IntAttribute.unerase_item(item) for item in storage] def test_plain_attribute(): @@ -247,7 +249,6 @@ assert obj.getdict(space) is obj.getdict(space) assert obj.getdict(space).length() == 3 - def test_materialize_r_dict(): cls = Class() obj = cls.instantiate() @@ -301,6 +302,50 @@ obj.setdictvalue(space, a, 50) assert c.terminator.size_estimate() in [(i + 10) // 2, (i + 11) // 2] +class TestTypeSpecializedAttributes(object): + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withmapdict": True}) + + def test_attributes(self): + space = self.space + cls = Class(sp=space) + obj1 = cls.instantiate() + obj1.setdictvalue(space, "x", space.wrap(1)) + #assert space.eq_w(obj1.getdictvalue(space, "x"), space.wrap(1)) + + obj2 = cls.instantiate() + w_str = space.wrap("string") + obj2.setdictvalue(space, "x", w_str) + #assert space.eq_w(obj1.getdictvalue(space, "x"), w_str) + + assert obj1.map is not obj2.map + assert isinstance(obj1.map, IntAttribute) + + obj3 = cls.instantiate() + obj3.setdictvalue(space, "x", space.wrap(5)) + + assert obj1.map is obj3.map + + assert IntAttribute.unerase_item(obj1.storage[0]) == 1 + assert PlainAttribute.unerase_item(obj2.storage[0]) == w_str + + def test_add_more_attributes(self): + space = self.space + cls = Class(sp=space) + + obj1 = cls.instantiate() + obj1.setdictvalue(space, "x", space.wrap(1)) + obj1.setdictvalue(space, "y", space.wrap(2)) + + def test_switch_attribute_types(self): + space = self.space + cls = Class(sp=space) + obj1 = cls.instantiate() + obj1.setdictvalue(space, "x", space.wrap(1)) + assert isinstance(obj1.map, IntAttribute) + obj1.setdictvalue(space, "y", space.wrap("str")) + assert isinstance(obj1.map, PlainAttribute) + # ___________________________________________________________ # dict tests _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit