[pypy-svn] r5031 - in pypy/trunk/src/pypy/objspace/std: . test

arigo at codespeak.net arigo at codespeak.net
Thu Jun 10 15:55:52 CEST 2004


Author: arigo
Date: Thu Jun 10 15:55:51 2004
New Revision: 5031

Modified:
   pypy/trunk/src/pypy/objspace/std/dictobject.py
   pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py
Log:
noticing 'class A: pass' hung where 'class C: pass' did not we hunted and
killed a bug in dictionaries to do with horrible signedness issues.

added hopefully comprehensive test of the dictionary mechanics 


Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/dictobject.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/dictobject.py	Thu Jun 10 15:55:51 2004
@@ -9,6 +9,8 @@
 from pypy.interpreter import gateway
 from stringobject import W_StringObject
 
+from restricted_int import r_uint
+
 dummy = object()
 
 class W_DictObject(W_Object):
@@ -18,15 +20,19 @@
         W_Object.__init__(w_self, space)
         
         w_self.used = 0
-        w_self.data = [[0, None, None]]
+        w_self.data = [[r_uint(0), None, None]]
         w_self.resize(len(list_pairs_w)*2)
         for w_k, w_v in list_pairs_w:
-            w_self.insert(space.unwrap(space.hash(w_k)), w_k, w_v)
+            w_self.insert(w_self.hash(w_k), w_k, w_v)
         
     def __repr__(w_self):
         """ representation for debugging purposes """
         return "%s(%s)" % (w_self.__class__.__name__, w_self.data)
 
+    def hash(w_self, w_obj):
+        space = w_self.space
+        return r_uint(space.unwrap(space.hash(w_obj)))
+
     def insert(self, h, w_key, w_value):
         cell = self.lookdict(h, w_key)
         if cell[2] is None:
@@ -42,7 +48,7 @@
         od = self.data
 
         self.used = 0
-        self.data = [[0, None, None] for i in range(newsize)]
+        self.data = [[r_uint(0), None, None] for i in range(newsize)]
         for h, k, v in od:
             if v is not None:
                 self.insert(h, k, v)
@@ -51,6 +57,7 @@
         return [(h, w_k, w_v) for (h, w_k, w_v) in self.data if w_v is not None]
         
     def lookdict(self, lookup_hash, w_lookup):
+        assert isinstance(lookup_hash, r_uint)
         space = self.space
         i = lookup_hash % len(self.data)
 
@@ -67,9 +74,14 @@
             freeslot = None
 
         perturb = lookup_hash
+        c = 0
         while 1:
-            # XXX HAAAAAAACK to avoid FutureWarnings :-(
-            i = ((i & 0x1FFFFFFF) << 2) + i + perturb + 1
+            c += 1
+            if c > 1000:
+                import pdb
+                pdb.set_trace()
+                
+            i = (i << 2) + i + perturb + 1
             entry = self.data[i%len(self.data)]
             if entry[1] is None:
                 if freeslot:
@@ -114,19 +126,19 @@
     space.call_method(w_dict, 'update', w_kwds)
 
 def getitem__Dict_ANY(space, w_dict, w_lookup):
-    entry = w_dict.lookdict(space.unwrap(space.hash(w_lookup)), w_lookup)
+    entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup)
     if entry[2] is not None:
         return entry[2]
     else:
         raise OperationError(space.w_KeyError, w_lookup)
 
 def setitem__Dict_ANY_ANY(space, w_dict, w_newkey, w_newvalue):
-    w_dict.insert(space.unwrap(space.hash(w_newkey)), w_newkey, w_newvalue)
+    w_dict.insert(w_dict.hash(w_newkey), w_newkey, w_newvalue)
     if 2*w_dict.used > len(w_dict.data):
         w_dict.resize(2*w_dict.used)
 
 def delitem__Dict_ANY(space, w_dict, w_lookup):
-    entry = w_dict.lookdict(space.unwrap(space.hash(w_lookup)), w_lookup)
+    entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup)
     if entry[2] is not None:
         w_dict.used -= 1
         entry[1] = dummy
@@ -138,7 +150,7 @@
     return space.wrap(w_dict.used)
 
 def contains__Dict_ANY(space, w_dict, w_lookup):
-    entry = w_dict.lookdict(space.unwrap(space.hash(w_lookup)), w_lookup)
+    entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup)
     return space.newbool(entry[2] is not None)
 
 dict_has_key__Dict_ANY = contains__Dict_ANY
@@ -216,7 +228,7 @@
     w_self.used = 0
 
 def dict_get__Dict_ANY_ANY(space, w_dict, w_lookup, w_default):
-    entry = w_dict.lookdict(space.unwrap(space.hash(w_lookup)), w_lookup)
+    entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup)
     if entry[2] is not None:
         return entry[2]
     else:

Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py	(original)
+++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py	Thu Jun 10 15:55:51 2004
@@ -344,5 +344,41 @@
         self.assertEquals({1: 0, 2: 0, 3: 0}.fromkeys([1, '1'], 'j'),
                           {1: 'j', '1': 'j'})
 
+# the minimal 'space' needed to use a W_DictObject
+class FakeSpace:
+    def hash(self, obj):
+        return hash(obj)
+    def unwrap(self, x):
+        return x
+    def is_true(self, x):
+        return x
+    def is_(self, x, y):
+        return x is y
+    def eq(self, x, y):
+        return x == y
+
+from pypy.objspace.std.dictobject import getitem__Dict_ANY, setitem__Dict_ANY_ANY
+
+class TestDictImplementation(testit.TestCase):
+    
+    def setUp(self):
+        self.space = FakeSpace()
+
+    def tearDown(self):
+        pass
+
+    def test_stressdict(self):
+        from random import randint
+        d = W_DictObject(self.space, [])
+        N = 10000
+        pydict = {}
+        for i in range(N):
+            x = randint(-N, N)
+            setitem__Dict_ANY_ANY(self.space, d, x, i)
+            pydict[x] = i
+        for x in pydict:
+            self.assertEqual(pydict[x], getitem__Dict_ANY(self.space, d, x))
+            
+
 if __name__ == '__main__':
     testit.main()



More information about the Pypy-commit mailing list