Rev 130: the collection now manages a weakref list of proxy instances. in http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

John Arbash Meinel john at arbash-meinel.com
Mon Dec 28 03:30:15 GMT 2009


At http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

------------------------------------------------------------
revno: 130
revision-id: john at arbash-meinel.com-20091228033001-vwjof7itsddctrua
parent: john at arbash-meinel.com-20091228005448-hm6ll74g7cw7slw2
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: mem-object-collection
timestamp: Sun 2009-12-27 21:30:01 -0600
message:
  the collection now manages a weakref list of proxy instances.
  
  This way, when an item is deleted, we can invalidate its proxy, even if
  we can't get rid of the proxy itself.
  An alternative would be to transfer the memory control over to the proxy,
  assuming we always have one-and-only-one proxy.
-------------- next part --------------
=== modified file 'meliae/_loader.pyx'
--- a/meliae/_loader.pyx	2009-12-28 00:54:48 +0000
+++ b/meliae/_loader.pyx	2009-12-28 03:30:01 +0000
@@ -37,6 +37,8 @@
     # void fprintf(void *, char *, ...)
     # void *stderr
 
+import weakref
+
 
 ctypedef struct RefList:
     long size
@@ -166,40 +168,37 @@
         self.collection = collection
         self._obj = NULL
 
-    cdef _MemObject *_get_obj(self) except NULL:
+    cdef _MemObject *_ensure_obj(self) except NULL:
         if self._obj is NULL:
             raise RuntimeError('_MemObjectProxy was deleted underneath it.')
         return self._obj
 
+    def is_valid(self):
+        if self._obj is NULL:
+            return False
+        return True
+
     property type_str:
         """The type of this object."""
         def __get__(self):
-            cdef _MemObject *slot
-
-            slot = self._get_obj()
-            return <object>(slot.type_str)
+            self._ensure_obj()
+            return <object>(self._obj.type_str)
 
     property size:
         """The number of bytes allocated for this object."""
         def __get__(self):
-            cdef _MemObject *slot
-
-            slot = self._get_obj()
-            return slot.size
+            self._ensure_obj()
+            return self._obj.size
 
         def __set__(self, value):
-            cdef _MemObject *slot
-
-            slot = self._get_obj()
-            slot.size = value
+            self._ensure_obj()
+            self._obj.size = value
 
     def __len__(self):
-        cdef _MemObject *slot
-
-        slot = self._get_obj()
-        if slot.ref_list == NULL:
+        self._ensure_obj()
+        if self._obj.ref_list == NULL:
             return 0
-        return slot.ref_list.size
+        return self._obj.ref_list.size
 
     # def __getitem__(self, offset):
     #     cdef _MemObject *slot
@@ -223,12 +222,14 @@
     cdef readonly int _table_mask  # N slots = table_mask + 1
     cdef readonly int _active      # How many slots have real data
     cdef readonly int _filled      # How many slots have real or dummy
-    cdef _MemObject** _table # _MemObjects are stored inline
+    cdef _MemObject** _table       # _MemObjects are stored inline
+    cdef public object _proxies    # _MemObjectProxy instances
 
     def __init__(self):
         self._table_mask = 1024 - 1
         self._table = <_MemObject**>PyMem_Malloc(sizeof(_MemObject*)*1024)
         memset(self._table, 0, sizeof(_MemObject*)*1024)
+        self._proxies = weakref.WeakValueDictionary()
 
     cdef _MemObject** _lookup(self, address) except NULL:
         cdef long the_hash
@@ -320,8 +321,12 @@
         if slot[0] == NULL or slot[0] == _dummy:
             raise KeyError('address %s not present' % (at,))
         if proxy is None:
-            proxy = _MemObjectProxy(address, self)
-            proxy._obj = slot[0]
+            if address in self._proxies:
+                proxy = self._proxies[address]
+            else:
+                proxy = _MemObjectProxy(address, self)
+                proxy._obj = slot[0]
+                self._proxies[address] = proxy
         return proxy
 
     def __delitem__(self, at):
@@ -336,6 +341,9 @@
         slot = self._lookup(address)
         if slot[0] == NULL or slot[0] == _dummy:
             raise KeyError('address %s not present' % (at,))
+        proxy = self._proxies.get(address, None)
+        if proxy is not None:
+            proxy._obj = NULL
         self._clear_slot(slot)
         slot[0] = _dummy
         # TODO: Shrink

=== modified file 'meliae/tests/test__loader.py'
--- a/meliae/tests/test__loader.py	2009-12-28 00:54:48 +0000
+++ b/meliae/tests/test__loader.py	2009-12-28 03:30:01 +0000
@@ -223,3 +223,11 @@
         self.assertEqual(1024, mop.size)
         self.assertEqual(1024, self.moc[0].size)
         self.assertEqual(0, len(mop))
+
+    def test_deleted_proxy(self):
+        mop = self.moc[0]
+        del self.moc[0]
+        self.assertFalse(mop.is_valid())
+        self.assertRaises(RuntimeError, lambda: mop.type_str)
+        self.assertRaises(RuntimeError, lambda: mop.size)
+        self.assertRaises(RuntimeError, len, mop)



More information about the bazaar-commits mailing list