aboutsummaryrefslogtreecommitdiffstats
path: root/libshiboken
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2010-03-29 17:47:02 -0300
committerHugo Lima <hugo.lima@openbossa.org>2010-03-30 17:46:07 -0300
commitc0c093d485798aec96ea7a7230c0639797cd9830 (patch)
tree6014447a087ccb846b598d0a456d89708ccf00fa /libshiboken
parent6046687f8f78e1b674e7b4265ce5fb93dce078eb (diff)
Add support for multiple inheritance involving more than one C++ object.
Diffstat (limited to 'libshiboken')
-rw-r--r--libshiboken/basewrapper.cpp134
-rw-r--r--libshiboken/basewrapper.h18
-rw-r--r--libshiboken/basewrapper_p.h139
-rw-r--r--libshiboken/bindingmanager.cpp27
-rw-r--r--libshiboken/bindingmanager.h2
-rw-r--r--libshiboken/conversions.h13
6 files changed, 295 insertions, 38 deletions
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
index 620021700..9fa7e7ef6 100644
--- a/libshiboken/basewrapper.cpp
+++ b/libshiboken/basewrapper.cpp
@@ -33,11 +33,13 @@
*/
#include "basewrapper.h"
+#include "basewrapper_p.h"
#include <cstddef>
#include <algorithm>
#include "autodecref.h"
#include "typeresolver.h"
#include <string>
+#include <cstring>
namespace Shiboken
{
@@ -137,18 +139,42 @@ PyObject* SbkBaseWrapper_New(SbkBaseWrapperType* instanceType,
instanceType = instanceType->type_discovery->getType(cptr, instanceType);
SbkBaseWrapper* self = reinterpret_cast<SbkBaseWrapper*>(SbkBaseWrapper_TpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0));
- self->cptr = const_cast<void*>(cptr);
+ self->cptr[0] = cptr;
self->hasOwnership = hasOwnership;
self->validCppObject = 1;
- BindingManager::instance().registerWrapper(self);
+ BindingManager::instance().registerWrapper(self, cptr);
return reinterpret_cast<PyObject*>(self);
}
+void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor)
+{
+ PyObject* bases = currentType->tp_bases;
+ Py_ssize_t numBases = PyTuple_GET_SIZE(bases);
+ for (int i = 0; i < numBases; ++i) {
+ PyTypeObject* type = reinterpret_cast<PyTypeObject*>(PyTuple_GET_ITEM(bases, i));
+
+ if (type->ob_type != &Shiboken::SbkBaseWrapperType_Type) {
+ continue;
+ } else {
+ SbkBaseWrapperType* sbkType = reinterpret_cast<SbkBaseWrapperType*>(type);
+ if (sbkType->is_multicpp)
+ walkThroughClassHierarchy(type, visitor);
+ else
+ visitor->visit(sbkType);
+ }
+ if (visitor->wasFinished())
+ return;
+ }
+}
+
PyObject* SbkBaseWrapper_TpNew(PyTypeObject* subtype, PyObject*, PyObject*)
{
Shiboken::AutoDecRef emptyTuple(PyTuple_New(0));
SbkBaseWrapper* self = reinterpret_cast<SbkBaseWrapper*>(PyBaseObject_Type.tp_new(subtype, emptyTuple, 0));
- self->cptr = 0;
+
+ int numBases = reinterpret_cast<SbkBaseWrapperType*>(subtype)->is_multicpp ? getNumberOfCppBaseClasses(subtype) : 1;
+ self->cptr = new void*[numBases];
+ std::memset(self->cptr, 0, sizeof(void*)*numBases);
self->hasOwnership = 1;
self->containsCppWrapper = 0;
self->validCppObject = 0;
@@ -159,6 +185,30 @@ PyObject* SbkBaseWrapper_TpNew(PyTypeObject* subtype, PyObject*, PyObject*)
return reinterpret_cast<PyObject*>(self);
}
+void* getCppPointer(PyObject* wrapper, PyTypeObject* desiredType)
+{
+ PyTypeObject* type = wrapper->ob_type;
+ int idx = 0;
+ if (reinterpret_cast<SbkBaseWrapperType*>(type)->is_multicpp)
+ idx = getTypeIndexOnHierarchy(type, desiredType);
+ return reinterpret_cast<Shiboken::SbkBaseWrapper*>(wrapper)->cptr[idx];
+}
+
+bool setCppPointer(SbkBaseWrapper* wrapper, PyTypeObject* desiredType, void* cptr)
+{
+ int idx = 0;
+ if (reinterpret_cast<SbkBaseWrapperType*>(wrapper->ob_type)->is_multicpp)
+ idx = getTypeIndexOnHierarchy(wrapper->ob_type, desiredType);
+
+ bool alreadyInitialized = wrapper->cptr[idx];
+ if (alreadyInitialized)
+ PyErr_SetString(PyExc_RuntimeError, "You can't initialize an object twice!");
+ else
+ wrapper->cptr[idx] = cptr;
+
+ return !alreadyInitialized;
+}
+
bool cppObjectIsInvalid(PyObject* wrapper)
{
if (wrapper == Py_None
@@ -172,7 +222,6 @@ bool cppObjectIsInvalid(PyObject* wrapper)
void SbkBaseWrapper_Dealloc_PrivateDtor(PyObject* self)
{
-
if (((SbkBaseWrapper *)self)->weakreflist)
PyObject_ClearWeakRefs(self);
@@ -222,6 +271,41 @@ bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr)
// Wrapper metatype and base type ----------------------------------------------------------
+class DtorCallerVisitor : public HierarchyVisitor
+{
+public:
+ DtorCallerVisitor(SbkBaseWrapper* pyObj) : m_count(0), m_pyObj(pyObj) {}
+ virtual void visit(SbkBaseWrapperType* node)
+ {
+ node->cpp_dtor(m_pyObj->cptr[m_count]);
+ m_count++;
+ }
+private:
+ int m_count;
+ SbkBaseWrapper* m_pyObj;
+};
+
+static void deallocPythonTypes(PyObject* pyObj)
+{
+ SbkBaseWrapper* sbkObj = reinterpret_cast<SbkBaseWrapper*>(pyObj);
+ if (sbkObj->weakreflist)
+ PyObject_ClearWeakRefs(pyObj);
+
+ BindingManager::instance().releaseWrapper(pyObj);
+ if (SbkBaseWrapper_hasOwnership(sbkObj)) {
+ DtorCallerVisitor visitor(sbkObj);
+ walkThroughClassHierarchy(pyObj->ob_type, &visitor);
+ }
+
+ if (SbkBaseWrapper_hasParentInfo(sbkObj))
+ destroyParentInfo(sbkObj);
+ SbkBaseWrapper_clearReferences(sbkObj);
+
+ delete[] sbkObj->cptr;
+ sbkObj->cptr = 0;
+ Py_TYPE(pyObj)->tp_free(pyObj);
+}
+
void deallocWrapper(PyObject* pyObj)
{
SbkBaseWrapper* sbkObj = reinterpret_cast<SbkBaseWrapper*>(pyObj);
@@ -231,15 +315,15 @@ void deallocWrapper(PyObject* pyObj)
BindingManager::instance().releaseWrapper(pyObj);
if (SbkBaseWrapper_hasOwnership(pyObj)) {
SbkBaseWrapperType* sbkType = reinterpret_cast<SbkBaseWrapperType*>(pyObj->ob_type);
- assert(!sbkType->is_python_type);
- sbkType->cpp_dtor(sbkObj->cptr);
+ assert(!sbkType->is_multicpp);
+ sbkType->cpp_dtor(sbkObj->cptr[0]);
}
if (SbkBaseWrapper_hasParentInfo(pyObj))
destroyParentInfo(sbkObj);
SbkBaseWrapper_clearReferences(sbkObj);
- delete sbkObj->cptr;
+ delete[] sbkObj->cptr;
sbkObj->cptr = 0;
Py_TYPE(pyObj)->tp_free(pyObj);
}
@@ -253,17 +337,31 @@ SbkBaseWrapperType_TpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds)
if (!newType)
return 0;
- // This expects that Python classes will inherit from only one C++ wrapped class.
- SbkBaseWrapperType* parentType = reinterpret_cast<SbkBaseWrapperType*>(PyTuple_GET_ITEM(PyTuple_GET_ITEM(args, 1), 0));
-
- newType->mi_offsets = parentType->mi_offsets;
- newType->mi_init = parentType->mi_init;
- newType->mi_specialcast = parentType->mi_specialcast;
- newType->ext_isconvertible = parentType->ext_isconvertible;
- newType->ext_tocpp = parentType->ext_tocpp;
- newType->type_discovery = parentType->type_discovery;
- newType->obj_copier = parentType->obj_copier;
-
+ std::list<SbkBaseWrapperType*> bases = getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType));
+ if (bases.size() == 1) {
+ SbkBaseWrapperType* parentType = bases.front();
+ newType->super.ht_type.tp_dealloc = parentType->super.ht_type.tp_dealloc;
+ newType->mi_offsets = parentType->mi_offsets;
+ newType->mi_init = parentType->mi_init;
+ newType->mi_specialcast = parentType->mi_specialcast;
+ newType->ext_isconvertible = parentType->ext_isconvertible;
+ newType->ext_tocpp = parentType->ext_tocpp;
+ newType->type_discovery = parentType->type_discovery;
+ newType->obj_copier = parentType->obj_copier;
+ newType->cpp_dtor = parentType->cpp_dtor;
+ newType->is_multicpp = 0;
+ } else {
+ newType->super.ht_type.tp_dealloc = &deallocPythonTypes;
+ newType->mi_offsets = 0;
+ newType->mi_init = 0;
+ newType->mi_specialcast = 0;
+ newType->ext_isconvertible = 0;
+ newType->ext_tocpp = 0;
+ newType->type_discovery = 0;
+ newType->obj_copier = 0;
+ newType->cpp_dtor = 0;
+ newType->is_multicpp = 1;
+ }
return reinterpret_cast<PyObject*>(newType);
}
diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
index b47a5cd50..c2b1e616a 100644
--- a/libshiboken/basewrapper.h
+++ b/libshiboken/basewrapper.h
@@ -111,6 +111,8 @@ struct LIBSHIBOKEN_API SbkBaseWrapperType
ExtendedToCppFunc ext_tocpp;
/// Pointer to a function responsible for deletetion of the C++ instance calling the proper destructor.
void (*cpp_dtor)(void*);
+ /// True if this type holds two or more C++ instances, e.g.: a Python class which inherits from two C++ classes.
+ int is_multicpp:1;
};
/// Base Python object for all the wrapped C++ classes.
@@ -118,7 +120,7 @@ struct LIBSHIBOKEN_API SbkBaseWrapper
{
PyObject_HEAD
/// Pointer to the C++ class.
- void* cptr;
+ void** cptr;
/// Instance dictionary.
PyObject* ob_dict;
/// True when Python is responsible for freeing the used memory.
@@ -171,6 +173,16 @@ inline bool isShibokenType(const PyObject* pyObj)
}
/**
+* Get the C++ pointer of type \p desiredType from a Python object.
+*/
+LIBSHIBOKEN_API void* getCppPointer(PyObject* wrapper, PyTypeObject* desiredType);
+
+/**
+* Set the C++ pointer of type \p desiredType of a Python object.
+*/
+LIBSHIBOKEN_API bool setCppPointer(SbkBaseWrapper* wrapper, PyTypeObject* desiredType, void* cptr);
+
+/**
* Shiboken_TypeCheck macro performs a type check using the values registered with SbkType<>() template.
*/
#define Shiboken_TypeCheck(pyobj, type) (PyObject_TypeCheck(pyobj, SbkType<type>()))
@@ -178,8 +190,6 @@ inline bool isShibokenType(const PyObject* pyObj)
#define SbkBaseWrapper_Check(op) PyObject_TypeCheck(op, (PyTypeObject*)&Shiboken::SbkBaseWrapper_Type)
#define SbkBaseWrapper_CheckExact(op) ((op)->ob_type == &Shiboken::SbkBaseWrapper_Type)
-#define SbkBaseWrapper_cptr(pyobj) (((Shiboken::SbkBaseWrapper*)pyobj)->cptr)
-#define SbkBaseWrapper_setCptr(pyobj,c) (((Shiboken::SbkBaseWrapper*)pyobj)->cptr = c)
#define SbkBaseWrapper_instanceDict(pyobj) (((Shiboken::SbkBaseWrapper*)pyobj)->ob_dict)
#define SbkBaseWrapper_setInstanceDict(pyobj,d) (((Shiboken::SbkBaseWrapper*)pyobj)->ob_dict = d)
#define SbkBaseWrapper_hasOwnership(pyobj) (((Shiboken::SbkBaseWrapper*)pyobj)->hasOwnership)
@@ -222,8 +232,10 @@ LIBSHIBOKEN_API void SbkBaseWrapper_clearReferences(SbkBaseWrapper* self);
/// Returns true and sets a Python RuntimeError if the Python wrapper is not marked as valid.
LIBSHIBOKEN_API bool cppObjectIsInvalid(PyObject* wrapper);
+/// Dealloc the python object \p pyObj and the C++ object represented by it.
LIBSHIBOKEN_API void deallocWrapper(PyObject* pyObj);
+/// Delete the class T allocated on \p cptr.
template<typename T>
void callCppDestructor(void* cptr)
{
diff --git a/libshiboken/basewrapper_p.h b/libshiboken/basewrapper_p.h
new file mode 100644
index 000000000..555f40d49
--- /dev/null
+++ b/libshiboken/basewrapper_p.h
@@ -0,0 +1,139 @@
+/*
+* This file is part of the Shiboken Python Bindings Generator project.
+*
+* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+*
+* Contact: PySide team <contact@pyside.org>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* version 2.1 as published by the Free Software Foundation. Please
+* review the following information to ensure the GNU Lesser General
+* Public License version 2.1 requirements will be met:
+* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+*
+* As a special exception to the GNU Lesser General Public License
+* version 2.1, the object code form of a "work that uses the Library"
+* may incorporate material from a header file that is part of the
+* Library. You may distribute such object code under terms of your
+* choice, provided that the incorporated material (i) does not exceed
+* more than 5% of the total size of the Library; and (ii) is limited to
+* numerical parameters, data structure layouts, accessors, macros,
+* inline functions and templates.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*/
+
+#ifndef BASEWRAPPER_P_H
+#define BASEWRAPPER_P_H
+
+#include <Python.h>
+#include <list>
+
+namespace Shiboken
+{
+
+struct SbkBaseWrapperType;
+
+/**
+* Visitor class used by walkOnClassHierarchy function.
+*/
+class HierarchyVisitor
+{
+public:
+ HierarchyVisitor() : m_wasFinished(false) {}
+ virtual ~HierarchyVisitor() {}
+ virtual void visit(SbkBaseWrapperType* node) = 0;
+ void finish() { m_wasFinished = true; };
+ bool wasFinished() const { return m_wasFinished; }
+private:
+ bool m_wasFinished;
+};
+
+class BaseCountVisitor : public HierarchyVisitor
+{
+public:
+ BaseCountVisitor() : m_count(0) {}
+
+ void visit(SbkBaseWrapperType*)
+ {
+ m_count++;
+ }
+
+ int count() const { return m_count; }
+private:
+ int m_count;
+};
+
+class BaseAccumulatorVisitor : public HierarchyVisitor
+{
+public:
+ BaseAccumulatorVisitor() {}
+
+ void visit(SbkBaseWrapperType* node)
+ {
+ m_bases.push_back(node);
+ }
+
+ std::list<SbkBaseWrapperType*> bases() const { return m_bases; }
+private:
+ std::list<SbkBaseWrapperType*> m_bases;
+};
+
+class GetIndexVisitor : public HierarchyVisitor
+{
+public:
+ GetIndexVisitor(PyTypeObject* desiredType) : m_index(-1), m_desiredType(desiredType) {}
+ virtual void visit(SbkBaseWrapperType* node)
+ {
+ m_index++;
+ if (PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(node), m_desiredType))
+ finish();
+ }
+ int index() const { return m_index; }
+
+private:
+ int m_index;
+ PyTypeObject* m_desiredType;
+};
+
+/// \internal Internal function used to walk on classes inheritance trees.
+/**
+* Walk on class hierarchy using a DFS algorithm.
+* For each pure Shiboken type found, HiearchyVisitor::visit is called and the algorithm consider
+* all children of this type as visited.
+*/
+void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor);
+
+inline int getTypeIndexOnHierarchy(PyTypeObject* baseType, PyTypeObject* desiredType)
+{
+ GetIndexVisitor visitor(desiredType);
+ walkThroughClassHierarchy(baseType, &visitor);
+ return visitor.index();
+}
+
+inline int getNumberOfCppBaseClasses(PyTypeObject* baseType)
+{
+ BaseCountVisitor visitor;
+ walkThroughClassHierarchy(baseType, &visitor);
+ return visitor.count();
+}
+
+inline std::list<SbkBaseWrapperType*> getCppBaseClasses(PyTypeObject* baseType)
+{
+ BaseAccumulatorVisitor visitor;
+ walkThroughClassHierarchy(baseType, &visitor);
+ return visitor.bases();
+}
+
+}
+
+#endif
diff --git a/libshiboken/bindingmanager.cpp b/libshiboken/bindingmanager.cpp
index 5d9cb484e..26e146031 100644
--- a/libshiboken/bindingmanager.cpp
+++ b/libshiboken/bindingmanager.cpp
@@ -33,8 +33,10 @@
*/
#include "basewrapper.h"
+#include "basewrapper_p.h"
#include "bindingmanager.h"
#include "google/dense_hash_map"
+#include <cstddef>
namespace Shiboken
{
@@ -85,10 +87,9 @@ bool BindingManager::hasWrapper(const void* cptr)
{
return m_d->wrapperMapper.count(cptr);
}
-void BindingManager::registerWrapper(SbkBaseWrapper* pyobj)
+void BindingManager::registerWrapper(SbkBaseWrapper* pyobj, void* cptr)
{
SbkBaseWrapperType* instanceType = reinterpret_cast<SbkBaseWrapperType*>(pyobj->ob_type);
- void* cptr = pyobj->cptr;
if (instanceType->mi_init && !instanceType->mi_offsets)
instanceType->mi_offsets = instanceType->mi_init(cptr);
@@ -105,14 +106,20 @@ void BindingManager::registerWrapper(SbkBaseWrapper* pyobj)
void BindingManager::releaseWrapper(PyObject* wrapper)
{
- void* cptr = SbkBaseWrapper_cptr(wrapper);
- m_d->releaseWrapper(cptr);
- if (((SbkBaseWrapperType*) wrapper->ob_type)->mi_offsets) {
- int* offset = ((SbkBaseWrapperType*) wrapper->ob_type)->mi_offsets;
- while (*offset != -1) {
- if (*offset > 0)
- m_d->releaseWrapper((void*) ((size_t) cptr + (*offset)));
- offset++;
+ SbkBaseWrapperType* sbkType = reinterpret_cast<SbkBaseWrapperType*>(wrapper->ob_type);
+ int numBases = sbkType->is_multicpp ? getNumberOfCppBaseClasses(wrapper->ob_type) : 1;
+
+ void** cptrs = reinterpret_cast<SbkBaseWrapper*>(wrapper)->cptr;
+ for (int i = 0; i < numBases; ++i) {
+ void* cptr = cptrs[i];
+ m_d->releaseWrapper(cptr);
+ if (sbkType->mi_offsets) {
+ int* offset = sbkType->mi_offsets;
+ while (*offset != -1) {
+ if (*offset > 0)
+ m_d->releaseWrapper((void*) ((std::size_t) cptr + (*offset)));
+ offset++;
+ }
}
}
}
diff --git a/libshiboken/bindingmanager.h b/libshiboken/bindingmanager.h
index ec5a936f4..150baa90a 100644
--- a/libshiboken/bindingmanager.h
+++ b/libshiboken/bindingmanager.h
@@ -50,7 +50,7 @@ public:
bool hasWrapper(const void *cptr);
- void registerWrapper(SbkBaseWrapper* pyobj);
+ void registerWrapper( Shiboken::SbkBaseWrapper* pyobj, void* cptr);
void releaseWrapper(PyObject* wrapper);
PyObject* retrieveWrapper(const void* cptr);
PyObject* getOverride(const void* cptr, const char* methodName);
diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h
index 521e5f576..b1d57eb61 100644
--- a/libshiboken/conversions.h
+++ b/libshiboken/conversions.h
@@ -153,7 +153,7 @@ struct Converter<T*>
if (pyobj == Py_None)
return 0;
else if (Shiboken_TypeCheck(pyobj, T))
- return (T*) SbkBaseWrapper_cptr(pyobj);
+ return (T*) getCppPointer(pyobj, SbkType<T>());
else if (Converter<T>::isConvertible(pyobj))
return CppObjectCopier<T>::copy(Converter<T>::toCpp(pyobj));
return 0;
@@ -192,7 +192,8 @@ struct Converter<void*>
{
if (pyobj == Py_None)
return 0;
- return SbkBaseWrapper_cptr(pyobj);
+ // When someone request a void pointer, just give to him the first C++ object in the class hierarchy
+ return reinterpret_cast<SbkBaseWrapper*>(pyobj)->cptr[0];
}
};
template <> struct Converter<const void*> : Converter<void*> {};
@@ -236,7 +237,7 @@ struct ValueTypeConverter
return *cptr;
}
}
- return *reinterpret_cast<T*>(reinterpret_cast<Shiboken::SbkBaseWrapper*>(pyobj)->cptr);
+ return *reinterpret_cast<T*>(getCppPointer(pyobj, SbkType<T>()));
}
};
@@ -269,8 +270,8 @@ struct ObjectTypeConverter
return 0;
SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(pyobj->ob_type);
if (shiboType->mi_specialcast)
- return (T*) shiboType->mi_specialcast(SbkBaseWrapper_cptr(pyobj), reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()));
- return (T*) SbkBaseWrapper_cptr(pyobj);
+ return (T*) shiboType->mi_specialcast(getCppPointer(pyobj, SbkType<T>()), reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()));
+ return (T*) getCppPointer(pyobj, SbkType<T>());
}
};
@@ -551,7 +552,7 @@ struct StdListConverter
static StdList toCpp(PyObject* pyobj)
{
if (PyObject_TypeCheck(pyobj, SbkType<StdList>()))
- return *reinterpret_cast<StdList*>(SbkBaseWrapper_cptr(pyobj));
+ return *reinterpret_cast<StdList*>(getCppPointer(pyobj, SbkType<StdList>()));
StdList result;
for (int i = 0; i < PySequence_Size(pyobj); i++) {