aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2010-01-14 15:18:19 -0200
committerHugo Lima <hugo.lima@openbossa.org>2010-01-14 16:40:49 -0200
commit67f0c4988020833210537757fbd51ecb84825ce8 (patch)
tree805db73764d91ab3d6e9ea8d87b51207eeb343ca
parentc40f61ff076928f07591070763069cc75918768e (diff)
Implemented type discovery feature.
The problem: - There are two class, A and B, B inherits from A. - You are inside a virtual method reimplemented in python with just one parameter of type A*. - But the object referenced by a variable of type A* is an instance of B and it was created by C++, not Python! - Shiboken needs to create a PyObject of type B, not A! This does not makes sense for C++, but does for Python, because python variables does not store type information, just values. To achieve this we use RTTI to get the real type name of a variable, then we create the PyObject using the TypeResolver infrastructure initially developed to help with signal slot problems. In other words, the TypeResolver class has been moved from libpyside to libshiboken.
-rw-r--r--cppgenerator.cpp32
-rw-r--r--cppgenerator.h1
-rw-r--r--libshiboken/CMakeLists.txt1
-rw-r--r--libshiboken/basewrapper.cpp20
-rw-r--r--libshiboken/basewrapper.h4
-rw-r--r--libshiboken/conversions.h8
-rw-r--r--libshiboken/typeresolver.cpp125
-rw-r--r--libshiboken/typeresolver.h113
8 files changed, 291 insertions, 13 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index 3f83f137e..f6bae1c19 100644
--- a/cppgenerator.cpp
+++ b/cppgenerator.cpp
@@ -90,8 +90,9 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl
// headers
s << "// default includes" << endl;
s << "#include <shiboken.h>" << endl;
+ s << "#include <typeresolver.h>\n";
+ s << "#include <typeinfo>\n";
if (usePySideExtensions()) {
- s << "#include <typeresolver.h>\n";
if (metaClass->isQObject()) {
s << "#include <signalmanager.h>\n";
s << "#include <dynamicqmetaobject.h>\n";
@@ -146,6 +147,9 @@ void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *metaCl
s << endl;
}
+ if (metaClass->isPolymorphic())
+ writeTypeNameFunction(s, metaClass);
+
if (shouldGenerateCppWrapper(metaClass)) {
s << "// Native ---------------------------------------------------------" << endl;
s << endl;
@@ -1390,6 +1394,7 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass*
QString tp_as_number('0');
QString tp_as_sequence('0');
QString mi_init('0');
+ QString type_name_func('0');
QString mi_specialcast('0');
QString cppClassName = metaClass->qualifiedCppName();
QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), "");
@@ -1429,6 +1434,9 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass*
tp_init = ctors.isEmpty() ? "0" : QString("(initproc)%1_Init").arg(className);
}
+ if (metaClass->isPolymorphic())
+ type_name_func = cpythonBaseName(metaClass->typeEntry()) + "_typeName";
+
if (metaClass->hasPrivateDestructor())
tp_new = "0";
else
@@ -1513,7 +1521,8 @@ void CppGenerator::writeClassDefinition(QTextStream& s, const AbstractMetaClass*
s << "}, }," << endl;
s << INDENT << "/*mi_offsets*/ 0," << endl;
s << INDENT << "/*mi_init*/ " << mi_init << ',' << endl;
- s << INDENT << "/*mi_specialcast*/ " << mi_specialcast << endl;
+ s << INDENT << "/*mi_specialcast*/ " << mi_specialcast << ',' << endl;
+ s << INDENT << "/*type_name_func*/ " << type_name_func << endl;
s << "};" << endl;
}
@@ -2181,11 +2190,15 @@ void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* m
writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, 0, 0, metaClass);
}
- if (usePySideExtensions() && !metaClass->isNamespace()) {
+ if (!metaClass->isNamespace()) {
bool isObjectType = metaClass->typeEntry()->isObject();
- QString typeName = metaClass->qualifiedCppName() + (isObjectType ? "*" : "");
- s << INDENT << "PySide::TypeResolver::create" << (isObjectType ? "Object" : "Value");
- s << "TypeResolver<" << typeName << " >" << "(\"" << typeName << "\");\n";
+ QString typeName = metaClass->qualifiedCppName();
+ QString registeredTypeName = typeName + (isObjectType ? "*" : "");
+ QString functionSufix = isObjectType ? "Object" : "Value";
+ s << INDENT << "Shiboken::TypeResolver::create" << functionSufix;
+ s << "TypeResolver<" << typeName << " >" << "(\"" << registeredTypeName << "\");\n";
+ s << INDENT << "Shiboken::TypeResolver::create" << functionSufix;
+ s << "TypeResolver<" << typeName << " >" << "(typeid(" << typeName << ").name());\n";
}
s << '}' << endl << endl;
@@ -2258,6 +2271,13 @@ void CppGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* type)
s << INDENT << "return *" << cpythonWrapperCPtr(type, "pyobj") << ';' << endl;
s << '}' << endl << endl;
}
+void CppGenerator::writeTypeNameFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indent(INDENT);
+ s << "static const char* " << cpythonBaseName(metaClass->typeEntry()) << "_typeName(const void* cptr)\n{\n";
+ s << INDENT << "return typeid(*reinterpret_cast<const " << metaClass->qualifiedCppName() << "*>(cptr)).name();\n";
+ s << "}\n\n";
+}
void CppGenerator::writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractMetaClass* metaClass)
{
diff --git a/cppgenerator.h b/cppgenerator.h
index 132a075cd..15e0a05fc 100644
--- a/cppgenerator.h
+++ b/cppgenerator.h
@@ -65,6 +65,7 @@ private:
void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName);
void writeTypeConverterImpl(QTextStream& s, const TypeEntry* type);
+ void writeTypeNameFunction(QTextStream& s, const AbstractMetaClass* metaClass);
void writeSbkCopyCppObjectFunction(QTextStream& s, const AbstractMetaClass* metaClass);
diff --git a/libshiboken/CMakeLists.txt b/libshiboken/CMakeLists.txt
index f36567d63..3cc0a5618 100644
--- a/libshiboken/CMakeLists.txt
+++ b/libshiboken/CMakeLists.txt
@@ -14,6 +14,7 @@ basewrapper.cpp
helper.cpp
pyenum.cpp
bindingmanager.cpp
+typeresolver.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp
index cad4efe0d..b0f1b9c0a 100644
--- a/libshiboken/basewrapper.cpp
+++ b/libshiboken/basewrapper.cpp
@@ -36,6 +36,7 @@
#include <cstddef>
#include <algorithm>
#include "autodecref.h"
+#include "typeresolver.h"
namespace Shiboken
{
@@ -109,12 +110,24 @@ void destroyParentInfo(SbkBaseWrapper* obj, bool removeFromParent)
PyObject* SbkBaseWrapper_New(SbkBaseWrapperType* instanceType,
const void* cptr,
bool hasOwnership,
- bool containsCppWrapper)
+ bool isExactType)
{
+ // Try to find the exact type of cptr.
+ if (!isExactType && instanceType->type_name_func) {
+ const char* typeName = instanceType->type_name_func(cptr);
+ TypeResolver* typeResolver = TypeResolver::get(typeName);
+ if (typeResolver)
+ instanceType = reinterpret_cast<SbkBaseWrapperType*>(typeResolver->pythonType());
+ #ifndef NDEBUG
+ else
+ fprintf(stderr, "[SHIBOKEN] Can't find type resolver for %s.\n", typeName);
+ #endif
+ }
+
SbkBaseWrapper* self = reinterpret_cast<SbkBaseWrapper*>(SbkBaseWrapper_TpNew(reinterpret_cast<PyTypeObject*>(instanceType), 0, 0));
self->cptr = const_cast<void*>(cptr);
self->hasOwnership = hasOwnership;
- self->containsCppWrapper = containsCppWrapper;
+ self->containsCppWrapper = 0;
self->validCppObject = 1;
self->parentInfo = 0;
BindingManager::instance().registerWrapper(self);
@@ -253,7 +266,8 @@ SbkBaseWrapperType SbkBaseWrapper_Type = { { {
}, },
/*mi_offsets*/ 0,
/*mi_init*/ 0,
-/*mi_specialcast*/ 0
+/*mi_specialcast*/ 0,
+/*type_name_func*/ 0
};
PyAPI_FUNC(void) init_shiboken()
diff --git a/libshiboken/basewrapper.h b/libshiboken/basewrapper.h
index 7de5f9086..38e0a0c48 100644
--- a/libshiboken/basewrapper.h
+++ b/libshiboken/basewrapper.h
@@ -69,6 +69,7 @@ struct SbkBaseWrapperType;
* The implementation of this function is auto generated by the generator and you don't need to care about it.
*/
typedef void* (*SpecialCastFunction)(PyObject*, SbkBaseWrapperType*);
+typedef const char* (*TypeNameFunction)(const void*);
LIBSHIBOKEN_API PyAPI_DATA(PyTypeObject) SbkBaseWrapperType_Type;
LIBSHIBOKEN_API PyAPI_DATA(SbkBaseWrapperType) SbkBaseWrapper_Type;
@@ -81,6 +82,7 @@ struct LIBSHIBOKEN_API SbkBaseWrapperType
MultipleInheritanceInitFunction mi_init;
/// Special cast function, null if this class doesn't have multiple inheritance.
SpecialCastFunction mi_specialcast;
+ TypeNameFunction type_name_func;
};
/// Base Python object for all the wrapped C++ classes.
@@ -194,7 +196,7 @@ LIBSHIBOKEN_API PyAPI_FUNC(PyObject*)
SbkBaseWrapper_New(SbkBaseWrapperType* instanceType,
const void* cptr,
bool hasOwnership = true,
- bool containsCppWrapper = false);
+ bool isExactType = false);
LIBSHIBOKEN_API PyAPI_FUNC(PyObject*)
SbkBaseWrapper_TpNew(PyTypeObject* subtype, PyObject*, PyObject*);
diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h
index 1dc00b00f..e3b2ac34b 100644
--- a/libshiboken/conversions.h
+++ b/libshiboken/conversions.h
@@ -89,10 +89,10 @@ struct CppObjectCopier
* Convenience template to create wrappers using the proper Python type for a given C++ class instance.
*/
template<typename T>
-inline PyObject* SbkCreateWrapper(const T* cppobj, bool hasOwnership = false, bool containsCppWrapper = false)
+inline PyObject* SbkCreateWrapper(const T* cppobj, bool hasOwnership = false, bool isExactType = false)
{
return SbkBaseWrapper_New(reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()),
- cppobj, hasOwnership, containsCppWrapper);
+ cppobj, hasOwnership, isExactType);
}
// Base Conversions ----------------------------------------------------------
@@ -105,7 +105,9 @@ struct ConverterBase
static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<T*>(cppobj)); }
static inline PyObject* toPython(const T& cppobj)
{
- return SbkCreateWrapper<T>(CppObjectCopier<T>::copy(cppobj), true, CppObjectCopier<T>::isCppWrapper);
+ PyObject* obj = SbkCreateWrapper<T>(CppObjectCopier<T>::copy(cppobj), true, true);
+ SbkBaseWrapper_setContainsCppWrapper(obj, CppObjectCopier<T>::isCppWrapper);
+ return obj;
}
// Classes with implicit conversions are expected to reimplement
// this to build T from its various implicit constructors.
diff --git a/libshiboken/typeresolver.cpp b/libshiboken/typeresolver.cpp
new file mode 100644
index 000000000..3ed3daf67
--- /dev/null
+++ b/libshiboken/typeresolver.cpp
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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
+ */
+
+#include "typeresolver.h"
+#include "google/dense_hash_map"
+#include <cstdlib>
+
+using namespace Shiboken;
+
+typedef google::dense_hash_map<std::string, TypeResolver*> TypeResolverMap;
+static TypeResolverMap typeResolverMap;
+
+struct TypeResolver::TypeResolverPrivate
+{
+ const char* typeName; // maybe this is not needed anymore
+ CppToPythonFunc cppToPython;
+ PythonToCppFunc pythonToCpp;
+ DeleteObjectFunc deleteObject;
+ GetPyTypeFunc getPyType;
+};
+
+static void deinitTypeResolver()
+{
+ for (TypeResolverMap::const_iterator it = typeResolverMap.begin(); it != typeResolverMap.end(); ++it)
+ delete it->second;
+ typeResolverMap.clear();
+}
+
+static void registerTypeResolver(TypeResolver* resolver)
+{
+ static bool initied = false;
+ if (!initied) {
+ assert(typeResolverMap.empty());
+ typeResolverMap.set_empty_key("");
+ typeResolverMap.set_deleted_key("?");
+ initied = true;
+ std::atexit(deinitTypeResolver);
+ TypeResolver::createValueTypeResolver<double>("double");
+ TypeResolver::createValueTypeResolver<float>("float");
+ TypeResolver::createValueTypeResolver<bool>("bool");
+ TypeResolver::createValueTypeResolver<int>("int");
+ }
+ assert(typeResolverMap.find(resolver->typeName()) == typeResolverMap.end());
+ typeResolverMap[resolver->typeName()] = resolver;
+}
+
+TypeResolver::TypeResolver(const char* typeName, TypeResolver::CppToPythonFunc cppToPy, TypeResolver::PythonToCppFunc pyToCpp, GetPyTypeFunc getPyType, TypeResolver::DeleteObjectFunc deleter)
+{
+ m_d = new TypeResolverPrivate;
+ m_d->typeName = typeName;
+ m_d->cppToPython = cppToPy;
+ m_d->pythonToCpp = pyToCpp;
+ m_d->deleteObject = deleter;
+ m_d->getPyType = getPyType;
+
+ registerTypeResolver(this);
+}
+
+TypeResolver::~TypeResolver()
+{
+ delete m_d;
+}
+
+TypeResolver* TypeResolver::get(const char* typeName)
+{
+ TypeResolverMap::const_iterator it = typeResolverMap.find(typeName);
+ return it == typeResolverMap.end() ? 0 : it->second;
+}
+
+const char* TypeResolver::typeName() const
+{
+ return m_d->typeName;
+}
+
+void* TypeResolver::toCpp(PyObject* pyObj)
+{
+ return m_d->pythonToCpp(pyObj);
+}
+
+PyObject* TypeResolver::toPython(void* cppObj)
+{
+ return m_d->cppToPython(cppObj);
+}
+
+void TypeResolver::deleteObject(void* object)
+{
+ if (m_d->deleteObject)
+ m_d->deleteObject(object);
+}
+
+PyTypeObject* TypeResolver::pythonType()
+{
+ return m_d->getPyType();
+}
diff --git a/libshiboken/typeresolver.h b/libshiboken/typeresolver.h
new file mode 100644
index 000000000..4e7efb81b
--- /dev/null
+++ b/libshiboken/typeresolver.h
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the Shiboken Python Bindings Generator project.
+ *
+ * Copyright (C) 2009 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 TYPERESOLVER_H
+#define TYPERESOLVER_H
+
+#include "shibokenmacros.h"
+#include "conversions.h"
+
+namespace Shiboken
+{
+
+class SbkBaseWrapperType;
+
+/* To C++ convertion functions. */
+template <typename T>
+inline void* pythonToValueType(PyObject* pyobj)
+{
+ return Shiboken::CppObjectCopier<T>::copy(Shiboken::Converter<T>::toCpp(pyobj));
+}
+
+template <typename T>
+inline void* pythonToObjectType(PyObject* pyobj)
+{
+ return Shiboken::Converter<T*>::toCpp(pyobj);
+}
+
+template <typename T>
+inline void objectDeleter(void* data)
+{
+ delete reinterpret_cast<T*>(data);
+}
+
+template <typename T>
+inline PyObject* objectTypeToPython(void* cptr)
+{
+ return Shiboken::Converter<T*>::toPython(*reinterpret_cast<T**>(cptr));
+}
+
+class LIBSHIBOKEN_API TypeResolver
+{
+public:
+ typedef PyObject* (*CppToPythonFunc)(void*);
+ typedef void* (*PythonToCppFunc)(PyObject*);
+ typedef void (*DeleteObjectFunc)(void*);
+ typedef PyTypeObject* (*GetPyTypeFunc)();
+
+ ~TypeResolver();
+
+ template<typename T>
+ static TypeResolver* createValueTypeResolver(const char* typeName)
+ {
+ return new TypeResolver(typeName, &Shiboken::Converter<T>::toPython, &pythonToValueType<T>, &SbkType<T>, &objectDeleter<T>);
+ }
+
+ template<typename T>
+ static TypeResolver* createObjectTypeResolver(const char* typeName)
+ {
+ return new TypeResolver(typeName, &objectTypeToPython<T>, &pythonToObjectType<T>, &SbkType<T>);
+ }
+
+ static TypeResolver* get(const char* typeName);
+
+ const char* typeName() const;
+ PyObject* toPython(void* cppObj);
+ void* toCpp(PyObject* pyObj);
+ void deleteObject(void* object);
+ PyTypeObject* pythonType();
+
+private:
+ struct TypeResolverPrivate;
+ TypeResolverPrivate* m_d;
+
+ // disable object copy
+ TypeResolver(const TypeResolver&);
+ TypeResolver& operator=(const TypeResolver&);
+
+ TypeResolver(const char* typeName, CppToPythonFunc cppToPy, PythonToCppFunc pyToCpp, GetPyTypeFunc getPyType, DeleteObjectFunc deleter = 0);
+};
+}
+
+#endif