diff options
author | Hugo Lima <hugo.lima@openbossa.org> | 2009-11-27 16:22:46 -0200 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2009-11-27 16:53:13 -0200 |
commit | eb5cadcdddf834d5df0b36d19d9411e4cf931cce (patch) | |
tree | 3ba054a53b9bde5b843748da179784fa4581d459 /libshiboken | |
parent | 3c2e7df28e219a1628f7ed0f1e63b831d07fc69c (diff) |
Implemented primitives to solve the parent/children problem.
Reviewed by Marcelo Lira <marcelo.lira@openbossa.org>
Diffstat (limited to 'libshiboken')
-rw-r--r-- | libshiboken/basewrapper.cpp | 114 | ||||
-rw-r--r-- | libshiboken/basewrapper.h | 51 |
2 files changed, 135 insertions, 30 deletions
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp index bf33a9e52..7c0497f16 100644 --- a/libshiboken/basewrapper.cpp +++ b/libshiboken/basewrapper.cpp @@ -33,42 +33,109 @@ */ #include "basewrapper.h" +#include <cstddef> +#include <algorithm> namespace Shiboken { -PyObject* -PyBaseWrapper_New(PyTypeObject* instanceType, - ShiboTypeObject* baseWrapperType, - const void* cptr, - unsigned int hasOwnership, - unsigned int containsCppWrapper) +void removeParent(PyBaseWrapper* child) +{ + if (child->parentInfo->parent) { + ShiboChildrenList& oldBrothers = child->parentInfo->parent->parentInfo->children; + oldBrothers.remove(child); + child->parentInfo->parent = 0; + Py_DECREF(child); + } +} + +void setParent(PyObject* parent, PyObject* child) +{ + if (!child || child == Py_None || child == parent) + return; + + bool parentIsNull = !parent || parent == Py_None; + + PyBaseWrapper* parent_ = reinterpret_cast<PyBaseWrapper*>(parent); + PyBaseWrapper* child_ = reinterpret_cast<PyBaseWrapper*>(child); + if (!child_->parentInfo) + child_->parentInfo = new ShiboParentInfo; + + if (!parentIsNull) { + if (!parent_->parentInfo) + parent_->parentInfo = new ShiboParentInfo; + // do not re-add a child + ShiboChildrenList& children = parent_->parentInfo->children; + if (std::find(children.begin(), children.end(), child_) != children.end()) + return; + } + + bool hasAnotherParent = child_->parentInfo->parent && child_->parentInfo->parent != parent_; + + // check if we need to remove this child from the old parent + if (parentIsNull || hasAnotherParent) + removeParent(child_); + + // Add the child to the new parent + if (!parentIsNull) { + child_->parentInfo->parent = parent_; + parent_->parentInfo->children.push_back(child_); + Py_INCREF(child_); + } +} + +void destroyParentInfo(PyBaseWrapper* obj, bool removeFromParent) +{ + if (removeFromParent && obj->parentInfo->parent) + removeParent(obj); + // invalidate all children + ShiboChildrenList::iterator it = obj->parentInfo->children.begin(); + for (; it != obj->parentInfo->children.end(); ++it) { + PyBaseWrapper*& child = *it; + destroyParentInfo(child, false); + BindingManager::instance().invalidateWrapper(reinterpret_cast<PyObject*>(child)); + Py_DECREF(child); + } + delete obj->parentInfo; + obj->parentInfo = 0; +} + +PyObject* PyBaseWrapper_New(PyTypeObject* instanceType, + ShiboTypeObject* baseWrapperType, + const void* cptr, + unsigned int hasOwnership, + unsigned int containsCppWrapper) { if (!cptr) return 0; - PyObject* self = ((ShiboTypeObject*) instanceType)->pytype.tp_alloc((PyTypeObject*) instanceType, 0); - ((PyBaseWrapper*)self)->baseWrapperType = baseWrapperType; - ((PyBaseWrapper*)self)->cptr = const_cast<void*>(cptr); - ((PyBaseWrapper*)self)->hasOwnership = hasOwnership; - ((PyBaseWrapper*)self)->containsCppWrapper = containsCppWrapper; - ((PyBaseWrapper*)self)->validCppObject = 1; - if (((ShiboTypeObject*) instanceType)->mi_init && !((ShiboTypeObject*) instanceType)->mi_offsets) - ((ShiboTypeObject*) instanceType)->mi_offsets = ((ShiboTypeObject*) instanceType)->mi_init(cptr); - BindingManager::instance().assignWrapper(self, cptr); - if (((ShiboTypeObject*) instanceType)->mi_offsets) { - int* offset = ((ShiboTypeObject*) instanceType)->mi_offsets; + ShiboTypeObject* const& instanceType_ = reinterpret_cast<ShiboTypeObject*>(instanceType); + PyBaseWrapper* self = (PyBaseWrapper*)instanceType_->pytype.tp_alloc((PyTypeObject*) instanceType, 0); + + self->baseWrapperType = baseWrapperType; + self->cptr = const_cast<void*>(cptr); + self->hasOwnership = hasOwnership; + self->containsCppWrapper = containsCppWrapper; + self->validCppObject = 1; + self->parentInfo = 0; + + if (instanceType_->mi_init && !instanceType_->mi_offsets) + instanceType_->mi_offsets = instanceType_->mi_init(cptr); + BindingManager::instance().assignWrapper(reinterpret_cast<PyObject*>(self), cptr); + if (instanceType_->mi_offsets) { + int* offset = instanceType_->mi_offsets; while (*offset != -1) { - if (*offset > 0) - BindingManager::instance().assignWrapper(self, (void*) ((size_t) cptr + (*offset))); + if (*offset > 0) { + BindingManager::instance().assignWrapper(reinterpret_cast<PyObject*>(self), + reinterpret_cast<void*>((std::size_t) cptr + (*offset))); + } offset++; } } - return self; + return reinterpret_cast<PyObject*>(self); } -bool -cppObjectIsInvalid(PyObject* wrapper) +bool cppObjectIsInvalid(PyObject* wrapper) { if (((Shiboken::PyBaseWrapper*)wrapper)->validCppObject) return false; @@ -76,8 +143,7 @@ cppObjectIsInvalid(PyObject* wrapper) return true; } -void -PyBaseWrapper_Dealloc_PrivateDtor(PyObject* self) +void PyBaseWrapper_Dealloc_PrivateDtor(PyObject* self) { BindingManager::instance().releaseWrapper(self); Py_TYPE(((PyBaseWrapper*)self))->tp_free((PyObject*)self); diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h index a65c9096a..90c38c735 100644 --- a/libshiboken/basewrapper.h +++ b/libshiboken/basewrapper.h @@ -37,18 +37,34 @@ #include <Python.h> #include "bindingmanager.h" +#include <list> namespace Shiboken { -extern "C" +struct PyBaseWrapper; + +/// Linked list of PyBaseWrapper pointers +typedef std::list<PyBaseWrapper*> ShiboChildrenList; + +/// Struct used to store information about object parent and children. +struct LIBSHIBOKEN_API ShiboParentInfo { + /// Default ctor. + ShiboParentInfo() : parent(0) {} + /// Pointer to parent object. + PyBaseWrapper* parent; + /// List of object children. + ShiboChildrenList children; +}; +extern "C" +{ /// Function signature for the multiple inheritance information initializers that should be provided by classes with multiple inheritance. typedef int* (*MultipleInheritanceInitFunction)(const void*); -// PyTypeObject extended with C++ multiple inheritance information. -struct ShiboTypeObject +/// PyTypeObject extended with C++ multiple inheritance information. +struct LIBSHIBOKEN_API ShiboTypeObject { PyTypeObject pytype; int* mi_offsets; @@ -56,7 +72,7 @@ struct ShiboTypeObject }; /// Base Python object for all the wrapped C++ classes. -struct PyBaseWrapper +struct LIBSHIBOKEN_API PyBaseWrapper { PyObject_HEAD /// First binding provided parent type of a Python class that inherits from a wrapped class. @@ -69,10 +85,32 @@ struct PyBaseWrapper unsigned int containsCppWrapper : 1; /// Marked as false when the object is lost to C++ and the binding can not know if it was deleted or not. unsigned int validCppObject : 1; + /// Information about the object parents and children, can be null. + ShiboParentInfo* parentInfo; }; } // extern "C" +/** +* Set the parent of \p child to \p parent. +* When an object dies, all their children, granchildren, etc, are tagged as invalid. +* \param parent the parent object, if null, the child will have no parents. +* \param child the child. +*/ +LIBSHIBOKEN_API void setParent(PyObject* parent, PyObject* child); + +/** +* Remove this child from their parent, if any. +* \param child the child. +*/ +LIBSHIBOKEN_API void removeParent(PyBaseWrapper* child); + +/** +* \internal This is an internal function called by PyBaseWrapper_Dealloc, it's exported just for techinical reasons. +* \note Do not call this function inside your bindings. +*/ +LIBSHIBOKEN_API void destroyParentInfo(PyBaseWrapper* obj, bool removeFromParent = true); + #define PyBaseWrapper_Check(op) PyObject_TypeCheck(op, &Shiboken::PyBaseWrapper_Type) #define PyBaseWrapper_CheckExact(op) ((op)->ob_type == &Shiboken::PyBaseWrapper_Type) @@ -80,6 +118,7 @@ struct PyBaseWrapper #define PyBaseWrapper_setCptr(pyobj,c) (((Shiboken::PyBaseWrapper*)pyobj)->cptr = c) #define PyBaseWrapper_hasOwnership(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->hasOwnership) #define PyBaseWrapper_setOwnership(pyobj,o) (((Shiboken::PyBaseWrapper*)pyobj)->hasOwnership = o) +#define PyBaseWrapper_hasParentInfo(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->parentInfo) #define PyBaseWrapper_containsCppWrapper(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->containsCppWrapper) #define PyBaseWrapper_setContainsCppWrapper(pyobj,o)(((Shiboken::PyBaseWrapper*)pyobj)->containsCppWrapper= o) #define PyBaseWrapper_validCppObject(pyobj) (((Shiboken::PyBaseWrapper*)pyobj)->validCppObject) @@ -133,7 +172,6 @@ typedef struct { #define Py_TPFLAGS_HAVE_NEWBUFFER 0 #endif - LIBSHIBOKEN_API PyAPI_FUNC(PyObject*) PyBaseWrapper_New(PyTypeObject* instanceType, ShiboTypeObject* baseWrapperType, @@ -150,6 +188,8 @@ void PyBaseWrapper_Dealloc(PyObject* self) BindingManager::instance().releaseWrapper(self); if (PyBaseWrapper_hasOwnership(self)) delete ((T*)PyBaseWrapper_cptr(self)); + if (PyBaseWrapper_hasParentInfo(self)) + destroyParentInfo(reinterpret_cast<PyBaseWrapper*>(self)); Py_TYPE(((PyBaseWrapper*)self))->tp_free((PyObject*)self); } @@ -158,4 +198,3 @@ LIBSHIBOKEN_API PyAPI_FUNC(void) PyBaseWrapper_Dealloc_PrivateDtor(PyObject* sel } // namespace Shiboken #endif // BASEWRAPPER_H - |