patch [#26215] Python weak reference (weakref) support for game objects
authorCampbell Barton <ideasman42@gmail.com>
Fri, 25 Feb 2011 14:32:35 +0000 (14:32 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 25 Feb 2011 14:32:35 +0000 (14:32 +0000)
by Alex Fraser (z0r)

source/gameengine/Expressions/PyObjectPlus.cpp
source/gameengine/Expressions/PyObjectPlus.h

index a3c1e24cdf689b58a3c568b3b2f9cd6b4a34c711..84d6a1cba4bfdc221b578d000c7625d69a81a5f1 100644 (file)
@@ -108,19 +108,26 @@ void PyObjectPlus::InvalidateProxy()              // check typename of each parent
 
 PyTypeObject PyObjectPlus::Type = {
        PyVarObject_HEAD_INIT(NULL, 0)
-       "PyObjectPlus",                 /*tp_name*/
+       "PyObjectPlus",                                 /*tp_name*/
        sizeof(PyObjectPlus_Proxy),             /*tp_basicsize*/
-       0,                              /*tp_itemsize*/
+       0,                                                              /*tp_itemsize*/
        /* methods */
-       py_base_dealloc,
-       0,
-       0,
-       0,
+       py_base_dealloc,                                /* tp_dealloc */
+       0,                                                              /* printfunc tp_print; */
+       0,                                                              /* getattrfunc tp_getattr; */
+       0,                                                              /* setattrfunc tp_setattr; */
+       0,                                                              /* tp_compare */ /* DEPRECATED in python 3.0! */
+       py_base_repr,                                   /* tp_repr */
+       0,0,0,0,0,0,0,0,0,                              /* Method suites for standard classes */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* long tp_flags; */
+       0,0,0,0,
+       /* weak reference enabler */
+#ifdef USE_WEAKREFS
+       offsetof(PyObjectPlus_Proxy, in_weakreflist),   /* long tp_weaklistoffset; */
+#else
        0,
-       py_base_repr,
-       0,0,0,0,0,0,0,0,0,
-       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-       0,0,0,0,0,0,0,
+#endif
+       0,0,
        Methods,
        0,
        0,
@@ -209,8 +216,16 @@ PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObjec
        return (PyObject *)ret;
 }
 
+/**
+  * @param self A PyObjectPlus_Proxy
+  */
 void PyObjectPlus::py_base_dealloc(PyObject *self)                             // python wrapper
 {
+#ifdef USE_WEAKREFS
+       if (BGE_PROXY_WKREF(self) != NULL)
+               PyObject_ClearWeakRefs((PyObject *) self);
+#endif
+
        if (BGE_PROXY_PYREF(self)) {
                PyObjectPlus *self_plus= BGE_PROXY_REF(self);
                if(self_plus) {
@@ -1107,6 +1122,7 @@ PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, v
                self->m_proxy = reinterpret_cast<PyObject *>PyObject_NEW( PyObjectPlus_Proxy, tp);
                BGE_PROXY_PYOWNS(self->m_proxy) = false;
                BGE_PROXY_PYREF(self->m_proxy) = true;
+               BGE_PROXY_WKREF(self->m_proxy) = NULL;
        }
        //PyObject_Print(self->m_proxy, stdout, 0);
        //printf("ref %d\n", self->m_proxy->ob_refcnt);
@@ -1127,6 +1143,7 @@ PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, v
                BGE_PROXY_PYOWNS(proxy) = py_owns;
                BGE_PROXY_REF(proxy) = NULL; 
                BGE_PROXY_PTR(proxy) = ptr;
+               BGE_PROXY_WKREF(self->m_proxy) = NULL;
                return proxy;
        }
        if (self->m_proxy)
index 12ae31f6c8218dd45a1ca9b736b73a524648aa97..315a328317dd869e541df497b658dcffd3d989dd 100644 (file)
@@ -31,6 +31,9 @@
  *  \ingroup expressions
  */
 
+/* for now keep weakrefs optional */
+#define USE_WEAKREFS
+
 #ifndef _adr_py_lib_h_                         // only process once,
 #define _adr_py_lib_h_                         // even if multiply included
 
@@ -95,6 +98,9 @@ typedef struct PyObjectPlus_Proxy {
        void *ptr;                                      // optional pointer to generic structure, the structure holds no reference to this proxy
        bool py_owns;           // true if the object pointed by ref should be deleted when the proxy is deleted
        bool py_ref;            // true if proxy is connected to a GE object (ref is used)
+#ifdef USE_WEAKREFS
+       PyObject *in_weakreflist; // weak reference enabler
+#endif
 } PyObjectPlus_Proxy;
 
 #define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable"
@@ -102,6 +108,7 @@ typedef struct PyObjectPlus_Proxy {
 #define BGE_PROXY_PTR(_self) (((PyObjectPlus_Proxy *)_self)->ptr)
 #define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns)
 #define BGE_PROXY_PYREF(_self) (((PyObjectPlus_Proxy *)_self)->py_ref)
+#define BGE_PROXY_WKREF(_self) (((PyObjectPlus_Proxy *)_self)->in_weakreflist)
 
 /* Note, sometimes we dont care what BGE type this is as long as its a proxy */
 #define BGE_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == PyObjectPlus::py_base_dealloc)