[pypy-svn] r25223 - in pypy/dist/pypy: tool/algo tool/algo/test translator/tool

arigo at codespeak.net arigo at codespeak.net
Sun Apr 2 15:46:05 CEST 2006


Author: arigo
Date: Sun Apr  2 15:46:04 2006
New Revision: 25223

Added:
   pypy/dist/pypy/tool/algo/multiweakdict.py
   pypy/dist/pypy/tool/algo/test/test_multiweakdict.py
Modified:
   pypy/dist/pypy/translator/tool/reftracker.py
Log:
(arre, pedronis, arigo)

* fix the reference tracker to display non-negative id's

* a MultiWeakKeyDictionary: like a WeakKeyDictionary but
  with tuples as keys; when any item of a key is deallocated,
  the whole entry is removed from the dict.

NB: we're not sure at all we'll actually use it, but we
had fun writing it anyway.


Added: pypy/dist/pypy/tool/algo/multiweakdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/tool/algo/multiweakdict.py	Sun Apr  2 15:46:04 2006
@@ -0,0 +1,45 @@
+import weakref
+import UserDict
+
+
+class MultiWeakKeyDictionary(UserDict.DictMixin):
+
+    def __init__(self):
+        self._bylength = {}
+
+    def __getitem__(self, key):
+        key = (len(key),) + key
+        d = self._bylength
+        for step in key:
+            d = d[step]
+        return d
+
+    def __setitem__(self, key, value):
+        key = (len(key),) + key
+        d = self._bylength
+        for step in key[:-1]:
+            try:
+                d = d[step]
+            except KeyError:
+                d[step] = newd = weakref.WeakKeyDictionary()
+                d = newd
+        d[key[-1]] = value
+
+    def __delitem__(self, key):
+        key = (len(key),) + key
+        d = self._bylength
+        for step in key[:-1]:
+            d = d[step]
+        del d[key[-1]]
+
+    def keys(self):
+        result = []
+        def enumkeys(initialkey, d, result):
+            if len(initialkey) == length:
+                result.append(initialkey)
+            else:
+                for key, value in d.iteritems():
+                    enumkeys(initialkey + (key,), value, result)
+        for length, d in self._bylength.iteritems():
+            enumkeys((), d, result)
+        return result

Added: pypy/dist/pypy/tool/algo/test/test_multiweakdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/tool/algo/test/test_multiweakdict.py	Sun Apr  2 15:46:04 2006
@@ -0,0 +1,52 @@
+import py, gc
+from pypy.tool.algo.multiweakdict import MultiWeakKeyDictionary
+
+
+class A(object):
+    pass
+
+
+def test_simple():
+    d = MultiWeakKeyDictionary()
+    a1 = A()
+    a2 = A()
+    a3 = A()
+    d[a1, a2] = 12
+    d[a1,] = 1
+    d[a2,] = 2
+    d[a2, a1] = 21
+    d[a2, a2] = 22
+    d[()] = 0
+    assert d[a1, a2] == 12
+    assert d[a1,] == 1
+    assert d[a2,] == 2
+    assert d[a2, a1] == 21
+    assert d[a2, a2] == 22
+    assert d[()] == 0
+    assert dict.fromkeys(d.keys()) == {(a1, a2): None,
+                                       (a1,): None,
+                                       (a2,): None,
+                                       (a2, a1): None,
+                                       (a2, a2): None,
+                                       (): None}
+    del d[a2,]
+    assert dict.fromkeys(d.keys()) == {(a1, a2): None,
+                                       (a1,): None,
+                                       (a2, a1): None,
+                                       (a2, a2): None,
+                                       (): None}
+    assert d[a1, a2] == 12
+    assert d[a1,] == 1
+    assert d[a2, a1] == 21
+    assert d[a2, a2] == 22
+    assert d[()] == 0
+    py.test.raises(KeyError, "d[a2,]")
+
+    del a1
+    locals()   # obscure fix for CPython -- make sure a1 is no longer in
+               # the cached f_locals of the frame
+    gc.collect()   # less obscure fix for other Python implementations
+    assert dict.fromkeys(d.keys()) == {(a2, a2): None,
+                                       (): None}
+    assert d[a2, a2] == 22
+    assert d[()] == 0

Modified: pypy/dist/pypy/translator/tool/reftracker.py
==============================================================================
--- pypy/dist/pypy/translator/tool/reftracker.py	(original)
+++ pypy/dist/pypy/translator/tool/reftracker.py	Sun Apr  2 15:46:04 2006
@@ -6,6 +6,7 @@
 import autopath
 import gc
 from pypy.translator.tool.graphpage import GraphPage, DotGen
+from pypy.tool.uid import uid
 
 
 MARKER = object()
@@ -22,7 +23,7 @@
         edges = {}
 
         def addedge(o1, o2):
-            key = (id(o1), id(o2))
+            key = (uid(o1), uid(o2))
             slst = []
             if type(o1) in (list, tuple):
                 for i in range(len(o1)):
@@ -36,7 +37,7 @@
 
         for i in range(1, len(objectlist)):
             s = repr(objectlist[i])
-            word = '0x%x' % id(objectlist[i])
+            word = '0x%x' % uid(objectlist[i])
             if len(s) > 50:
                 self.links[word] = s
                 s = s[:20] + ' ... ' + s[-20:]
@@ -45,12 +46,12 @@
                                     s)
             nodename = 'node%d' % len(nodes)
             dotgen.emit_node(nodename, label=s, shape="box")
-            nodes[id(objectlist[i])] = nodename
+            nodes[uid(objectlist[i])] = nodename
             for o2 in gc.get_referents(objectlist[i]):
                 if o2 is None:
                     continue
                 addedge(objectlist[i], o2)
-                id2typename[id(o2)] = type(o2).__name__
+                id2typename[uid(o2)] = type(o2).__name__
                 del o2
             for o2 in gc.get_referrers(objectlist[i]):
                 if o2 is None:
@@ -58,7 +59,7 @@
                 if type(o2) is list and o2 and o2[0] is MARKER:
                     continue
                 addedge(o2, objectlist[i])
-                id2typename[id(o2)] = type(o2).__name__
+                id2typename[uid(o2)] = type(o2).__name__
                 del o2
 
         for ids, label in edges.items():
@@ -81,10 +82,10 @@
         objectlist = self.objectlist
         for i in range(1, len(objectlist)):
             for o2 in gc.get_referents(objectlist[i]):
-                if id(o2) == id1:
+                if uid(o2) == id1:
                     found = o2
             for o2 in gc.get_referrers(objectlist[i]):
-                if id(o2) == id1:
+                if uid(o2) == id1:
                     found = o2
         if found is not None:
             objectlist = objectlist + [found]



More information about the Pypy-commit mailing list