summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2009-11-27 16:22:46 -0200
committerHugo Lima <hugo.lima@openbossa.org>2009-11-27 16:53:13 -0200
commiteb5cadcdddf834d5df0b36d19d9411e4cf931cce (patch)
tree3ba054a53b9bde5b843748da179784fa4581d459
parent3c2e7df28e219a1628f7ed0f1e63b831d07fc69c (diff)
downloadshiboken-eb5cadcdddf834d5df0b36d19d9411e4cf931cce.tar.gz
shiboken-eb5cadcdddf834d5df0b36d19d9411e4cf931cce.tar.xz
shiboken-eb5cadcdddf834d5df0b36d19d9411e4cf931cce.zip
Implemented primitives to solve the parent/children problem.
Reviewed by Marcelo Lira <marcelo.lira@openbossa.org>
-rw-r--r--cppgenerator.cpp60
-rw-r--r--cppgenerator.h1
-rw-r--r--libshiboken/basewrapper.cpp114
-rw-r--r--libshiboken/basewrapper.h51
4 files changed, 184 insertions, 42 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index 282e7bd5..bf8d3580 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 19002224..b001acf4 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 bf33a9e5..7c0497f1 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 a65c9096..90c38c73 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
-