aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/libshiboken/basewrapper.cpp
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-22 17:50:30 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-22 18:20:59 +0200
commit9c333ade1a1b694fc6ce22e483f5de3e952c17ad (patch)
treed3a2e41de3501f91ebfdc8ec81a80156597c2585 /sources/shiboken2/libshiboken/basewrapper.cpp
parent8f3761d8eac7780393382ab54dbdb487eb4df027 (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.cpp1516
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