[pypy-svn] r33152 - in pypy/dist/pypy/rpython: . ootypesystem test

antocuni at codespeak.net antocuni at codespeak.net
Wed Oct 11 13:21:37 CEST 2006


Author: antocuni
Date: Wed Oct 11 13:21:35 2006
New Revision: 33152

Modified:
   pypy/dist/pypy/rpython/ootypesystem/ootype.py
   pypy/dist/pypy/rpython/ootypesystem/rdict.py
   pypy/dist/pypy/rpython/rdict.py
   pypy/dist/pypy/rpython/test/test_rdict.py
Log:
Make DictItemsIterator.ll_go_next raise RuntimeError if the dictionary
we are iterating over has been changed.



Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py	Wed Oct 11 13:21:35 2006
@@ -552,17 +552,9 @@
             self.VALUETYPE_T: VALUETYPE
             }
 
-        # some words about the interface of the iterator: we can't
-        # write the next() method directly in the backend because of
-        # two reasons:
-        #  1) tuples aren't BuiltinType, yet, so we can't make them
-        #     generic; moreover, they are constructed on-the-fly, so the
-        #     two-item tuple type that an hypotetic next() would return
-        #     isn't available at this time.
-        #  2) StopIteration is generated at translation time too, so
-        #     this would prevent backends to do a precompilation of
-        #     support code.
-
+        # Dictionaries are not allowed to be changed during an
+        # iteration. The ll_go_next method should check this condition
+        # and raise RuntimeError in that case.
         self._GENERIC_METHODS = frozendict({
             "ll_go_next": Meth([], Bool), # move forward; return False is there is no more data available
             "ll_current_key": Meth([], self.KEYTYPE_T),
@@ -1043,6 +1035,7 @@
     def __init__(self, DICT):
         self._TYPE = DICT
         self._dict = {}
+        self._stamp = 0
 
     def ll_length(self):
         # NOT_RPYTHON
@@ -1059,12 +1052,14 @@
         assert typeOf(key) == self._TYPE._KEYTYPE
         assert typeOf(value) == self._TYPE._VALUETYPE
         self._dict[key] = value
+        self._stamp += 1
 
     def ll_remove(self, key):
         # NOT_RPYTHON
         assert typeOf(key) == self._TYPE._KEYTYPE
         try:
             del self._dict[key]
+            self._stamp += 1
             return True
         except KeyError:
             return False
@@ -1076,12 +1071,14 @@
 
     def ll_clear(self):
         self._dict.clear()
+        self._stamp += 1
 
     def ll_get_items_iterator(self):
         # NOT_RPYTHON
         ITER = DictItemsIterator(self._TYPE._KEYTYPE, self._TYPE._VALUETYPE)
         iter = _dict_items_iterator(ITER)
-        iter._items = self._dict.items()
+        iter._set_dict(self)
+        #print 'ITERATOR created with stamp', self._stamp
         return iter
 
 class _null_dict(_null_mixin(_dict), _dict):
@@ -1112,11 +1109,20 @@
 class _dict_items_iterator(_builtin_type):
     def __init__(self, ITER):
         self._TYPE = ITER
-        self._items = []
         self._index = -1
 
+    def _set_dict(self, d):
+        self._dict = d
+        self._items = d._dict.items()
+        self._stamp = d._stamp
+
+    def _check_stamp(self):
+        if self._stamp != self._dict._stamp:
+            raise RuntimeError, 'Dictionary changed during iteration'
+
     def ll_go_next(self):
         # NOT_RPYTHON
+        self._check_stamp()
         self._index += 1        
         if self._index >= len(self._items):
             return False
@@ -1125,11 +1131,13 @@
 
     def ll_current_key(self):
         # NOT_RPYTHON
+        self._check_stamp()
         assert 0 <= self._index < len(self._items)
         return self._items[self._index][0]
     
     def ll_current_value(self):
         # NOT_RPYTHON
+        self._check_stamp()
         assert 0 <= self._index < len(self._items)
         return self._items[self._index][1]
 

Modified: pypy/dist/pypy/rpython/ootypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rdict.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rdict.py	Wed Oct 11 13:21:35 2006
@@ -362,6 +362,9 @@
         ITER = ootype.DictItemsIterator(KEYTYPE, VALUETYPE)
         return ootype.Record({"iterator": ITER})
 
+    def _next_implicit_exceptions(self, hop):
+        hop.has_implicit_exception(StopIteration)
+        hop.has_implicit_exception(RuntimeError)
 
 def ll_dictiter(ITER, d):
     iter = ootype.new(ITER)

Modified: pypy/dist/pypy/rpython/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/rdict.py	(original)
+++ pypy/dist/pypy/rpython/rdict.py	Wed Oct 11 13:21:35 2006
@@ -89,6 +89,9 @@
         citerptr = hop.inputconst(lltype.Void, self.lowleveltype)
         return hop.gendirectcall(self.ll_dictiter, citerptr, v_dict)
 
+    def _next_implicit_exceptions(self, hop):
+        hop.has_implicit_exception(StopIteration)
+
     def rtype_next(self, hop):
         variant = self.variant
         v_iter, = hop.inputargs(self)
@@ -97,7 +100,7 @@
             c1 = hop.inputconst(lltype.Void, None)
         else:
             c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype)
-        hop.has_implicit_exception(StopIteration) # record that we know about it
+        self._next_implicit_exceptions(hop) # record that we know about it
         hop.exception_is_here()
         v = hop.gendirectcall(self.ll_dictnext, v_iter, v_func, c1)
         if variant == 'keys':

Modified: pypy/dist/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rdict.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rdict.py	Wed Oct 11 13:21:35 2006
@@ -749,6 +749,13 @@
         res = self.interpret(func, [5])
         assert res.ll_get(5) is res
 
-
-
-
+    def test_invalid_iterator(self):
+        def func():
+            try:
+                d = {'a': 1, 'b': 2}
+                for key in d:
+                    d[key] = 0
+                return True
+            except RuntimeError:
+                return False
+        assert self.interpret(func, []) == False


More information about the pypy-svn mailing list