[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