[pypy-commit] pypy json-decoder-maps: simplify fringe handling

cfbolz pypy.commits at gmail.com
Wed Jun 5 09:49:57 EDT 2019


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: json-decoder-maps
Changeset: r96758:5dc3d4fba79a
Date: 2019-06-05 15:27 +0200
http://bitbucket.org/pypy/pypy/changeset/5dc3d4fba79a/

Log:	simplify fringe handling

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
@@ -595,7 +595,7 @@
 
     def decode_key(self, i, currmap):
         newmap = self._decode_key(i, currmap)
-        currmap.observe_transition(newmap)
+        currmap.observe_transition(newmap, self.startmap)
         return newmap
 
     def _decode_key(self, i, currmap):
@@ -789,7 +789,7 @@
                 decoder.pos = position + len(single_nextmap.key_repr)
                 return single_nextmap
 
-    def observe_transition(self, newmap):
+    def observe_transition(self, newmap, terminator):
         """ 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.
@@ -797,7 +797,7 @@
         self.instantiation_count += 1
         if isinstance(self, JSONMap) and self.state == MapBase.FRINGE:
             if self.is_useful():
-                self.mark_useful(self.startmap)
+                self.mark_useful(terminator)
 
     def _make_next_map(self, w_key, key_repr):
         return JSONMap(self.space, self, w_key, key_repr)
@@ -852,23 +852,21 @@
                 self.cleanup_fringe()
             self.current_fringe[prelim] = None
 
+    def remove_from_fringe(self, former_fringe):
+        assert former_fringe.state in (MapBase.USEFUL, MapBase.BLOCKED)
+        del self.current_fringe[former_fringe]
+
     def cleanup_fringe(self):
         min_fringe = None
         min_avg = 10000000000
         for f in self.current_fringe:
-            if f.state == MapBase.FRINGE:
-                avg = f.average_instantiation()
-                if avg < min_avg:
-                    min_avg = avg
-                    min_fringe = f
-            else:
-                for f in self.current_fringe.keys():
-                    if f.state != MapBase.FRINGE:
-                        del self.current_fringe[f]
-                return
+            assert f.state == MapBase.FRINGE
+            avg = f.average_instantiation()
+            if avg < min_avg:
+                min_avg = avg
+                min_fringe = f
         assert min_fringe
         min_fringe.mark_blocked(self)
-        del self.current_fringe[min_fringe]
 
 
 class JSONMap(MapBase):
@@ -932,8 +930,11 @@
     def mark_useful(self, terminator):
         # mark self as useful, and also the most commonly instantiated
         # children, recursively
+        was_fringe = self.state == MapBase.FRINGE
         assert self.state in (MapBase.FRINGE, MapBase.PRELIMINARY)
         self.state = MapBase.USEFUL
+        if was_fringe:
+            terminator.remove_from_fringe(self)
         maxchild = self.single_nextmap
         if self.all_next is not None:
             for child in self.all_next.itervalues():
@@ -948,7 +949,10 @@
                 self.single_nextmap = maxchild
 
     def mark_blocked(self, terminator):
+        was_fringe = self.state == MapBase.FRINGE
         self.state = MapBase.BLOCKED
+        if was_fringe:
+            terminator.remove_from_fringe(self)
         if self.all_next:
             for next in self.all_next.itervalues():
                 next.mark_blocked(terminator)
diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py
--- a/pypy/module/_pypyjson/test/test__pypyjson.py
+++ b/pypy/module/_pypyjson/test/test__pypyjson.py
@@ -150,7 +150,7 @@
         assert m2.number_of_leaves == 3
         assert m5.number_of_leaves == 1
 
-    def test_cleanup_fringe_simple(self):
+    def test_mark_useful_cleans_fringe(self):
         base, m1, m2, m3, m4 = self._make_some_maps()
         base.instantiation_count = 6
         assert m1.state == MapBase.FRINGE
@@ -161,11 +161,9 @@
         assert base.current_fringe == {m1: None}
 
         m1.mark_useful(base)
-        assert base.current_fringe == {m1: None, m3: None} # not cleaned up
-        base.cleanup_fringe()
         assert base.current_fringe == {m3: None}
 
-    def test_cleanup_fringe_block(self):
+    def test_cleanup_fringe(self):
         w_a = self.space.newutf8("a", 1)
         w_b = self.space.newutf8("b", 1)
         w_c = self.space.newutf8("c", 1)


More information about the pypy-commit mailing list