[pypy-svn] r40858 - in pypy/dist/pypy/rpython: lltypesystem test

arigo at codespeak.net arigo at codespeak.net
Tue Mar 20 19:33:01 CET 2007


Author: arigo
Date: Tue Mar 20 19:33:00 2007
New Revision: 40858

Modified:
   pypy/dist/pypy/rpython/lltypesystem/rdict.py
   pypy/dist/pypy/rpython/test/test_rdict.py
Log:
The rdict logic was too clever.  Unfortunately some tests check the
details of the cleverness, so here is an attempt to fix the clever
bit.  Added stress-tests for more combinations.


Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rdict.py	Tue Mar 20 19:33:00 2007
@@ -92,30 +92,47 @@
             s_value = self.dictvalue.s_value
             nullkeymarker = not self.key_repr.can_ll_be_null(s_key)
             nullvaluemarker = not self.value_repr.can_ll_be_null(s_value)
+            dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper,
+                                                            s_key)
+            dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper,
+                                                                s_value)
 
-            if nullkeymarker:
+            # * the state of the entry - trying to encode it as dummy objects
+            if nullkeymarker and dummykeyobj:
+                # all the state can be encoded in the key
                 entrymeths['everused'] = ll_everused_from_key
-            elif nullvaluemarker:
-                entrymeths['everused'] = ll_everused_from_value
-            else:
-                entryfields.append(("f_everused", lltype.Bool))
-                entrymeths['everused'] = ll_everused_from_flag
-
-            # * if the key or the value can also contain a "dummy" non-null
-            #   marker, we use it for deleted entries.
-            rtyper = self.rtyper
-            dummy_obj = self.key_repr.get_ll_dummyval_obj(rtyper, s_key)
-            if dummy_obj:
-                entrymeths['dummy_obj'] = dummy_obj
+                entrymeths['dummy_obj'] = dummykeyobj
                 entrymeths['valid'] = ll_valid_from_key
                 entrymeths['mark_deleted'] = ll_mark_deleted_in_key
                 # the key is overwritten by 'dummy' when the entry is deleted
                 entrymeths['must_clear_key'] = False
+
+            elif nullvaluemarker and dummyvalueobj:
+                # all the state can be encoded in the value
+                entrymeths['everused'] = ll_everused_from_value
+                entrymeths['dummy_obj'] = dummyvalueobj
+                entrymeths['valid'] = ll_valid_from_value
+                entrymeths['mark_deleted'] = ll_mark_deleted_in_value
+                # value is overwritten by 'dummy' when entry is deleted
+                entrymeths['must_clear_value'] = False
+
             else:
-                dummy_obj = self.value_repr.get_ll_dummyval_obj(rtyper,
-                                                                s_value)
-                if dummy_obj:
-                    entrymeths['dummy_obj'] = dummy_obj
+                # we need a flag to know if the entry was ever used
+                # (we cannot use a NULL as a marker for this, because
+                # the key and value will be reset to NULL to clear their
+                # reference)
+                entryfields.append(("f_everused", lltype.Bool))
+                entrymeths['everused'] = ll_everused_from_flag
+
+                # can we still rely on a dummy obj to mark deleted entries?
+                if dummykeyobj:
+                    entrymeths['dummy_obj'] = dummykeyobj
+                    entrymeths['valid'] = ll_valid_from_key
+                    entrymeths['mark_deleted'] = ll_mark_deleted_in_key
+                    # key is overwritten by 'dummy' when entry is deleted
+                    entrymeths['must_clear_key'] = False
+                elif dummyvalueobj:
+                    entrymeths['dummy_obj'] = dummyvalueobj
                     entrymeths['valid'] = ll_valid_from_value
                     entrymeths['mark_deleted'] = ll_mark_deleted_in_value
                     # value is overwritten by 'dummy' when entry is deleted

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	Tue Mar 20 19:33:00 2007
@@ -602,55 +602,6 @@
 
     # ____________________________________________________________
 
-    def test_stress(self):
-        from pypy.annotation.dictdef import DictKey, DictValue
-        from pypy.annotation import model as annmodel
-        dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr,
-                                  DictKey(None, annmodel.SomeInteger()),
-                                  DictValue(None, annmodel.SomeInteger()))
-        dictrepr.setup()
-        l_dict = rdict.ll_newdict(dictrepr.DICT)
-        referencetable = [None] * 400
-        referencelength = 0
-        value = 0
-
-        def complete_check():
-            for n, refvalue in zip(range(len(referencetable)), referencetable):
-                try:
-                    gotvalue = rdict.ll_dict_getitem(l_dict, n)
-                except KeyError:
-                    assert refvalue is None
-                else:
-                    assert gotvalue == refvalue
-
-        for x in not_really_random():
-            n = int(x*100.0)    # 0 <= x < 400
-            op = repr(x)[-1]
-            if op <= '2' and referencetable[n] is not None:
-                rdict.ll_dict_delitem(l_dict, n)
-                referencetable[n] = None
-                referencelength -= 1
-            elif op <= '6':
-                rdict.ll_dict_setitem(l_dict, n, value)
-                if referencetable[n] is None:
-                    referencelength += 1
-                referencetable[n] = value
-                value += 1
-            else:
-                try:
-                    gotvalue = rdict.ll_dict_getitem(l_dict, n)
-                except KeyError:
-                    assert referencetable[n] is None
-                else:
-                    assert gotvalue == referencetable[n]
-            if 1.38 <= x <= 1.39:
-                complete_check()
-                print 'current dict length:', referencelength
-            assert l_dict.num_items == referencelength
-        complete_check()
-
-    # ____________________________________________________________
-
     def test_opt_nullkeymarker(self):
         def f():
             d = {"hello": None}
