diff options
author | Hugo Lima <hugo.lima@openbossa.org> | 2010-03-29 17:47:02 -0300 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2010-03-30 17:46:07 -0300 |
commit | c0c093d485798aec96ea7a7230c0639797cd9830 (patch) | |
tree | 6014447a087ccb846b598d0a456d89708ccf00fa /libshiboken | |
parent | 6046687f8f78e1b674e7b4265ce5fb93dce078eb (diff) |
Add support for multiple inheritance involving more than one C++ object.
Diffstat (limited to 'libshiboken')
-rw-r--r-- | libshiboken/basewrapper.cpp | 134 | ||||
-rw-r--r-- | libshiboken/basewrapper.h | 18 | ||||
-rw-r--r-- | libshiboken/basewrapper_p.h | 139 | ||||
-rw-r--r-- | libshiboken/bindingmanager.cpp | 27 | ||||
-rw-r--r-- | libshiboken/bindingmanager.h | 2 | ||||
-rw-r--r-- | libshiboken/conversions.h | 13 |
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++) { |