aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/libshiboken/conversions.h
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 17:50:30 +0200
commit170d47f92d03b81e74e8623cf15db9282957452d (patch)
tree3da6eb4446b42619c21a4ed591988529b75b1a3e /sources/shiboken2/libshiboken/conversions.h
parent6c018822ba40cc0a4427bd3f9ab8c96829c207df (diff)
move everying into sources/shiboken2
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/conversions.h')
-rw-r--r--sources/shiboken2/libshiboken/conversions.h731
1 files changed, 731 insertions, 0 deletions
diff --git a/sources/shiboken2/libshiboken/conversions.h b/sources/shiboken2/libshiboken/conversions.h
new file mode 100644
index 000000000..f0af2be8e
--- /dev/null
+++ b/sources/shiboken2/libshiboken/conversions.h
@@ -0,0 +1,731 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef CONVERSIONS_H
+#define CONVERSIONS_H
+
+#include "sbkpython.h"
+#include <limits>
+#include <typeinfo>
+
+#include "sbkstring.h"
+#include "sbkenum.h"
+#include "basewrapper.h"
+#include "bindingmanager.h"
+#include "sbkdbg.h"
+
+// When the user adds a function with an argument unknown for the typesystem, the generator writes type checks as
+// TYPENAME_Check, so this macro allows users to add PyObject arguments to their added functions.
+#define PyObject_Check(X) true
+#define SbkChar_Check(X) (SbkNumber_Check(X) || Shiboken::String::checkChar(X))
+#include "autodecref.h"
+
+namespace Shiboken
+{
+/**
+* This function template is used to get the PyTypeObject of a C++ type T.
+* All implementations should be provided by template specializations generated by the generator when
+* T isn't a C++ primitive type.
+* \see SpecialCastFunction
+*/
+template<typename T>
+PyTypeObject* SbkType()
+{
+ return 0;
+}
+
+template<> inline PyTypeObject* SbkType<int>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<unsigned int>() { return &PyLong_Type; }
+template<> inline PyTypeObject* SbkType<short>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<long>() { return &PyLong_Type; }
+template<> inline PyTypeObject* SbkType<unsigned long>() { return &PyLong_Type; }
+template<> inline PyTypeObject* SbkType<PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject* SbkType<unsigned PY_LONG_LONG>() { return &PyLong_Type; }
+template<> inline PyTypeObject* SbkType<bool>() { return &PyBool_Type; }
+template<> inline PyTypeObject* SbkType<float>() { return &PyFloat_Type; }
+template<> inline PyTypeObject* SbkType<double>() { return &PyFloat_Type; }
+template<> inline PyTypeObject* SbkType<char>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<signed char>() { return &PyInt_Type; }
+template<> inline PyTypeObject* SbkType<unsigned char>() { return &PyInt_Type; }
+
+/**
+ * Convenience template to create wrappers using the proper Python type for a given C++ class instance.
+ */
+template<typename T>
+inline PyObject* createWrapper(const T* cppobj, bool hasOwnership = false, bool isExactType = false)
+{
+ const char* typeName = 0;
+ if (!isExactType)
+ typeName = typeid(*const_cast<T*>(cppobj)).name();
+ return Object::newObject(reinterpret_cast<SbkObjectType*>(SbkType<T>()),
+ const_cast<T*>(cppobj), hasOwnership, isExactType, typeName);
+}
+
+// Base Conversions ----------------------------------------------------------
+// The basic converter must be empty to avoid object types being converted by value.
+template <typename T> struct Converter {};
+
+// Pointer conversion specialization for value types.
+template <typename T>
+struct Converter<T*>
+{
+ static inline bool checkType(PyObject* pyObj)
+ {
+ return Converter<T>::checkType(pyObj);
+ }
+
+ static inline bool isConvertible(PyObject* pyObj)
+ {
+ return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType<T>());
+ }
+
+ static PyObject* toPython(const T* cppobj)
+ {
+ if (!cppobj)
+ Py_RETURN_NONE;
+ PyObject* pyobj = reinterpret_cast<PyObject*>(BindingManager::instance().retrieveWrapper(cppobj));
+ if (pyobj)
+ Py_INCREF(pyobj);
+ else
+ pyobj = createWrapper<T>(cppobj);
+ return pyobj;
+ }
+
+ static T* toCpp(PyObject* pyobj)
+ {
+ if (PyObject_TypeCheck(pyobj, SbkType<T>()))
+ return reinterpret_cast<T *>(Object::cppPointer(reinterpret_cast<SbkObject *>(pyobj), SbkType<T>()));
+ else if (Converter<T>::isConvertible(pyobj))
+ return new T(Converter<T>::toCpp(pyobj));
+ else if (pyobj == Py_None)
+ return 0;
+
+ assert(false);
+ return 0;
+ }
+};
+template <typename T> struct Converter<const T*> : Converter<T*> {};
+
+// Specialization for reference conversions.
+template <typename T>
+struct Converter<T&>
+{
+ static inline bool checkType(PyObject* pyObj) { return Converter<T>::checkType(pyObj); }
+ static inline bool isConvertible(PyObject* pyObj) { return Converter<T>::isConvertible(pyObj); }
+ static inline PyObject* toPython(const T& cppobj) { return Converter<T*>::toPython(&cppobj); }
+ static inline T& toCpp(PyObject* pyobj) { return *Converter<T*>::toCpp(pyobj); }
+};
+
+// Void pointer conversions.
+template<>
+struct Converter<void*>
+{
+ static inline bool checkType(PyObject *) { return false; }
+ static inline bool isConvertible(PyObject *) { return true; }
+ static PyObject* toPython(void* cppobj)
+ {
+ if (!cppobj)
+ Py_RETURN_NONE;
+ PyObject *result = reinterpret_cast<PyObject *>(cppobj);
+ Py_INCREF(result);
+ return result;
+ }
+ static void* toCpp(PyObject* pyobj) { return pyobj; }
+};
+
+// Base converter meant to be inherited by converters for classes that could be
+// passed by value.
+// Example: "struct Converter<ValueTypeClass> : ValueTypeConverter<ValueTypeClass>"
+template <typename T>
+struct ValueTypeConverter
+{
+ static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType<T>()); }
+
+ // The basic version of this method also tries to use the extended 'isConvertible' method.
+ static inline bool isConvertible(PyObject* pyobj)
+ {
+ if (PyObject_TypeCheck(pyobj, SbkType<T>()))
+ return true;
+ SbkObjectType* shiboType = reinterpret_cast<SbkObjectType*>(SbkType<T>());
+ return ObjectType::isExternalConvertible(shiboType, pyobj);
+ }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<T*>(cppobj)); }
+ static inline PyObject* toPython(const T& cppobj)
+ {
+ PyObject* obj = createWrapper<T>(new T(cppobj), true, true);
+// SbkBaseWrapper_setContainsCppWrapper(obj, SbkTypeInfo<T>::isCppWrapper);
+ return obj;
+ }
+ // Classes with implicit conversions are expected to reimplement 'toCpp' to build T from
+ // its various implicit constructors. Even classes without implicit conversions could
+ // get some of those via other modules defining conversion operator for them, thus
+ // the basic Converter for value types checks for extended conversion and tries to
+ // use them if it is the case.
+ static inline T toCpp(PyObject* pyobj)
+ {
+ if (!PyObject_TypeCheck(pyobj, SbkType<T>())) {
+ SbkObjectType* shiboType = reinterpret_cast<SbkObjectType*>(SbkType<T>());
+ if (ObjectType::hasExternalCppConversions(shiboType) && isConvertible(pyobj)) {
+ T* cptr = reinterpret_cast<T*>(ObjectType::callExternalCppConversion(shiboType, pyobj));
+ const T result = *cptr;
+ delete cptr;
+ return result;
+ }
+ assert(false);
+ }
+ return *reinterpret_cast<T*>(Object::cppPointer(reinterpret_cast<SbkObject*>(pyobj), SbkType<T>()));
+ }
+};
+
+// Base converter meant to be inherited by converters for abstract classes and object types
+// (i.e. classes with private copy constructors and = operators).
+// Example: "struct Converter<AbstractClass*> : ObjectTypeConverter<AbstractClass>"
+template <typename T>
+struct ObjectTypeConverter
+{
+ static inline bool checkType(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType<T>()); }
+ /// Py_None objects are the only objects convertible to an object type (in the form of a NULL pointer).
+ static inline bool isConvertible(PyObject* pyObj) { return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType<T>()); }
+ /// Convenience overload that calls "toPython(const T*)" method.
+ static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast<T*>(cppobj)); }
+ /// Returns a new Python wrapper for the C++ object or an existing one with its reference counter incremented.
+ static PyObject* toPython(const T* cppobj)
+ {
+ if (!cppobj)
+ Py_RETURN_NONE;
+ PyObject* pyobj = reinterpret_cast<PyObject*>(BindingManager::instance().retrieveWrapper(cppobj));
+ if (pyobj)
+ Py_INCREF(pyobj);
+ else
+ pyobj = createWrapper<T>(cppobj);
+ return pyobj;
+ }
+ /// Returns the wrapped C++ pointer casted properly, or a NULL pointer if the argument is a Py_None.
+ static T* toCpp(PyObject* pyobj)
+ {
+ if (pyobj == Py_None)
+ return 0;
+ SbkObject *sbkObj = reinterpret_cast<SbkObject *>(pyobj);
+ SbkObjectType* shiboType = reinterpret_cast<SbkObjectType*>(pyobj->ob_type);
+ if (ObjectType::hasCast(shiboType))
+ return reinterpret_cast<T*>(ObjectType::cast(shiboType, sbkObj, SbkType<T>()));
+ return reinterpret_cast<T *>(Object::cppPointer(sbkObj, SbkType<T>()));
+ }
+};
+
+template <typename T>
+struct ObjectTypeReferenceConverter : ObjectTypeConverter<T>
+{
+ static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType<T>()); }
+ static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType<T>()); }
+ static inline PyObject* toPython(const T& cppobj) { return Converter<T*>::toPython(&cppobj); }
+ static inline T& toCpp(PyObject* pyobj)
+ {
+ T* t = Converter<T*>::toCpp(pyobj);
+ assert(t);
+ return *t;
+ }
+};
+
+// PyObject* specialization to avoid converting what doesn't need to be converted.
+template<>
+struct Converter<PyObject*> : ObjectTypeConverter<PyObject*>
+{
+ static inline PyObject* toCpp(PyObject* pyobj) { return pyobj; }
+};
+
+// Primitive Conversions ------------------------------------------------------
+template <>
+struct Converter<bool>
+{
+ static inline bool checkType(PyObject* pyobj) { return PyBool_Check(pyobj); }
+ static inline bool isConvertible(PyObject* pyobj) { return PyInt_Check(pyobj); }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<bool*>(cppobj)); }
+ static inline PyObject* toPython(bool cppobj) { return PyBool_FromLong(cppobj); }
+ static inline bool toCpp(PyObject* pyobj) { return PyInt_AS_LONG(pyobj); }
+};
+
+/**
+ * Helper template for checking if a value overflows when casted to type T
+ */
+template<typename T, bool isSigned = std::numeric_limits<T>::is_signed >
+struct OverFlowChecker;
+
+template<typename T>
+struct OverFlowChecker<T, true>
+{
+ static bool check(const PY_LONG_LONG& value)
+ {
+ return value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max();
+ }
+};
+
+template<typename T>
+struct OverFlowChecker<T, false>
+{
+ static bool check(const PY_LONG_LONG& value)
+ {
+ return value < 0 || static_cast<unsigned long long>(value) > std::numeric_limits<T>::max();
+ }
+};
+
+template<>
+struct OverFlowChecker<PY_LONG_LONG, true>
+{
+ static bool check(const PY_LONG_LONG &)
+ {
+ return false;
+ }
+};
+
+template<>
+struct OverFlowChecker<double, true>
+{
+ static bool check(const double &)
+ {
+ return false;
+ }
+};
+
+template<>
+struct OverFlowChecker<float, true>
+{
+ static bool check(const double& value)
+ {
+ return value < std::numeric_limits<float>::min() || value > std::numeric_limits<float>::max();
+ }
+};
+
+template <typename PyIntEquiv>
+struct Converter_PyInt
+{
+ static inline bool checkType(PyObject* pyobj) { return PyInt_Check(pyobj); }
+ static inline bool isConvertible(PyObject* pyobj) { return SbkNumber_Check(pyobj); }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<PyIntEquiv*>(cppobj)); }
+ static inline PyObject* toPython(const PyIntEquiv& cppobj) { return PyInt_FromLong((long) cppobj); }
+ static PyIntEquiv toCpp(PyObject* pyobj)
+ {
+ if (PyFloat_Check(pyobj)) {
+ double d_result = PyFloat_AS_DOUBLE(pyobj);
+ // If cast to long directly it could overflow silently
+ if (OverFlowChecker<PyIntEquiv>::check(d_result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return static_cast<PyIntEquiv>(d_result);
+ } else {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyobj);
+ if (OverFlowChecker<PyIntEquiv>::check(result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return static_cast<PyIntEquiv>(result);
+ }
+ }
+};
+
+template <typename T>
+struct Converter_PyULongInt : Converter_PyInt<T>
+{
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<T*>(cppobj)); }
+ static inline PyObject* toPython(const T& cppobj) { return PyLong_FromUnsignedLong(cppobj); }
+};
+
+/// Specialization to convert char and unsigned char, it accepts Python numbers and strings with just one character.
+template <typename CharType>
+struct CharConverter
+{
+ static inline bool checkType(PyObject* pyobj) { return SbkChar_Check(pyobj); }
+ static inline bool isConvertible(PyObject* pyobj) { return SbkChar_Check(pyobj); }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<CharType*>(cppobj)); }
+ static inline PyObject* toPython(const CharType& cppobj) { return PyInt_FromLong(cppobj); }
+ static CharType toCpp(PyObject* pyobj)
+ {
+ if (PyBytes_Check(pyobj)) {
+ assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check
+ return PyBytes_AS_STRING(pyobj)[0];
+ } else if (PyInt_Check(pyobj)) {
+ PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj);
+ if (OverFlowChecker<CharType>::check(result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return result;
+ } else if (Shiboken::String::check(pyobj)) {
+ return Shiboken::String::toCString(pyobj)[0];
+ } else {
+ return 0;
+ }
+ }
+};
+
+template <> struct Converter<unsigned long> : Converter_PyULongInt<unsigned long> {};
+template <> struct Converter<unsigned int> : Converter_PyULongInt<unsigned int> {};
+template <> struct Converter<char> : CharConverter<char>
+{
+ // Should we really return a string?
+ using CharConverter<char>::toPython;
+ using CharConverter<char>::isConvertible;
+ using CharConverter<char>::toCpp;
+
+
+ static inline bool isConvertible(PyObject* pyobj) {
+ return SbkChar_Check(pyobj);
+ }
+
+ static inline PyObject* toPython(const char& cppObj) {
+ return Shiboken::String::fromFormat("%c", cppObj);
+ }
+
+ static char toCpp(PyObject* pyobj)
+ {
+ if (PyBytes_Check(pyobj)) {
+ assert(PyBytes_GET_SIZE(pyobj) == 1); // This check is made on SbkChar_Check
+ return PyBytes_AS_STRING(pyobj)[0];
+ } else if (PyInt_Check(pyobj)) {
+ PY_LONG_LONG result = PyInt_AsUnsignedLongLongMask(pyobj);
+ if (OverFlowChecker<char>::check(result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return char(result);
+ } else if (Shiboken::String::check(pyobj)) {
+ return Shiboken::String::toCString(pyobj)[0];
+ } else {
+ return 0;
+ }
+ }
+};
+template <> struct Converter<signed char> : CharConverter<signed char> {};
+template <> struct Converter<unsigned char> : CharConverter<unsigned char> {};
+template <> struct Converter<int> : Converter_PyInt<int> {};
+template <> struct Converter<short> : Converter_PyInt<short> {};
+template <> struct Converter<unsigned short> : Converter_PyInt<unsigned short> {};
+template <> struct Converter<long> : Converter_PyInt<long> {};
+
+template <>
+struct Converter<PY_LONG_LONG>
+{
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<PY_LONG_LONG*>(cppobj)); }
+ static inline PyObject* toPython(PY_LONG_LONG cppobj) { return PyLong_FromLongLong(cppobj); }
+ static inline PY_LONG_LONG toCpp(PyObject* pyobj) { return (PY_LONG_LONG) PyLong_AsLongLong(pyobj); }
+};
+
+template <>
+struct Converter<unsigned PY_LONG_LONG>
+{
+ static inline PyObject* toPython(void* cppobj)
+ {
+ return toPython(*reinterpret_cast<unsigned PY_LONG_LONG*>(cppobj));
+ }
+ static inline PyObject* toPython(unsigned PY_LONG_LONG cppobj)
+ {
+ return PyLong_FromUnsignedLongLong(cppobj);
+ }
+ static inline unsigned PY_LONG_LONG toCpp(PyObject* pyobj)
+ {
+#if PY_MAJOR_VERSION >= 3
+ if (!PyLong_Check(pyobj)) {
+ PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion");
+ return 0;
+ }
+
+ return PyLong_AsUnsignedLongLong(pyobj);
+#else
+ if (PyInt_Check(pyobj)) {
+ long result = (unsigned PY_LONG_LONG) PyInt_AsLong(pyobj);
+ if (result < 0) {
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return 0;
+ } else
+ return (unsigned PY_LONG_LONG) result;
+ } else if (PyLong_Check(pyobj)) {
+ return (unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(pyobj);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion");
+ return 0;
+ }
+#endif // Python 2
+ }
+};
+
+template <typename PyFloatEquiv>
+struct Converter_PyFloat
+{
+ static inline bool checkType(PyObject* obj) { return PyFloat_Check(obj); }
+ static inline bool isConvertible(PyObject* obj) { return SbkNumber_Check(obj); }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<PyFloatEquiv*>(cppobj)); }
+ static inline PyObject* toPython(PyFloatEquiv cppobj) { return PyFloat_FromDouble((double) cppobj); }
+ static inline PyFloatEquiv toCpp(PyObject* pyobj)
+ {
+ if (PyInt_Check(pyobj) || PyLong_Check(pyobj))
+ return (PyFloatEquiv) PyLong_AsLong(pyobj);
+ return (PyFloatEquiv) PyFloat_AsDouble(pyobj);
+ }
+};
+
+template <> struct Converter<float> : Converter_PyFloat<float> {};
+template <> struct Converter<double> : Converter_PyFloat<double> {};
+
+// PyEnum Conversions ---------------------------------------------------------
+template <typename CppEnum>
+struct EnumConverter
+{
+ static inline bool checkType(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType<CppEnum>()); }
+ static inline bool isConvertible(PyObject* pyObj) { return PyObject_TypeCheck(pyObj, SbkType<CppEnum>()); }
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<CppEnum*>(cppobj)); }
+ static inline PyObject* toPython(CppEnum cppenum)
+ {
+ return Shiboken::Enum::newItem(Shiboken::SbkType<CppEnum>(), (long) cppenum);
+ }
+ static inline CppEnum toCpp(PyObject* pyObj)
+ {
+ return (CppEnum) Shiboken::Enum::getValue(pyObj);;
+ }
+};
+
+// C Sting Types --------------------------------------------------------------
+template <typename CString>
+struct Converter_CString
+{
+ // Note: 0 is also a const char* in C++, so None is accepted in checkType
+ static inline bool checkType(PyObject* pyObj) {
+ return Shiboken::String::check(pyObj);
+ }
+ static inline bool isConvertible(PyObject* pyObj) {
+ return Shiboken::String::isConvertible(pyObj);
+ }
+ static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast<CString>(cppobj)); }
+ static inline PyObject* toPython(CString cppobj)
+ {
+ if (!cppobj)
+ Py_RETURN_NONE;
+ return Shiboken::String::fromCString(cppobj);
+ }
+ static inline CString toCpp(PyObject* pyobj) {
+ if (pyobj == Py_None)
+ return 0;
+ return Shiboken::String::toCString(pyobj);
+ }
+};
+
+template <> struct Converter<const char*> : Converter_CString<const char*> {};
+
+template <> struct Converter<std::string> : Converter_CString<std::string>
+{
+ static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<std::string*>(cppobj)); }
+ static inline PyObject* toPython(std::string cppObj)
+ {
+ return Shiboken::String::fromCString(cppObj.c_str());
+ }
+
+ static inline std::string toCpp(PyObject* pyobj)
+ {
+ if (pyobj == Py_None)
+ return 0;
+ return std::string(Shiboken::String::toCString(pyobj));
+ }
+};
+
+// C++ containers -------------------------------------------------------------
+// The following container converters are meant to be used for pairs, lists and maps
+// that are similar to the STL containers of the same name.
+
+// For example to create a converter for a std::list the following code is enough:
+// template<typename T> struct Converter<std::list<T> > : StdListConverter<std::list<T> > {};
+
+// And this for a std::map:
+// template<typename KT, typename VT>
+// struct Converter<std::map<KT, VT> > : StdMapConverter<std::map<KT, VT> > {};
+
+template <typename StdList>
+struct StdListConverter
+{
+ static inline bool checkType(PyObject* pyObj)
+ {
+ return isConvertible(pyObj);
+ }
+
+ static inline bool isConvertible(PyObject* pyObj)
+ {
+ if (PyObject_TypeCheck(pyObj, SbkType<StdList>()))
+ return true;
+ // Sequence conversion are made ONLY for python sequences, not for
+ // binded types implementing sequence protocol, otherwise this will
+ // cause a mess like QBitArray being accepted by someone expecting a
+ // QStringList.
+ if ((SbkType<StdList>() && Object::checkType(pyObj)) || !PySequence_Check(pyObj))
+ return false;
+ for (int i = 0, max = PySequence_Length(pyObj); i < max; ++i) {
+ AutoDecRef item(PySequence_GetItem(pyObj, i));
+ if (!Converter<typename StdList::value_type>::isConvertible(item))
+ return false;
+ }
+ return true;
+ }
+ static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast<StdList*>(cppObj)); }
+ static PyObject* toPython(const StdList& cppobj)
+ {
+ PyObject* result = PyList_New((int) cppobj.size());
+ typename StdList::const_iterator it = cppobj.begin();
+ for (int idx = 0; it != cppobj.end(); ++it, ++idx) {
+ typename StdList::value_type vh(*it);
+ PyList_SET_ITEM(result, idx, Converter<typename StdList::value_type>::toPython(vh));
+ }
+ return result;
+ }
+ static StdList toCpp(PyObject* pyobj)
+ {
+ if (PyObject_TypeCheck(pyobj, SbkType<StdList>()))
+ return *reinterpret_cast<StdList*>(Object::cppPointer(reinterpret_cast<SbkObject*>(pyobj), SbkType<StdList>()));
+
+ StdList result;
+ for (int i = 0; i < PySequence_Size(pyobj); i++) {
+ AutoDecRef pyItem(PySequence_GetItem(pyobj, i));
+ result.push_back(Converter<typename StdList::value_type>::toCpp(pyItem));
+ }
+ return result;
+ }
+};
+
+template <typename StdPair>
+struct StdPairConverter
+{
+ static inline bool checkType(PyObject* pyObj)
+ {
+ return isConvertible(pyObj);
+ }
+
+ static inline bool isConvertible(PyObject* pyObj)
+ {
+ if (PyObject_TypeCheck(pyObj, SbkType<StdPair>()))
+ return true;
+ if ((SbkType<StdPair>() && Object::checkType(pyObj)) || !PySequence_Check(pyObj) || PySequence_Length(pyObj) != 2)
+ return false;
+
+ AutoDecRef item1(PySequence_GetItem(pyObj, 0));
+ AutoDecRef item2(PySequence_GetItem(pyObj, 1));
+
+ if (!Converter<typename StdPair::first_type>::isConvertible(item1)
+ && !Converter<typename StdPair::second_type>::isConvertible(item2)) {
+ return false;
+ }
+ return true;
+ }
+ static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast<StdPair*>(cppObj)); }
+ static PyObject* toPython(const StdPair& cppobj)
+ {
+ typename StdPair::first_type first(cppobj.first);
+ typename StdPair::second_type second(cppobj.second);
+ PyObject* tuple = PyTuple_New(2);
+ PyTuple_SET_ITEM(tuple, 0, Converter<typename StdPair::first_type>::toPython(first));
+ PyTuple_SET_ITEM(tuple, 1, Converter<typename StdPair::second_type>::toPython(second));
+ return tuple;
+ }
+ static StdPair toCpp(PyObject* pyobj)
+ {
+ StdPair result;
+ AutoDecRef pyFirst(PySequence_GetItem(pyobj, 0));
+ AutoDecRef pySecond(PySequence_GetItem(pyobj, 1));
+ result.first = Converter<typename StdPair::first_type>::toCpp(pyFirst);
+ result.second = Converter<typename StdPair::second_type>::toCpp(pySecond);
+ return result;
+ }
+};
+
+template <typename StdMap>
+struct StdMapConverter
+{
+ static inline bool checkType(PyObject* pyObj)
+ {
+ return isConvertible(pyObj);
+ }
+
+ static inline bool isConvertible(PyObject* pyObj)
+ {
+ if (PyObject_TypeCheck(pyObj, SbkType<StdMap>()))
+ return true;
+ if ((SbkType<StdMap>() && Object::checkType(pyObj)) || !PyDict_Check(pyObj))
+ return false;
+
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(pyObj, &pos, &key, &value)) {
+ if (!Converter<typename StdMap::key_type>::isConvertible(key)
+ || !Converter<typename StdMap::mapped_type>::isConvertible(value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast<StdMap*>(cppObj)); }
+ static PyObject* toPython(const StdMap& cppobj)
+ {
+ PyObject* result = PyDict_New();
+ typename StdMap::const_iterator it = cppobj.begin();
+
+ for (; it != cppobj.end(); ++it) {
+ PyDict_SetItem(result,
+ Converter<typename StdMap::key_type>::toPython(it->first),
+ Converter<typename StdMap::mapped_type>::toPython(it->second));
+ }
+
+ return result;
+ }
+ static StdMap toCpp(PyObject* pyobj)
+ {
+ StdMap result;
+
+ PyObject* key;
+ PyObject* value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next(pyobj, &pos, &key, &value)) {
+ result.insert(typename StdMap::value_type(
+ Converter<typename StdMap::key_type>::toCpp(key),
+ Converter<typename StdMap::mapped_type>::toCpp(value)));
+ }
+ return result;
+ }
+};
+
+
+// class used to translate python objects to another type
+template <typename T> struct PythonConverter {};
+
+} // namespace Shiboken
+
+#endif // CONVERSIONS_H
+