@@ -759,3 +710,120 @@
             except RuntimeError:
                 return False
         assert self.interpret(func, []) == False
+
+    # ____________________________________________________________
+
+class TestStress:
+
+    def test_stress(self):
+        from pypy.annotation.dictdef import DictKey, DictValue
+        from pypy.annotation import model as annmodel
+        dictrepr = rdict.DictRepr(None, rint.signed_repr, rint.signed_repr,
+                                  DictKey(None, annmodel.SomeInteger()),
+                                  DictValue(None, annmodel.SomeInteger()))
+        dictrepr.setup()
+        l_dict = rdict.ll_newdict(dictrepr.DICT)
+        referencetable = [None] * 400
+        referencelength = 0
+        value = 0
+
+        def complete_check():
+            for n, refvalue in zip(range(len(referencetable)), referencetable):
+                try:
+                    gotvalue = rdict.ll_dict_getitem(l_dict, n)
+                except KeyError:
+                    assert refvalue is None
+                else:
+                    assert gotvalue == refvalue
+
+        for x in not_really_random():
+            n = int(x*100.0)    # 0 <= x < 400
+            op = repr(x)[-1]
+            if op <= '2' and referencetable[n] is not None:
+                rdict.ll_dict_delitem(l_dict, n)
+                referencetable[n] = None
+                referencelength -= 1
+            elif op <= '6':
+                rdict.ll_dict_setitem(l_dict, n, value)
+                if referencetable[n] is None:
+                    referencelength += 1
+                referencetable[n] = value
+                value += 1
+            else:
+                try:
+                    gotvalue = rdict.ll_dict_getitem(l_dict, n)
+                except KeyError:
+                    assert referencetable[n] is None
+                else:
+                    assert gotvalue == referencetable[n]
+            if 1.38 <= x <= 1.39:
+                complete_check()
+                print 'current dict length:', referencelength
+            assert l_dict.num_items == referencelength
+        complete_check()
+
+    def test_stress_2(self):
+        yield self.stress_combination, True,  False
+        yield self.stress_combination, False, True
+        yield self.stress_combination, False, False
+        yield self.stress_combination, True,  True
+
+    def stress_combination(self, key_can_be_none, value_can_be_none):
+        from pypy.rpython.lltypesystem.rstr import string_repr
+        from pypy.annotation.dictdef import DictKey, DictValue
+        from pypy.annotation import model as annmodel
+
+        print
+        print "Testing combination with can_be_None: keys %s, values %s" % (
+            key_can_be_none, value_can_be_none)
+
+        class PseudoRTyper:
+            cache_dummy_values = {}
+        dictrepr = rdict.DictRepr(PseudoRTyper(), string_repr, string_repr,
+                       DictKey(None, annmodel.SomeString(key_can_be_none)),
+                       DictValue(None, annmodel.SomeString(value_can_be_none)))
+        dictrepr.setup()
+        print dictrepr.lowleveltype
+        for key, value in dictrepr.DICTENTRY._adtmeths.items():
+            print '    %s = %s' % (key, value)
+        l_dict = rdict.ll_newdict(dictrepr.DICT)
+        referencetable = [None] * 400
+        referencelength = 0
+        values = not_really_random()
+        keytable = [string_repr.convert_const("foo%d" % n)
+                    for n in range(len(referencetable))]
+
+        def complete_check():
+            for n, refvalue in zip(range(len(referencetable)), referencetable):
+                try:
+                    gotvalue = rdict.ll_dict_getitem(l_dict, keytable[n])
+                except KeyError:
+                    assert refvalue is None
+                else:
+                    assert gotvalue == refvalue
+
+        for x in not_really_random():
+            n = int(x*100.0)    # 0 <= x < 400
+            op = repr(x)[-1]
+            if op <= '2' and referencetable[n] is not None:
+                rdict.ll_dict_delitem(l_dict, keytable[n])
+                referencetable[n] = None
+                referencelength -= 1
+            elif op <= '6':
+                ll_value = string_repr.convert_const(str(values.next()))
+                rdict.ll_dict_setitem(l_dict, keytable[n], ll_value)
+                if referencetable[n] is None:
+                    referencelength += 1
+                referencetable[n] = ll_value
+            else:
+                try:
+                    gotvalue = rdict.ll_dict_getitem(l_dict, keytable[n])
+                except KeyError:
+                    assert referencetable[n] is None
+                else:
+                    assert gotvalue == referencetable[n]
+            if 1.38 <= x <= 1.39:
+                complete_check()
+                print 'current dict length:', referencelength
+            assert l_dict.num_items == referencelength
+        complete_check()



More information about the Pypy-commit mailing list