diff options
-rw-r--r-- | cppgenerator.cpp | 60 | ||||
-rw-r--r-- | cppgenerator.h | 1 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 114 | ||||
-rw-r--r-- | libshiboken/basewrapper.h | 51 |
4 files changed, 184 insertions, 42 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index 282e7bd5b..bf8d35803 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -425,7 +425,6 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun OverloadData overloadData(overloads, this); const AbstractMetaFunction* rfunc = overloadData.referenceFunction(); QString className = cpythonTypeName(rfunc->ownerClass()); - bool hasCppWrapper = shouldGenerateCppWrapper(rfunc->ownerClass()); s << "PyObject*" << endl; s << cpythonFunctionName(rfunc) << "(PyTypeObject *type, PyObject *args, PyObject *kwds)" << endl; @@ -433,6 +432,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun s << INDENT << "PyObject* self;" << endl; s << INDENT; + bool hasCppWrapper = shouldGenerateCppWrapper(rfunc->ownerClass()); s << (hasCppWrapper ? wrapperName(rfunc->ownerClass()) : rfunc->ownerClass()->qualifiedCppName()); s << "* cptr;" << endl << endl; @@ -457,18 +457,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream& s, const AbstractMetaFun } writeOverloadedMethodDecisor(s, &overloadData); - s << endl; - - s << INDENT << "self = Shiboken::PyBaseWrapper_New(type, &" << className << ", cptr"; - - // If the created C++ object has a C++ wrapper the ownership is assigned to Python - // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper - // is marked as true (the second "1"). Otherwise the default values apply: - // Python owns it and C++ wrapper is false. - if (hasCppWrapper) - s << ", 1, 1"; - s << ");" << endl; s << endl << INDENT << "if (!self) {" << endl; { Indentation indentation(INDENT); @@ -1142,6 +1131,21 @@ void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* f writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::TargetLangCode, func, lastArg); } + if (func->isConstructor()) { + + QString className = cpythonTypeName(func->ownerClass()); + s << INDENT << "self = Shiboken::PyBaseWrapper_New(type, &" << className << ", cptr"; + // If the created C++ object has a C++ wrapper the ownership is assigned to Python + // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper + // is marked as true (the second "1"). Otherwise the default values apply: + // Python owns it and C++ wrapper is false. + if (shouldGenerateCppWrapper(func->ownerClass())) + s << ", 1, 1"; + + s << ");" << endl; + } + writeParentChildManagement(s, func); + // Ownership transference between C++ and Python. QList<ArgumentModification> ownership_mods; foreach (FunctionModification func_mod, functionModifications(func)) { @@ -2336,3 +2340,35 @@ void CppGenerator::finishGeneration() } } } + +void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func) +{ + const int numArgs = func->arguments().count(); + const AbstractMetaClass* cppClass = func->ownerClass(); + for (int i = -1; i <= numArgs; ++i) { + QString parentVariable; + QString childVariable; + ArgumentOwner argOwner = func->argumentOwner(cppClass, i); + bool usePyArgs = getMinMaxArguments(func).second > 1 || func->isConstructor(); + + if (argOwner.action != ArgumentOwner::Invalid) { + if (!usePyArgs && i > 1) + ReportHandler::warning(""); + + if (argOwner.index == -1) + childVariable = "self"; + else + childVariable = usePyArgs ? "pyargs["+QString::number(argOwner.index-1)+"]" : "arg"; + + if (argOwner.action == ArgumentOwner::Remove) + parentVariable = "0"; + else if (i == 0) + parentVariable = "self"; + else + parentVariable = usePyArgs ? "pyargs["+QString::number(i-1)+"]" : "arg"; + + s << INDENT << "Shiboken::setParent(" << parentVariable << ", " << childVariable << ");\n"; + + } + } +} diff --git a/cppgenerator.h b/cppgenerator.h index 19002224a..b001acf4e 100644 --- a/cppgenerator.h +++ b/cppgenerator.h @@ -135,6 +135,7 @@ private: /// Writes the function that registers the multiple inheritance information for the classes that need it. void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass); + void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func); /** * Returns the multiple inheritance initializer function for the given class. * \param metaClass the class for whom the function name must be generated. 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 - |