diff options
author | Hugo Lima <hugo.lima@openbossa.org> | 2010-03-05 15:43:14 -0300 |
---|---|---|
committer | Hugo Lima <hugo.lima@openbossa.org> | 2010-03-18 19:45:07 -0300 |
commit | dc8dcf70f06304105d9a4e6467d98a266dbfe78f (patch) | |
tree | b78dba3e4b94ba3528cdcc7dd7f2e01224b684bf | |
parent | f52951862649d104abf664da5d456b0e0bb987fd (diff) |
Changed the semantic of Converter<T>::isConvertible method.
The new semantic is:
Returns true when the type can be converted to T OR the type is T.
The old semantic was:
Returns true when the type can be converted to T and false if the
type is T, however int and float converters did not follow this
rule, because they used PyNumber_Check on their isConvertible implementation.
-rw-r--r-- | cppgenerator.cpp | 12 | ||||
-rw-r--r-- | headergenerator.cpp | 41 | ||||
-rw-r--r-- | libshiboken/conversions.h | 91 | ||||
-rw-r--r-- | shibokengenerator.cpp | 14 | ||||
-rw-r--r-- | tests/samplebinding/complex_conversions.h | 19 | ||||
-rw-r--r-- | tests/samplebinding/oddbool_conversions.h | 2 |
6 files changed, 126 insertions, 53 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index b5c2d8709..749fa001a 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -1057,11 +1057,6 @@ void CppGenerator::writeInvalidCppObjectCheck(QTextStream& s, QString pyArgName, void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType) { - bool writeIsConvertibleCheck = argType->typeEntry()->isObject() || argType->typeEntry()->isValue(); - - if (writeIsConvertibleCheck || isCString(argType) || isPairContainer(argType)) - s << '('; - if (!customType.isEmpty()) s << guessCPythonCheckFunction(customType); else if (argType->typeEntry()->isFlags()) @@ -1072,13 +1067,6 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argTyp s << cpythonCheckFunction(argType, isNumber); s << '(' << argumentName << ')'; - - if (isPairContainer(argType)) - s << " && PySequence_Size(" << argumentName << ") == 2)"; - else if (isCString(argType)) - s << " || " << argumentName << " == Py_None)"; - else if (writeIsConvertibleCheck) - s << " || " << cpythonIsConvertibleFunction(argType) << '(' << argumentName << "))"; } void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName) diff --git a/headergenerator.cpp b/headergenerator.cpp index ea4666384..670e633f7 100644 --- a/headergenerator.cpp +++ b/headergenerator.cpp @@ -164,19 +164,28 @@ void HeaderGenerator::writeTypeConverterDecl(QTextStream& s, const TypeEntry* ty implicitConvs << func; } bool isValueTypeWithImplConversions = type->isValue() && !implicitConvs.isEmpty(); - - s << "struct Converter<" << type->name() << (isAbstractOrObjectType ? "*" : "") << " > : "; - if (type->isEnum() || type->isFlags()) - s << "EnumConverter"; - else if (isAbstractOrObjectType) - s << "ObjectTypeConverter"; - else - s << "ValueTypeConverter"; - s << '<' << type->name() << " >" << endl; - s << '{' << endl; - if (isValueTypeWithImplConversions) { + bool hasCustomConversion = type->hasConversionRule(); + QString typeT = type->name() + (isAbstractOrObjectType ? "*" : ""); + + s << "struct Converter<" << typeT << " >"; + if (!hasCustomConversion) { + if (type->isEnum() || type->isFlags()) + s << " : EnumConverter"; + else if (isAbstractOrObjectType) + s << " : ObjectTypeConverter"; + else + s << " : ValueTypeConverter"; + s << '<' << type->name() << " >"; + } + s << endl << '{' << endl; + if (isValueTypeWithImplConversions || hasCustomConversion) { s << INDENT << "static " << type->name() << " toCpp(PyObject* pyobj);" << endl; s << INDENT << "static bool isConvertible(PyObject* pyobj);" << endl; + if (hasCustomConversion) { + s << INDENT << "static inline PyObject* toPython(void* cppObj) { return toPython(*reinterpret_cast<" + << type->name() << (isAbstractOrObjectType ? "" : "*") << " >(cppObj)); }" << endl; + s << INDENT << "static PyObject* toPython(const " << type->name() << "& cppObj);" << endl; + } } s << "};" << endl; } @@ -469,6 +478,14 @@ void HeaderGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* ty // Write Converter<T>::isConvertible s << "inline bool Shiboken::Converter<" << type->name() << " >::isConvertible(PyObject* pyobj)" << endl; s << '{' << endl; + + if (type->isValue()) { + s << INDENT << "if (ValueTypeConverter<" << type->name() << " >::isConvertible(pyobj))" << endl; + Indentation indent(INDENT); + s << INDENT << "return true;" << endl; + } + + s << INDENT << "SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<"; s << type->name() << " >());" << endl; s << INDENT << "return "; @@ -500,7 +517,7 @@ void HeaderGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* ty { Indentation indent(INDENT); s << INDENT << "SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<"; - s << type->name() << ">());" << endl; + s << type->name() << " >());" << endl; } bool firstImplicitIf = true; foreach (const AbstractMetaFunction* ctor, implicitConvs) { diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h index 8d9cddf1f..0b94b328e 100644 --- a/libshiboken/conversions.h +++ b/libshiboken/conversions.h @@ -42,10 +42,12 @@ #include "pyenum.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 +#include "autodecref.h" namespace Shiboken { @@ -124,12 +126,13 @@ template <typename T> struct Converter {}; // Pointer conversion specialization for value types. template <typename T> -struct Converter<T*> : Converter<T> +struct Converter<T*> { - /// Value type pointers should be convertible only to NULL pointers, represented in Python by a 'None' object. - static inline bool isConvertible(PyObject* pyobj) { return pyobj == Py_None; } - /// Convenience overload that calls "toPython(const T*)" method. - static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast<T*>(cppobj)); } + static inline bool isConvertible(PyObject* pyObj) + { + return pyObj == Py_None || PyObject_TypeCheck(pyObj, SbkType<T>()); + } + static PyObject* toPython(const T* cppobj) { if (!cppobj) @@ -141,6 +144,7 @@ struct Converter<T*> : Converter<T> pyobj = createWrapper<T>(cppobj); return pyobj; } + static T* toCpp(PyObject* pyobj) { if (Shiboken_TypeCheck(pyobj, T)) @@ -154,19 +158,20 @@ template <typename T> struct Converter<const T*> : Converter<T*> {}; // Specialization for reference conversions. template <typename T> -struct Converter<T&> : Converter<T*> +struct Converter<T&> { - static inline PyObject* toPython(void* cppobj) { return toPython(*reinterpret_cast<T*>(cppobj)); } + 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); } }; + template <typename T> struct Converter<const T&> : Converter<T&> {}; // Void pointer conversions. template<> struct Converter<void*> { - static inline bool isConvertible(PyObject* pyobj) { return false; } + static inline bool isConvertible(PyObject* pyobj) { return true; } static PyObject* toPython(const void* cppobj) { PyObject* pyobj = BindingManager::instance().retrieveWrapper(cppobj); @@ -194,6 +199,8 @@ struct ValueTypeConverter // 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; SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()); if (shiboType->ext_isconvertible) return shiboType->ext_isconvertible(pyobj); @@ -213,11 +220,14 @@ struct ValueTypeConverter // use them if it is the case. static inline T toCpp(PyObject* pyobj) { - if (isConvertible(pyobj)) { - SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(SbkType<T>()); - T* cptr = reinterpret_cast<T*>(shiboType->ext_tocpp(pyobj)); - std::auto_ptr<T> cptr_auto_ptr(cptr); - return *cptr; + PyTypeObject* typeObj = SbkType<T>(); + if (typeObj->ob_type == &Shiboken::SbkBaseWrapperType_Type) { + SbkBaseWrapperType* shiboType = reinterpret_cast<SbkBaseWrapperType*>(typeObj); + if (shiboType->ext_tocpp && isConvertible(pyobj)) { + T* cptr = reinterpret_cast<T*>(shiboType->ext_tocpp(pyobj)); + std::auto_ptr<T> cptr_auto_ptr(cptr); + return *cptr; + } } return *reinterpret_cast<T*>(reinterpret_cast<Shiboken::SbkBaseWrapper*>(pyobj)->cptr); } @@ -230,7 +240,7 @@ template <typename T> struct ObjectTypeConverter { /// 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; } + 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. @@ -425,6 +435,7 @@ struct Converter<unsigned PY_LONG_LONG> template <typename PyFloatEquiv> struct Converter_PyFloat { + static inline bool isConvertible(PyObject* obj) { return PyNumber_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) @@ -442,6 +453,7 @@ template <> struct Converter<double> : Converter_PyFloat<double> {}; template <typename CppEnum> struct EnumConverter { + 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) { @@ -457,6 +469,7 @@ struct EnumConverter template <typename CString> struct Converter_CString { + static inline bool isConvertible(PyObject* pyObj) { return pyObj == Py_None || PyString_Check(pyObj); } static inline PyObject* toPython(void* cppobj) { return toPython(reinterpret_cast<CString>(cppobj)); } static inline PyObject* toPython(CString cppobj) { @@ -488,9 +501,18 @@ template <> struct Converter<const char*> : Converter_CString<const char*> {}; template <typename StdList> struct Converter_std_list { - static inline bool isConvertible(const PyObject* pyObj) - { - return PySequence_Check(const_cast<PyObject*>(pyObj)); + static inline bool isConvertible(PyObject* pyObj) + { + if (PyObject_TypeCheck(pyObj, SbkType<StdList>())) + return true; + if (!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(const StdList& cppobj) { @@ -516,9 +538,21 @@ struct Converter_std_list template <typename StdPair> struct Converter_std_pair { - static inline bool isConvertible(const PyObject* pyObj) + static inline bool isConvertible(PyObject* pyObj) { - return PySequence_Check(const_cast<PyObject*>(pyObj)); + if (PyObject_TypeCheck(pyObj, SbkType<StdPair>())) + return true; + if (!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(const StdPair& cppobj) { @@ -543,9 +577,24 @@ struct Converter_std_pair template <typename StdMap> struct Converter_std_map { - static inline bool isConvertible(const PyObject* pyObj) + static inline bool isConvertible(PyObject* pyObj) { - return PyDict_Check(const_cast<PyObject*>(pyObj)); + if (PyObject_TypeCheck(pyObj, SbkType<StdMap>())) + return true; + if (!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(const StdMap& cppobj) diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp index 653e8ddb6..4fd54f746 100644 --- a/shibokengenerator.cpp +++ b/shibokengenerator.cpp @@ -590,6 +590,7 @@ bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractM static QString checkFunctionName(QString baseName, bool genericNumberType, bool checkExact) { + // TODO: Remove checkExact argument. return QString("%1_Check%2") .arg((genericNumberType && ShibokenGenerator::isNumber(baseName) ? "PyNumber" : baseName)) .arg((checkExact && !genericNumberType ? "Exact" : "")); @@ -597,9 +598,18 @@ static QString checkFunctionName(QString baseName, bool genericNumberType, bool QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType, bool checkExact) { - if (metaType->typeEntry()->isCustom()) + QString baseName = cpythonBaseName(metaType); + if (metaType->typeEntry()->isCustom()) { return guessCPythonCheckFunction(metaType->typeEntry()->name()); - return checkFunctionName(cpythonBaseName(metaType), genericNumberType, checkExact); + } else if (isNumber(baseName)) { + return genericNumberType ? "PyNumber_Check" : baseName+"_Check"; + } else { + QString str; + QTextStream s(&str); + writeBaseConversion(s, metaType, 0); + s.flush(); + return str + "isConvertible"; + } } QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType, bool checkExact) diff --git a/tests/samplebinding/complex_conversions.h b/tests/samplebinding/complex_conversions.h index 6a69b26f3..0e5e2cfaf 100644 --- a/tests/samplebinding/complex_conversions.h +++ b/tests/samplebinding/complex_conversions.h @@ -1,19 +1,28 @@ namespace Shiboken { template<> -struct Converter<Complex> : public ValueTypeConverter<Complex> +struct Converter<Complex> { - static bool isConvertible(const PyObject* pyObj) + static inline bool checkType(PyObject* pyObj) { return PyComplex_Check(pyObj); } - using ValueTypeConverter<Complex>::toPython; + static inline bool isConvertible(PyObject* pyObj) + { + return PyComplex_Check(pyObj); + } - static PyObject* toPython(const Complex& cpx) + static inline PyObject* toPython(void* cppobj) + { + return toPython(*reinterpret_cast<Complex*>(cppobj)); + } + + static inline PyObject* toPython(const Complex& cpx) { return PyComplex_FromDoubles(cpx.real(), cpx.imag()); } - static Complex toCpp(PyObject* pyobj) + + static inline Complex toCpp(PyObject* pyobj) { double real = PyComplex_RealAsDouble(pyobj); double imag = PyComplex_ImagAsDouble(pyobj); diff --git a/tests/samplebinding/oddbool_conversions.h b/tests/samplebinding/oddbool_conversions.h index 452b94725..74ecef24d 100644 --- a/tests/samplebinding/oddbool_conversions.h +++ b/tests/samplebinding/oddbool_conversions.h @@ -2,7 +2,7 @@ namespace Shiboken { template <> struct Converter<OddBool> : public ValueTypeConverter<OddBool> { - static bool isConvertible(const PyObject* pyObj) + static bool isConvertible(PyObject* pyObj) { return PyBool_Check(pyObj); } |