diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-22 17:50:30 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-05-22 18:20:59 +0200 |
commit | 9c333ade1a1b694fc6ce22e483f5de3e952c17ad (patch) | |
tree | d3a2e41de3501f91ebfdc8ec81a80156597c2585 /sources/shiboken2/libshiboken/basewrapper.cpp | |
parent | 8f3761d8eac7780393382ab54dbdb487eb4df027 (diff) |
move everying into sources/shiboken2 (5.9 edition)
in preparation for a subtree merge.
this should not be necessary to do in a separate commit, but git is a
tad stupid about following history correctly without it.
Diffstat (limited to 'sources/shiboken2/libshiboken/basewrapper.cpp')
-rw-r--r-- | sources/shiboken2/libshiboken/basewrapper.cpp | 1516 |
1 files changed, 1516 insertions, 0 deletions
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp new file mode 100644 index 000000000..5ecda1eaf --- /dev/null +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -0,0 +1,1516 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of PySide2. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "basewrapper.h" +#include "basewrapper_p.h" +#include "sbkconverter.h" +#include "sbkenum.h" +#include "autodecref.h" +#include "typeresolver.h" +#include "gilstate.h" +#include <string> +#include <cstring> +#include <cstddef> +#include <set> +#include <sstream> +#include <algorithm> +#include "threadstatesaver.h" + +namespace { + void _destroyParentInfo(SbkObject* obj, bool keepReference); +} + +extern "C" +{ + +static void SbkObjectTypeDealloc(PyObject* pyObj); +static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); + +PyTypeObject SbkObjectType_Type = { + PyVarObject_HEAD_INIT(0, 0) + /*tp_name*/ "Shiboken.ObjectType", + /*tp_basicsize*/ sizeof(SbkObjectType), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ SbkObjectTypeDealloc, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ 0, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ PyObject_GenericSetAttr, + /*tp_as_buffer*/ 0, + /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + /*tp_doc*/ 0, + /*tp_traverse*/ 0, + /*tp_clear*/ 0, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ 0, + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ 0, + /*tp_base*/ &PyType_Type, + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ 0, + /*tp_init*/ 0, + /*tp_alloc*/ PyType_GenericAlloc, + /*tp_new*/ SbkObjectTypeTpNew, + /*tp_free*/ PyObject_GC_Del, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0, + /*tp_del*/ 0, + /*tp_version_tag*/ 0 +}; + +static PyObject *SbkObjectGetDict(PyObject* pObj, void *) +{ + SbkObject *obj = reinterpret_cast<SbkObject *>(pObj); + if (!obj->ob_dict) + obj->ob_dict = PyDict_New(); + if (!obj->ob_dict) + return 0; + Py_INCREF(obj->ob_dict); + return obj->ob_dict; +} + +static PyGetSetDef SbkObjectGetSetList[] = { + {const_cast<char*>("__dict__"), SbkObjectGetDict, 0, 0, 0}, + {0, 0, 0, 0, 0} // Sentinel +}; + +static int SbkObject_traverse(PyObject* self, visitproc visit, void* arg) +{ + SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self); + + //Visit children + Shiboken::ParentInfo* pInfo = sbkSelf->d->parentInfo; + if (pInfo) { + std::set<SbkObject*>::const_iterator it = pInfo->children.begin(); + for(; it != pInfo->children.end(); ++it) + Py_VISIT(*it); + } + + //Visit refs + Shiboken::RefCountMap* rInfo = sbkSelf->d->referredObjects; + if (rInfo) { + Shiboken::RefCountMap::const_iterator it = rInfo->begin(); + for (; it != rInfo->end(); ++it) { + std::list<PyObject*>::const_iterator ref = it->second.begin(); + for(; ref != it->second.end(); ++ref) + Py_VISIT(*ref); + } + } + + if (sbkSelf->ob_dict) + Py_VISIT(sbkSelf->ob_dict); + return 0; +} + +static int SbkObject_clear(PyObject* self) +{ + SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self); + + Shiboken::Object::removeParent(sbkSelf); + + if (sbkSelf->d->parentInfo) + _destroyParentInfo(sbkSelf, true); + + Shiboken::Object::clearReferences(sbkSelf); + + if (sbkSelf->ob_dict) + Py_CLEAR(sbkSelf->ob_dict); + return 0; +} + +SbkObjectType SbkObject_Type = { { { + PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0) + /*tp_name*/ "Shiboken.Object", + /*tp_basicsize*/ sizeof(SbkObject), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ SbkDeallocWrapperWithPrivateDtor, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ 0, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ 0, + /*tp_as_buffer*/ 0, + /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, + /*tp_doc*/ 0, + /*tp_traverse*/ SbkObject_traverse, + /*tp_clear*/ SbkObject_clear, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ offsetof(SbkObject, weakreflist), + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ SbkObjectGetSetList, + /*tp_base*/ 0, + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ offsetof(SbkObject, ob_dict), + /*tp_init*/ 0, + /*tp_alloc*/ 0, + /*tp_new*/ 0, + /*tp_free*/ 0, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0, + /*tp_del*/ 0, + /*tp_version_tag*/ 0 +}, }, + /*priv_data*/ 0 +}; + + +static void SbkDeallocWrapperCommon(PyObject* pyObj, bool canDelete) +{ + SbkObject* sbkObj = reinterpret_cast<SbkObject*>(pyObj); + PyTypeObject* pyType = Py_TYPE(pyObj); + + // Need to decref the type if this is the dealloc func; if type + // is subclassed, that dealloc func will decref (see subtype_dealloc + // in typeobject.c in the python sources) + bool needTypeDecref = (pyType->tp_dealloc == SbkDeallocWrapper + || pyType->tp_dealloc == SbkDeallocWrapperWithPrivateDtor); + + // Ensure that the GC is no longer tracking this object to avoid a + // possible reentrancy problem. Since there are multiple steps involved + // in deallocating a SbkObject it is possible for the garbage collector to + // be invoked and it trying to delete this object while it is still in + // progress from the first time around, resulting in a double delete and a + // crash. + PyObject_GC_UnTrack(pyObj); + + // Check that Python is still initialized as sometimes this is called by a static destructor + // after Python interpeter is shutdown. + if (sbkObj->weakreflist && Py_IsInitialized()) + PyObject_ClearWeakRefs(pyObj); + + // If I have ownership and is valid delete C++ pointer + if (canDelete && sbkObj->d->hasOwnership && sbkObj->d->validCppObject) { + SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyType); + if (sbkType->d->is_multicpp) { + Shiboken::DeallocVisitor visitor(sbkObj); + Shiboken::walkThroughClassHierarchy(pyObj->ob_type, &visitor); + } else { + void* cptr = sbkObj->d->cptr[0]; + Shiboken::Object::deallocData(sbkObj, true); + + Shiboken::ThreadStateSaver threadSaver; + if (Py_IsInitialized()) + threadSaver.save(); + sbkType->d->cpp_dtor(cptr); + } + } else { + Shiboken::Object::deallocData(sbkObj, true); + } + + if (needTypeDecref) + Py_DECREF(pyType); +} + +void SbkDeallocWrapper(PyObject* pyObj) +{ + SbkDeallocWrapperCommon(pyObj, true); +} + +void SbkDeallocWrapperWithPrivateDtor(PyObject* self) +{ + SbkDeallocWrapperCommon(self, false); +} + +void SbkObjectTypeDealloc(PyObject* pyObj) +{ + SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(pyObj); + + PyObject_GC_UnTrack(pyObj); + Py_TRASHCAN_SAFE_BEGIN(pyObj); + if (sbkType->d) { + if(sbkType->d->user_data && sbkType->d->d_func) { + sbkType->d->d_func(sbkType->d->user_data); + sbkType->d->user_data = 0; + } + free(sbkType->d->original_name); + sbkType->d->original_name = 0; + if (!Shiboken::ObjectType::isUserType(reinterpret_cast<PyTypeObject*>(sbkType))) + Shiboken::Conversions::deleteConverter(sbkType->d->converter); + delete sbkType->d; + sbkType->d = 0; + } + Py_TRASHCAN_SAFE_END(pyObj); +} + +PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds) +{ +#ifndef IS_PY3K + // Check if all bases are new style before calling type.tp_new + // Was causing gc assert errors in test_bug704.py when + // this check happened after creating the type object. + // Argument parsing take from type.tp_new code. + PyObject* name; + PyObject* pyBases; + PyObject* dict; + static const char* kwlist[] = { "name", "bases", "dict", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:sbktype", (char**)kwlist, + &name, + &PyTuple_Type, &pyBases, + &PyDict_Type, &dict)) + return NULL; + + for(int i=0, i_max=PyTuple_GET_SIZE(pyBases); i < i_max; i++) { + PyObject* baseType = PyTuple_GET_ITEM(pyBases, i); + if (PyClass_Check(baseType)) { + PyErr_Format(PyExc_TypeError, "Invalid base class used in type %s. PySide only support multiple inheritance from python new style class.", metatype->tp_name); + return 0; + } + } +#endif + + // The meta type creates a new type when the Python programmer extends a wrapped C++ class. + SbkObjectType* newType = reinterpret_cast<SbkObjectType*>(PyType_Type.tp_new(metatype, args, kwds)); + if (!newType) + return 0; + + Shiboken::ObjectType::initPrivateData(newType); + SbkObjectTypePrivate* d = newType->d; + + std::list<SbkObjectType*> bases = Shiboken::getCppBaseClasses(reinterpret_cast<PyTypeObject*>(newType)); + if (bases.size() == 1) { + SbkObjectTypePrivate* parentType = bases.front()->d; + d->mi_offsets = parentType->mi_offsets; + d->mi_init = parentType->mi_init; + d->mi_specialcast = parentType->mi_specialcast; + d->type_discovery = parentType->type_discovery; + d->cpp_dtor = parentType->cpp_dtor; + d->is_multicpp = 0; + d->converter = parentType->converter; + } else { + d->mi_offsets = 0; + d->mi_init = 0; + d->mi_specialcast = 0; + d->type_discovery = 0; + d->cpp_dtor = 0; + d->is_multicpp = 1; + d->converter = 0; + } + if (bases.size() == 1) + d->original_name = strdup(bases.front()->d->original_name); + else + d->original_name = strdup("object"); + d->user_data = 0; + d->d_func = 0; + d->is_user_type = 1; + + std::list<SbkObjectType*>::const_iterator it = bases.begin(); + for (; it != bases.end(); ++it) { + if ((*it)->d->subtype_init) + (*it)->d->subtype_init(newType, args, kwds); + } + + return reinterpret_cast<PyObject*>(newType); +} + +PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObject*) +{ + SbkObject* self = PyObject_GC_New(SbkObject, subtype); + Py_INCREF(reinterpret_cast<PyObject*>(subtype)); + SbkObjectPrivate* d = new SbkObjectPrivate; + + SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(subtype); + int numBases = ((sbkType->d && sbkType->d->is_multicpp) ? Shiboken::getNumberOfCppBaseClasses(subtype) : 1); + d->cptr = new void*[numBases]; + std::memset(d->cptr, 0, sizeof(void*)*numBases); + d->hasOwnership = 1; + d->containsCppWrapper = 0; + d->validCppObject = 0; + d->parentInfo = 0; + d->referredObjects = 0; + d->cppObjectCreated = 0; + self->ob_dict = 0; + self->weakreflist = 0; + self->d = d; + PyObject_GC_Track(reinterpret_cast<PyObject*>(self)); + return reinterpret_cast<PyObject*>(self); +} + + +} //extern "C" + + +namespace +{ + +void _destroyParentInfo(SbkObject* obj, bool keepReference) +{ + Shiboken::ParentInfo* pInfo = obj->d->parentInfo; + if (pInfo) { + while(!pInfo->children.empty()) { + SbkObject* first = *pInfo->children.begin(); + // Mark child as invalid + Shiboken::Object::invalidate(first); + Shiboken::Object::removeParent(first, false, keepReference); + } + Shiboken::Object::removeParent(obj, false); + } +} + +} + +namespace Shiboken +{ + +static void decRefPyObjectList(const std::list<PyObject*> &pyObj, PyObject* skip = 0); + +static 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 (!PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + continue; + } else { + SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(type); + if (sbkType->d->is_user_type) + _walkThroughClassHierarchy(type, visitor); + else + visitor->visit(sbkType); + } + if (visitor->wasFinished()) + break; + } +} + +void walkThroughClassHierarchy(PyTypeObject* currentType, HierarchyVisitor* visitor) +{ + _walkThroughClassHierarchy(currentType, visitor); + visitor->done(); +} + + +bool importModule(const char* moduleName, PyTypeObject*** cppApiPtr) +{ + PyObject* sysModules = PyImport_GetModuleDict(); + PyObject* module = PyDict_GetItemString(sysModules, moduleName); + if (!module) { + module = PyImport_ImportModule(moduleName); + if (!module) + return false; + } else { + Py_INCREF(module); + } + + Shiboken::AutoDecRef cppApi(PyObject_GetAttrString(module, "_Cpp_Api")); + Py_DECREF(module); + + if (cppApi.isNull()) + return false; + +#ifdef IS_PY3K + if (PyCapsule_CheckExact(cppApi)) + *cppApiPtr = reinterpret_cast<PyTypeObject**>(PyCapsule_GetPointer(cppApi, 0)); +#else + // Python 2.6 doesn't have PyCapsule API, so let's keep usign PyCObject on all Python 2.x + if (PyCObject_Check(cppApi)) + *cppApiPtr = reinterpret_cast<PyTypeObject**>(PyCObject_AsVoidPtr(cppApi)); +#endif + return true; +} + +// Wrapper metatype and base type ---------------------------------------------------------- + +void DtorCallerVisitor::visit(SbkObjectType* node) +{ + m_ptrs.push_back(std::make_pair(m_pyObj->d->cptr[m_ptrs.size()], node)); +} + +void DtorCallerVisitor::done() +{ + std::list<std::pair<void*, SbkObjectType*> >::const_iterator it = m_ptrs.begin(); + for (; it != m_ptrs.end(); ++it) { + Shiboken::ThreadStateSaver threadSaver; + threadSaver.save(); + it->second->d->cpp_dtor(it->first); + } +} + +void DeallocVisitor::done() +{ + Shiboken::Object::deallocData(m_pyObj, true); + DtorCallerVisitor::done(); +} + +namespace Conversions { void init(); } + +void init() +{ + static bool shibokenAlreadInitialised = false; + if (shibokenAlreadInitialised) + return; + + Conversions::init(); + + initTypeResolver(); + PyEval_InitThreads(); + + //Init private data + Shiboken::ObjectType::initPrivateData(&SbkObject_Type); + + if (PyType_Ready(&SbkEnumType_Type) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.SbkEnumType metatype."); + + if (PyType_Ready(&SbkObjectType_Type) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapperType metatype."); + + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(&SbkObject_Type)) < 0) + Py_FatalError("[libshiboken] Failed to initialise Shiboken.BaseWrapper type."); + + shibokenAlreadInitialised = true; +} + +void setErrorAboutWrongArguments(PyObject* args, const char* funcName, const char** cppOverloads) +{ + std::string msg; + std::string params; + if (args) { + if (PyTuple_Check(args)) { + for (Py_ssize_t i = 0, max = PyTuple_GET_SIZE(args); i < max; ++i) { + if (i) + params += ", "; + PyObject* arg = PyTuple_GET_ITEM(args, i); + params += arg->ob_type->tp_name; + } + } else { + params = args->ob_type->tp_name; + } + } + + if (!cppOverloads) { + msg = "'" + std::string(funcName) + "' called with wrong argument types: " + params; + } else { + msg = "'" + std::string(funcName) + "' called with wrong argument types:\n "; + msg += funcName; + msg += '('; + msg += params; + msg += ")\n"; + msg += "Supported signatures:"; + for (int i = 0; cppOverloads[i]; ++i) { + msg += "\n "; + msg += funcName; + msg += '('; + msg += cppOverloads[i]; + msg += ')'; + } + } + PyErr_SetString(PyExc_TypeError, msg.c_str()); + +} + +class FindBaseTypeVisitor : public HierarchyVisitor +{ + public: + FindBaseTypeVisitor(PyTypeObject* typeToFind) : m_found(false), m_typeToFind(typeToFind) {} + virtual void visit(SbkObjectType* node) + { + if (reinterpret_cast<PyTypeObject*>(node) == m_typeToFind) { + m_found = true; + finish(); + } + } + bool found() const { return m_found; } + + private: + bool m_found; + PyTypeObject* m_typeToFind; +}; + +std::list<SbkObject*> splitPyObject(PyObject* pyObj) +{ + std::list<SbkObject*> result; + if (PySequence_Check(pyObj)) { + AutoDecRef lst(PySequence_Fast(pyObj, "Invalid keep reference object.")); + if (!lst.isNull()) { + for (Py_ssize_t i = 0, i_max = PySequence_Fast_GET_SIZE(lst.object()); i < i_max; ++i) { + PyObject* item = PySequence_Fast_GET_ITEM(lst.object(), i); + if (Object::checkType(item)) + result.push_back(reinterpret_cast<SbkObject*>(item)); + } + } + } else { + result.push_back(reinterpret_cast<SbkObject*>(pyObj)); + } + return result; +} + +static void decRefPyObjectList(const std::list<PyObject*>& lst, PyObject *skip) +{ + std::list<PyObject*>::const_iterator iter = lst.begin(); + while(iter != lst.end()) { + if (*iter != skip) + Py_DECREF(*iter); + ++iter; + } +} + +namespace ObjectType +{ + +bool checkType(PyTypeObject* type) +{ + return PyType_IsSubtype(type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type)); +} + +bool isUserType(PyTypeObject* type) +{ + return checkType(type) && reinterpret_cast<SbkObjectType*>(type)->d->is_user_type; +} + +bool canCallConstructor(PyTypeObject* myType, PyTypeObject* ctorType) +{ + FindBaseTypeVisitor visitor(ctorType); + walkThroughClassHierarchy(myType, &visitor); + if (!visitor.found()) { + PyErr_Format(PyExc_TypeError, "%s isn't a direct base class of %s", ctorType->tp_name, myType->tp_name); + return false; + } + return true; +} + + +bool hasExternalCppConversions(SbkObjectType*) { return false; } // DEPRECATED. +bool isExternalConvertible(SbkObjectType *, PyObject *) { return false; } // DEPRECATED. +void setExternalCppConversionFunction(SbkObjectType*, ExtendedToCppFunc) {} // DEPRECATED. +void setExternalIsConvertibleFunction(SbkObjectType*, ExtendedIsConvertibleFunc) {} // DEPRECATED. +void* callExternalCppConversion(SbkObjectType*, PyObject*) { return 0; } // DEPRECATED. + + +bool hasCast(SbkObjectType* type) +{ + return type->d->mi_specialcast; +} + +void* cast(SbkObjectType* sourceType, SbkObject* obj, PyTypeObject* targetType) +{ + return sourceType->d->mi_specialcast(Object::cppPointer(obj, targetType), reinterpret_cast<SbkObjectType*>(targetType)); +} + +void setCastFunction(SbkObjectType* type, SpecialCastFunction func) +{ + type->d->mi_specialcast = func; +} + +void setOriginalName(SbkObjectType* self, const char* name) +{ + if (self->d->original_name) + free(self->d->original_name); + self->d->original_name = strdup(name); +} + +const char* getOriginalName(SbkObjectType* self) +{ + return self->d->original_name; +} + +void setTypeDiscoveryFunctionV2(SbkObjectType* self, TypeDiscoveryFuncV2 func) +{ + self->d->type_discovery = func; +} + +void setTypeDiscoveryFunction(SbkObjectType* self, TypeDiscoveryFunc func) +{ + self->d->type_discovery = (TypeDiscoveryFuncV2)func; +} + +TypeDiscoveryFunc getTypeDiscoveryFunction(SbkObjectType* self) +{ + // This is an illegal cast because the return value is different, + // but nobody ever used this function, so... =] + return (TypeDiscoveryFunc)self->d->type_discovery; +} + +void copyMultimpleheritance(SbkObjectType* self, SbkObjectType* other) +{ + self->d->mi_init = other->d->mi_init; + self->d->mi_offsets = other->d->mi_offsets; + self->d->mi_specialcast = other->d->mi_specialcast; +} + +void setMultipleIheritanceFunction(SbkObjectType* self, MultipleInheritanceInitFunction function) +{ + self->d->mi_init = function; +} + +MultipleInheritanceInitFunction getMultipleIheritanceFunction(SbkObjectType* self) +{ + return self->d->mi_init; +} + +void setDestructorFunction(SbkObjectType* self, ObjectDestructor func) +{ + self->d->cpp_dtor = func; +} + +void initPrivateData(SbkObjectType* self) +{ + self->d = new SbkObjectTypePrivate; + memset(self->d, 0, sizeof(SbkObjectTypePrivate)); +} + +bool introduceWrapperType(PyObject* enclosingObject, + const char* typeName, const char* originalName, + SbkObjectType* type, ObjectDestructor cppObjDtor, + SbkObjectType* baseType, PyObject* baseTypes, + bool isInnerClass) +{ + initPrivateData(type); + setOriginalName(type, originalName); + setDestructorFunction(type, cppObjDtor); + + if (baseType) { + type->super.ht_type.tp_base = reinterpret_cast<PyTypeObject *>(baseType); + if (baseTypes) { + for (int i = 0; i < PySequence_Fast_GET_SIZE(baseTypes); ++i) + BindingManager::instance().addClassInheritance(reinterpret_cast<SbkObjectType *>(PySequence_Fast_GET_ITEM(baseTypes, i)), type); + type->super.ht_type.tp_bases = baseTypes; + } else { + BindingManager::instance().addClassInheritance(baseType, type); + } + } + + if (PyType_Ready(reinterpret_cast<PyTypeObject *>(type)) < 0) + return false; + + if (isInnerClass) + return PyDict_SetItemString(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; + + //PyModule_AddObject steals type's reference. + Py_INCREF(reinterpret_cast<PyObject *>(type)); + return PyModule_AddObject(enclosingObject, typeName, reinterpret_cast<PyObject *>(type)) == 0; +} + +void setSubTypeInitHook(SbkObjectType* self, SubTypeInitHook func) +{ + self->d->subtype_init = func; +} + +void* getTypeUserData(SbkObjectType* self) +{ + return self->d->user_data; +} + +void setTypeUserData(SbkObjectType* self, void* userData, DeleteUserDataFunc d_func) +{ + self->d->user_data = userData; + self->d->d_func = d_func; +} + +} // namespace ObjectType + + +namespace Object +{ + +static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen); + +bool checkType(PyObject* pyObj) +{ + return ObjectType::checkType(pyObj->ob_type); +} + +bool isUserType(PyObject* pyObj) +{ + return ObjectType::isUserType(pyObj->ob_type); +} + +Py_hash_t hash(PyObject* pyObj) +{ + assert(Shiboken::Object::checkType(pyObj)); + return reinterpret_cast<Py_hash_t>(pyObj); +} + +static void setSequenceOwnership(PyObject* pyObj, bool owner) +{ + if (PySequence_Check(pyObj)) { + std::list<SbkObject*> objs = splitPyObject(pyObj); + std::list<SbkObject*>::const_iterator it = objs.begin(); + for(; it != objs.end(); ++it) { + if (owner) + getOwnership(*it); + else + releaseOwnership(*it); + } + } else if (Object::checkType(pyObj)) { + if (owner) + getOwnership(reinterpret_cast<SbkObject*>(pyObj)); + else + releaseOwnership(reinterpret_cast<SbkObject*>(pyObj)); + } +} + +void setValidCpp(SbkObject* pyObj, bool value) +{ + pyObj->d->validCppObject = value; +} + +void setHasCppWrapper(SbkObject* pyObj, bool value) +{ + pyObj->d->containsCppWrapper = value; +} + +bool hasCppWrapper(SbkObject* pyObj) +{ + return pyObj->d->containsCppWrapper; +} + +bool wasCreatedByPython(SbkObject* pyObj) +{ + return pyObj->d->cppObjectCreated; +} + +void callCppDestructors(SbkObject* pyObj) +{ + SbkObjectType* sbkType = reinterpret_cast<SbkObjectType*>(Py_TYPE(pyObj)); + if (sbkType->d->is_multicpp) { + Shiboken::DtorCallerVisitor visitor(pyObj); + Shiboken::walkThroughClassHierarchy(Py_TYPE(pyObj), &visitor); + } else { + Shiboken::ThreadStateSaver threadSaver; + threadSaver.save(); + sbkType->d->cpp_dtor(pyObj->d->cptr[0]); + } + + /* invalidate needs to be called before deleting pointer array because + it needs to delete entries for them from the BindingManager hash table; + also release wrapper explicitly if object contains C++ wrapper because + invalidate doesn't */ + invalidate(pyObj); + if (pyObj->d->validCppObject && pyObj->d->containsCppWrapper) { + BindingManager::instance().releaseWrapper(pyObj); + } + + delete[] pyObj->d->cptr; + pyObj->d->cptr = 0; + pyObj->d->validCppObject = false; +} + +bool hasOwnership(SbkObject* pyObj) +{ + return pyObj->d->hasOwnership; +} + +void getOwnership(SbkObject* self) +{ + // skip if already have the ownership + if (self->d->hasOwnership) + return; + + // skip if this object has parent + if (self->d->parentInfo && self->d->parentInfo->parent) + return; + + // Get back the ownership + self->d->hasOwnership = true; + + if (self->d->containsCppWrapper) + Py_DECREF(reinterpret_cast<PyObject *>(self)); // Remove extra ref + else + makeValid(self); // Make the object valid again +} + +void getOwnership(PyObject* pyObj) +{ + if (pyObj) + setSequenceOwnership(pyObj, true); +} + +void releaseOwnership(SbkObject* self) +{ + // skip if the ownership have already moved to c++ + SbkObjectType* selfType = reinterpret_cast<SbkObjectType*>(Py_TYPE(self)); + if (!self->d->hasOwnership || Shiboken::Conversions::pythonTypeIsValueType(selfType->d->converter)) + return; + + // remove object ownership + self->d->hasOwnership = false; + + // If We have control over object life + if (self->d->containsCppWrapper) + Py_INCREF(reinterpret_cast<PyObject *>(self)); // keep the python object alive until the wrapper destructor call + else + invalidate(self); // If I do not know when this object will die We need to invalidate this to avoid use after +} + +void releaseOwnership(PyObject* self) +{ + setSequenceOwnership(self, false); +} + +/* Needed forward declarations */ +static void recursive_invalidate(PyObject* pyobj, std::set<SbkObject*>& seen); +static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen); + +void invalidate(PyObject* pyobj) +{ + std::set<SbkObject*> seen; + recursive_invalidate(pyobj, seen); +} + +void invalidate(SbkObject* self) +{ + std::set<SbkObject*> seen; + recursive_invalidate(self, seen); +} + +static void recursive_invalidate(PyObject* pyobj, std::set<SbkObject*>& seen) +{ + std::list<SbkObject*> objs = splitPyObject(pyobj); + std::list<SbkObject*>::const_iterator it = objs.begin(); + for (; it != objs.end(); it++) + recursive_invalidate(*it, seen); +} + +static void recursive_invalidate(SbkObject* self, std::set<SbkObject*>& seen) +{ + // Skip if this object not is a valid object or if it's already been seen + if (!self || reinterpret_cast<PyObject *>(self) == Py_None || seen.find(self) != seen.end()) + return; + seen.insert(self); + + if (!self->d->containsCppWrapper) { + self->d->validCppObject = false; // Mark object as invalid only if this is not a wrapper class + BindingManager::instance().releaseWrapper(self); + } + + // If it is a parent invalidate all children. + if (self->d->parentInfo) { + // Create a copy because this list can be changed during the process + ChildrenList copy = self->d->parentInfo->children; + ChildrenList::iterator it = copy.begin(); + + for (; it != copy.end(); ++it) { + // invalidate the child + recursive_invalidate(*it, seen); + + // if the parent not is a wrapper class, then remove children from him, because We do not know when this object will be destroyed + if (!self->d->validCppObject) + removeParent(*it, true, true); + } + } + + // If has ref to other objects invalidate all + if (self->d->referredObjects) { + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter; + for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) { + const std::list<PyObject*> lst = iter->second; + std::list<PyObject*>::const_iterator it = lst.begin(); + while(it != lst.end()) { + recursive_invalidate(*it, seen); + ++it; + } + } + } +} + +void makeValid(SbkObject* self) +{ + // Skip if this object not is a valid object + if (!self || reinterpret_cast<PyObject *>(self) == Py_None || self->d->validCppObject) + return; + + // Mark object as invalid only if this is not a wrapper class + self->d->validCppObject = true; + + // If it is a parent make all children valid + if (self->d->parentInfo) { + ChildrenList::iterator it = self->d->parentInfo->children.begin(); + for (; it != self->d->parentInfo->children.end(); ++it) + makeValid(*it); + } + + // If has ref to other objects make all valid again + if (self->d->referredObjects) { + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter; + for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) { + const std::list<PyObject*> lst = iter->second; + std::list<PyObject*>::const_iterator it = lst.begin(); + while(it != lst.end()) { + if (Shiboken::Object::checkType(*it)) + makeValid(reinterpret_cast<SbkObject*>(*it)); + ++it; + } + } + } +} + +bool hasParentInfo(SbkObject* pyObj) +{ + return pyObj->d->parentInfo; +} + +void* cppPointer(SbkObject* pyObj, PyTypeObject* desiredType) +{ + PyTypeObject* type = Py_TYPE(pyObj); + int idx = 0; + if (reinterpret_cast<SbkObjectType*>(type)->d->is_multicpp) + idx = getTypeIndexOnHierarchy(type, desiredType); + if (pyObj->d->cptr) + return pyObj->d->cptr[idx]; + return 0; +} + +std::vector<void*> cppPointers(SbkObject* pyObj) +{ + int n = getNumberOfCppBaseClasses(Py_TYPE(pyObj)); + std::vector<void*> ptrs(n); + for (int i = 0; i < n; ++i) + ptrs[i] = pyObj->d->cptr[i]; + return ptrs; +} + + +bool setCppPointer(SbkObject* sbkObj, PyTypeObject* desiredType, void* cptr) +{ + int idx = 0; + if (reinterpret_cast<SbkObjectType*>(Py_TYPE(sbkObj))->d->is_multicpp) + idx = getTypeIndexOnHierarchy(Py_TYPE(sbkObj), desiredType); + + bool alreadyInitialized = sbkObj->d->cptr[idx]; + if (alreadyInitialized) + PyErr_SetString(PyExc_RuntimeError, "You can't initialize an object twice!"); + else + sbkObj->d->cptr[idx] = cptr; + + sbkObj->d->cppObjectCreated = true; + return !alreadyInitialized; +} + +bool isValid(PyObject* pyObj) +{ + if (!pyObj || pyObj == Py_None + || Py_TYPE(pyObj->ob_type) != &SbkObjectType_Type) { + return true; + } + + SbkObjectPrivate* priv = reinterpret_cast<SbkObject*>(pyObj)->d; + + if (!priv->cppObjectCreated && isUserType(pyObj)) { + PyErr_Format(PyExc_RuntimeError, "'__init__' method of object's base class (%s) not called.", pyObj->ob_type->tp_name); + return false; + } + + if (!priv->validCppObject) { + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", pyObj->ob_type->tp_name); + return false; + } + + return true; +} + +bool isValid(SbkObject* pyObj, bool throwPyError) +{ + if (!pyObj) + return false; + + SbkObjectPrivate* priv = pyObj->d; + if (!priv->cppObjectCreated && isUserType(reinterpret_cast<PyObject*>(pyObj))) { + if (throwPyError) + PyErr_Format(PyExc_RuntimeError, "Base constructor of the object (%s) not called.", Py_TYPE(pyObj)->tp_name); + return false; + } + + if (!priv->validCppObject) { + if (throwPyError) + PyErr_Format(PyExc_RuntimeError, "Internal C++ object (%s) already deleted.", Py_TYPE(pyObj)->tp_name); + return false; + } + + return true; +} + +bool isValid(PyObject* pyObj, bool throwPyError) +{ + if (!pyObj || pyObj == Py_None || + !PyType_IsSubtype(pyObj->ob_type, reinterpret_cast<PyTypeObject*>(&SbkObject_Type))) { + return true; + } + return isValid(reinterpret_cast<SbkObject*>(pyObj), throwPyError); +} + +SbkObject *findColocatedChild(SbkObject *wrapper, + const SbkObjectType *instanceType) +{ + // Degenerate case, wrapper is the correct wrapper. + if (reinterpret_cast<const void *>(Py_TYPE(wrapper)) == reinterpret_cast<const void *>(instanceType)) + return wrapper; + + if (!(wrapper->d && wrapper->d->cptr)) + return 0; + + ParentInfo* pInfo = wrapper->d->parentInfo; + if (!pInfo) + return 0; + + ChildrenList& children = pInfo->children; + + ChildrenList::iterator childrenEnd = children.end(); + for (ChildrenList::iterator iChild = children.begin(); iChild != childrenEnd; ++iChild) { + if (!((*iChild)->d && (*iChild)->d->cptr)) + continue; + if ((*iChild)->d->cptr[0] == wrapper->d->cptr[0]) { + if (reinterpret_cast<const void *>(Py_TYPE(*iChild)) == reinterpret_cast<const void *>(instanceType)) + return const_cast<SbkObject *>((*iChild)); + else + return findColocatedChild(const_cast<SbkObject *>(*iChild), instanceType); + } + } + return 0; +} + + +PyObject *newObject(SbkObjectType* instanceType, + void* cptr, + bool hasOwnership, + bool isExactType, + const char* typeName) +{ + // Try to find the exact type of cptr. + if (!isExactType) { + PyTypeObject* exactType = 0; + if (typeName) { + exactType = Shiboken::Conversions::getPythonTypeObject(typeName); + if (exactType) + instanceType = reinterpret_cast<SbkObjectType*>(exactType); + } + if (!exactType) + instanceType = BindingManager::instance().resolveType(&cptr, instanceType); + } + + bool shouldCreate = true; + bool shouldRegister = true; + SbkObject* self = 0; + + // Some logic to ensure that colocated child field does not overwrite the parent + if (BindingManager::instance().hasWrapper(cptr)) { + SbkObject* existingWrapper = BindingManager::instance().retrieveWrapper(cptr); + + self = findColocatedChild(existingWrapper, instanceType); + if (self) { + // Wrapper already registered for cptr. + // This should not ideally happen, binding code should know when a wrapper + // already exists and retrieve it instead. + shouldRegister = shouldCreate = false; + } else if (hasOwnership && + (!(Shiboken::Object::hasCppWrapper(existingWrapper) || + Shiboken::Object::hasOwnership(existingWrapper)))) { + // Old wrapper is likely junk, since we have ownership and it doesn't. + BindingManager::instance().releaseWrapper(existingWrapper); + } else { + // Old wrapper may be junk caused by some bug in identifying object deletion + // but it may not be junk when a colocated field is accessed for an + // object which was not created by python (returned from c++ factory function). + // Hence we cannot release the wrapper confidently so we do not register. + shouldRegister = false; + } + } + + if (shouldCreate) { + self = reinterpret_cast<SbkObject*>(SbkObjectTpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0)); + self->d->cptr[0] = cptr; + self->d->hasOwnership = hasOwnership; + self->d->validCppObject = 1; + if (shouldRegister) { + BindingManager::instance().registerWrapper(self, cptr); + } + } else { + Py_IncRef(reinterpret_cast<PyObject*>(self)); + } + return reinterpret_cast<PyObject*>(self); +} + +void destroy(SbkObject* self) +{ + destroy(self, 0); +} + +void destroy(SbkObject* self, void* cppData) +{ + // Skip if this is called with NULL pointer this can happen in derived classes + if (!self) + return; + + // This can be called in c++ side + Shiboken::GilState gil; + + // Remove all references attached to this object + clearReferences(self); + + // Remove the object from parent control + + // Verify if this object has parent + bool hasParent = (self->d->parentInfo && self->d->parentInfo->parent); + + if (self->d->parentInfo) { + // Check for children information and make all invalid if they exists + _destroyParentInfo(self, true); + // If this object has parent then the pyobject can be invalid now, because we remove the last ref after remove from parent + } + + //if !hasParent this object could still alive + if (!hasParent && self->d->containsCppWrapper && !self->d->hasOwnership) { + // Remove extra ref used by c++ object this will case the pyobject destruction + // This can cause the object death + Py_DECREF(reinterpret_cast<PyObject *>(self)); + } + + //Python Object is not destroyed yet + if (cppData && Shiboken::BindingManager::instance().hasWrapper(cppData)) { + // Remove from BindingManager + Shiboken::BindingManager::instance().releaseWrapper(self); + self->d->hasOwnership = false; + + // the cpp object instance was deleted + delete[] self->d->cptr; + self->d->cptr = 0; + } + + // After this point the object can be death do not use the self pointer bellow +} + +void removeParent(SbkObject* child, bool giveOwnershipBack, bool keepReference) +{ + ParentInfo* pInfo = child->d->parentInfo; + if (!pInfo || !pInfo->parent) { + if (pInfo && pInfo->hasWrapperRef) { + pInfo->hasWrapperRef = false; + } + return; + } + + ChildrenList& oldBrothers = pInfo->parent->d->parentInfo->children; + // Verify if this child is part of parent list + ChildrenList::iterator iChild = std::find(oldBrothers.begin(), oldBrothers.end(), child); + if (iChild == oldBrothers.end()) + return; + + oldBrothers.erase(iChild); + + pInfo->parent = 0; + + // This will keep the wrapper reference, will wait for wrapper destruction to remove that + if (keepReference && + child->d->containsCppWrapper) { + //If have already a extra ref remove this one + if (pInfo->hasWrapperRef) + Py_DECREF(child); + else + pInfo->hasWrapperRef = true; + return; + } + + // Transfer ownership back to Python + child->d->hasOwnership = giveOwnershipBack; + + // Remove parent ref + Py_DECREF(child); +} + +void setParent(PyObject* parent, PyObject* child) +{ + if (!child || child == Py_None || child == parent) + return; + + /* + * setParent is recursive when the child is a native Python sequence, i.e. objects not binded by Shiboken + * like tuple and list. + * + * This "limitation" exists to fix the following problem: A class multiple inherits QObject and QString, + * so if you pass this class to someone that takes the ownership, we CAN'T enter in this if, but hey! QString + * follows the sequence protocol. + */ + if (PySequence_Check(child) && !Object::checkType(child)) { + Shiboken::AutoDecRef seq(PySequence_Fast(child, 0)); + for (Py_ssize_t i = 0, max = PySequence_Size(seq); i < max; ++i) + setParent(parent, PySequence_Fast_GET_ITEM(seq.object(), i)); + return; + } + + bool parentIsNull = !parent || parent == Py_None; + SbkObject* parent_ = reinterpret_cast<SbkObject*>(parent); + SbkObject* child_ = reinterpret_cast<SbkObject*>(child); + + if (!parentIsNull) { + if (!parent_->d->parentInfo) + parent_->d->parentInfo = new ParentInfo; + + // do not re-add a child + if (child_->d->parentInfo && (child_->d->parentInfo->parent == parent_)) + return; + } + + ParentInfo* pInfo = child_->d->parentInfo; + bool hasAnotherParent = pInfo && pInfo->parent && pInfo->parent != parent_; + + //Avoid destroy child during reparent operation + Py_INCREF(child); + + // check if we need to remove this child from the old parent + if (parentIsNull || hasAnotherParent) + removeParent(child_); + + // Add the child to the new parent + pInfo = child_->d->parentInfo; + if (!parentIsNull) { + if (!pInfo) + pInfo = child_->d->parentInfo = new ParentInfo; + + pInfo->parent = parent_; + parent_->d->parentInfo->children.insert(child_); + + // Add Parent ref + Py_INCREF(child_); + + // Remove ownership + child_->d->hasOwnership = false; + } + + // Remove previous safe ref + Py_DECREF(child); +} + +void deallocData(SbkObject* self, bool cleanup) +{ + // Make cleanup if this is not a wrapper otherwise this will be done on wrapper destructor + if(cleanup) { + removeParent(self); + + if (self->d->parentInfo) + _destroyParentInfo(self, true); + + clearReferences(self); + } + + if (self->d->cptr) { + // Remove from BindingManager + Shiboken::BindingManager::instance().releaseWrapper(self); + delete[] self->d->cptr; + self->d->cptr = 0; + // delete self->d; PYSIDE-205: wrong! + } + delete self->d; // PYSIDE-205: always delete d. + Py_XDECREF(self->ob_dict); + Py_TYPE(self)->tp_free(self); +} + +void setTypeUserData(SbkObject* wrapper, void* userData, DeleteUserDataFunc d_func) +{ + SbkObjectType* ob_type = reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper)); + if (ob_type->d->user_data) + ob_type->d->d_func(ob_type->d->user_data); + + ob_type->d->d_func = d_func; + ob_type->d->user_data = userData; +} + +void* getTypeUserData(SbkObject* wrapper) +{ + return reinterpret_cast<SbkObjectType*>(Py_TYPE(wrapper))->d->user_data; +} + +void keepReference(SbkObject* self, const char* key, PyObject* referredObject, bool append) +{ + bool isNone = (!referredObject || (referredObject == Py_None)); + + if (!self->d->referredObjects) + self->d->referredObjects = new Shiboken::RefCountMap; + + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter = refCountMap.find(key); + std::list<PyObject*> objects; + if (iter != refCountMap.end()) { + objects = (*iter).second; + std::list<PyObject*>::const_iterator found = std::find(objects.begin(), objects.end(), referredObject); + + // skip if objects already exists + if (found != objects.end()) + return; + } + + if (append && !isNone) { + refCountMap[key].push_back(referredObject); + Py_INCREF(referredObject); + } else if (!append) { + if (objects.size() > 0) + decRefPyObjectList(objects, isNone ? 0 : referredObject); + if (isNone) { + if (iter != refCountMap.end()) + refCountMap.erase(iter); + } else { + objects.clear(); + objects.push_back(referredObject); + refCountMap[key] = objects; + Py_INCREF(referredObject); + } + } +} + +void removeReference(SbkObject* self, const char* key, PyObject* referredObject) +{ + if (!referredObject || (referredObject == Py_None)) + return; + + if (!self->d->referredObjects) + return; + + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter = refCountMap.find(key); + if (iter != refCountMap.end()) { + decRefPyObjectList(iter->second); + refCountMap.erase(iter); + } +} + +void clearReferences(SbkObject* self) +{ + if (!self->d->referredObjects) + return; + + RefCountMap& refCountMap = *(self->d->referredObjects); + RefCountMap::iterator iter; + for (iter = refCountMap.begin(); iter != refCountMap.end(); ++iter) + decRefPyObjectList(iter->second); + self->d->referredObjects->clear(); +} + +std::string info(SbkObject* self) +{ + std::ostringstream s; + std::list<SbkObjectType*> bases; + + if (self->d && self->d->cptr) { + if (ObjectType::isUserType(Py_TYPE(self))) + bases = getCppBaseClasses(Py_TYPE(self)); + else + bases.push_back(reinterpret_cast<SbkObjectType*>(Py_TYPE(self))); + + s << "C++ address....... "; + std::list<SbkObjectType*>::const_iterator it = bases.begin(); + for (int i = 0; it != bases.end(); ++it, ++i) + s << reinterpret_cast<PyTypeObject *>(*it)->tp_name << '/' << self->d->cptr[i] << ' '; + s << "\n"; + } + else { + s << "C++ address....... <<Deleted>>\n"; + } + + s << "hasOwnership...... " << bool(self->d->hasOwnership) << "\n" + "containsCppWrapper " << self->d->containsCppWrapper << "\n" + "validCppObject.... " << self->d->validCppObject << "\n" + "wasCreatedByPython " << self->d->cppObjectCreated << "\n"; + + + if (self->d->parentInfo && self->d->parentInfo->parent) { + s << "parent............ "; + Shiboken::AutoDecRef parent(PyObject_Str(reinterpret_cast<PyObject *>(self->d->parentInfo->parent))); + s << String::toCString(parent) << "\n"; + } + + if (self->d->parentInfo && self->d->parentInfo->children.size()) { + s << "children.......... "; + ChildrenList& children = self->d->parentInfo->children; + for (ChildrenList::const_iterator it = children.begin(); it != children.end(); ++it) { + Shiboken::AutoDecRef child(PyObject_Str(reinterpret_cast<PyObject *>(*it))); + s << String::toCString(child) << ' '; + } + s << '\n'; + } + + if (self->d->referredObjects && self->d->referredObjects->size()) { + Shiboken::RefCountMap& map = *self->d->referredObjects; + s << "referred objects.. "; + Shiboken::RefCountMap::const_iterator it = map.begin(); + for (; it != map.end(); ++it) { + if (it != map.begin()) + s << " "; + s << '"' << it->first << "\" => "; + std::list<PyObject*>::const_iterator j = it->second.begin(); + for (; j != it->second.end(); ++j) { + Shiboken::AutoDecRef obj(PyObject_Str(*j)); + s << String::toCString(obj) << ' '; + } + s << ' '; + } + s << '\n'; + } + return s.str(); +} + +} // namespace Object + +} // namespace Shiboken |