aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Lima <hugo.lima@openbossa.org>2010-03-05 15:43:14 -0300
committerHugo Lima <hugo.lima@openbossa.org>2010-03-18 19:45:07 -0300
commitdc8dcf70f06304105d9a4e6467d98a266dbfe78f (patch)
treeb78dba3e4b94ba3528cdcc7dd7f2e01224b684bf
parentf52951862649d104abf664da5d456b0e0bb987fd (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.cpp12
-rw-r--r--headergenerator.cpp41
-rw-r--r--libshiboken/conversions.h91
-rw-r--r--shibokengenerator.cpp14
-rw-r--r--tests/samplebinding/complex_conversions.h19
-rw-r--r--tests/samplebinding/oddbool_conversions.h2
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);
}