[pypy-commit] pypy expose-jsonmap: re-implement dictstructure.append, with proper statistics keeping
cfbolz
pypy.commits at gmail.com
Mon Nov 4 05:53:56 EST 2019
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: expose-jsonmap
Changeset: r97949:c4a8e1c5dfd0
Date: 2019-11-04 11:53 +0100
http://bitbucket.org/pypy/pypy/changeset/c4a8e1c5dfd0/
Log: re-implement dictstructure.append, with proper statistics keeping
diff --git a/pypy/module/__pypy__/test/test_dictstructure.py b/pypy/module/__pypy__/test/test_dictstructure.py
--- a/pypy/module/__pypy__/test/test_dictstructure.py
+++ b/pypy/module/__pypy__/test/test_dictstructure.py
@@ -29,3 +29,25 @@
from __pypy__ import newdictstructure
with raises(ValueError):
newdictstructure([u"a", u"a"])
+
+ def test_append(self):
+ from __pypy__ import newdictstructure
+ s = newdictstructure([u"a"])
+ s1 = s.append(u"b")
+ assert s.append(u"b") is s1
+ assert s1.instantiate_dict([1, 2]) == {u"a": 1, u"b": 2}
+ with raises(ValueError):
+ s.append(u"a")
+
+
+class TestDictStructure(object):
+ def test_append_and_transitions(self):
+ from pypy.module._pypyjson.interp_decoder import Terminator
+ m = Terminator(self.space)
+ w_a = self.space.newutf8("a", 1)
+ w_b = self.space.newutf8("b", 1)
+ m1 = m.descr_append(self.space, w_a)
+ m2 = m1.descr_append(self.space, w_b)
+ count = m2.instantiation_count
+ m1.descr_append(self.space, w_b)
+ assert m2.instantiation_count == count + 1
diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py
--- a/pypy/module/_pypyjson/interp_decoder.py
+++ b/pypy/module/_pypyjson/interp_decoder.py
@@ -800,7 +800,7 @@
elif self.nextmap_first:
self.nextmap_first._check_invariants()
- def get_next(self, w_key, string, start, stop, terminator):
+ def get_next(self, w_key, string, start, stop, terminator=None):
""" Returns the next map, given a wrapped key w_key, the json input
string with positions start and stop, as well as a terminator.
@@ -843,6 +843,8 @@
# one new leaf has been created
self.change_number_of_leaves(1)
+ if terminator is None: # only from descr_append
+ terminator = self._slowly_get_terminator()
terminator.register_potential_fringe(next)
return next
@@ -869,7 +871,7 @@
return nextmap_first
return None
- def observe_transition(self, newmap, terminator):
+ def observe_transition(self, newmap, terminator=None):
""" observe a transition from self to newmap.
This does a few things, including updating the self size estimate with
the knowledge that one object transitioned from self to newmap.
@@ -877,6 +879,8 @@
newmap.instantiation_count += 1
if isinstance(self, JSONMap) and self.state == MapBase.FRINGE:
if self.is_useful():
+ if terminator is None:
+ self._slowly_get_terminator()
self.mark_useful(terminator)
def _make_next_map(self, w_key, key_repr):
@@ -899,21 +903,43 @@
# exposed methods
def descr_instantiate_dict(self, space, w_l):
- from pypy.objspace.std.jsondict import from_values_and_jsonmap
+ """ Create a dict instance given from the structure, using the list l
+ as values. It must have the same length as the structure has keys. """
+ from pypy.objspace.std.jsondict import from_values_and_jsonmap_checked
from pypy.objspace.std.jsondict import devolve_jsonmap_dict
l_w = space.listview(w_l)
if not isinstance(self, JSONMap):
return space.newdict()
- keys_w = self.get_keys_in_order()
- if len(l_w) != len(keys_w):
- raise oefmt(space.w_ValueError, "expected %s values, got %s", str(len(keys_w)), str(len(l_w)))
- w_dict = from_values_and_jsonmap(self.space, l_w[:], self)
+ w_dict = from_values_and_jsonmap_checked(self.space, l_w[:], self)
if self.is_state_blocked():
devolve_jsonmap_dict(w_dict)
return w_dict
def descr_repr(self, space):
- return space.newtext("<DictStructure [%s]>" % ", ".join([space.text_w(space.repr(w_key)) for w_key in self.get_keys_in_order()]))
+ res = []
+ curr = self
+ while type(curr) is JSONMap:
+ res.append(space.text_w(space.repr(self.w_key)))
+ curr = curr.prev
+ res.reverse()
+ return space.newtext("<DictStructure [%s]>" % ", ".join(res))
+
+ def descr_append(self, space, w_u):
+ from pypy.objspace.std.unicodeobject import W_UnicodeObject
+ if type(w_u) is not W_UnicodeObject:
+ raise oefmt(space.w_TypeError, "expected unicode, got %T", w_u)
+ u = space.utf8_w(w_u)
+ res = self.get_next(w_u, u, 0, len(u))
+ if res is None:
+ raise oefmt(space.w_ValueError, "repeated key %R", w_u)
+ self.observe_transition(res)
+ return res
+
+ def _slowly_get_terminator(self):
+ curr = self
+ while type(curr) is JSONMap:
+ curr = curr.prev
+ return curr
# ____________________________________________________________
@@ -1190,5 +1216,6 @@
__repr__ = interp2app(MapBase.descr_repr),
last_key = GetSetProperty(get_last_key, name="last_key"),
previous = GetSetProperty(get_previous, name="previous"),
+ append = interp2app(MapBase.descr_append),
)
MapBase.typedef.acceptable_as_base_class = False
diff --git a/pypy/objspace/std/jsondict.py b/pypy/objspace/std/jsondict.py
--- a/pypy/objspace/std/jsondict.py
+++ b/pypy/objspace/std/jsondict.py
@@ -8,7 +8,7 @@
from pypy.objspace.std.dictmultiobject import (
UnicodeDictStrategy, DictStrategy,
create_iterator_classes, W_DictObject)
-
+from pypy.interpreter.error import oefmt
def from_values_and_jsonmap(space, values_w, jsonmap):
debug.make_sure_not_resized(values_w)
@@ -21,6 +21,17 @@
storage = strategy.erase(values_w)
return W_DictObject(space, strategy, storage)
+def from_values_and_jsonmap_checked(space, values_w, jsonmap):
+ debug.make_sure_not_resized(values_w)
+ strategy = jsonmap.strategy_instance
+ if strategy is None:
+ jsonmap.strategy_instance = strategy = JsonDictStrategy(space, jsonmap)
+ keys_w = strategy.get_keys_in_order()
+ if len(values_w) != len(keys_w):
+ raise oefmt(space.w_ValueError, "expected %s values, got %s", str(len(keys_w)), str(len(values_w)))
+ storage = strategy.erase(values_w)
+ return W_DictObject(space, strategy, storage)
+
def devolve_jsonmap_dict(w_dict):
assert isinstance(w_dict, W_DictObject)
strategy = w_dict.get_strategy()
More information about the pypy-commit
mailing list