diff options
author | Marcelo Lira <marcelo.lira@openbossa.org> | 2011-08-16 16:03:21 -0300 |
---|---|---|
committer | Marcelo Lira <marcelo.lira@openbossa.org> | 2011-12-09 20:28:06 -0300 |
commit | 11eda546a3bc3133ab180c6be5723f10a2abcf22 (patch) | |
tree | d5e489f838a9e39e23ebd86c76a023c5c5c03d2f | |
parent | 3783e1c72b5497c5564a02308efb0b1fc7d4e224 (diff) | |
download | shiboken-11eda546a3bc3133ab180c6be5723f10a2abcf22.tar.gz shiboken-11eda546a3bc3133ab180c6be5723f10a2abcf22.tar.xz shiboken-11eda546a3bc3133ab180c6be5723f10a2abcf22.zip |
New converters for C++ primitive types.
-rw-r--r-- | generator/cppgenerator.cpp | 39 | ||||
-rw-r--r-- | generator/headergenerator.cpp | 2 | ||||
-rw-r--r-- | generator/shibokengenerator.cpp | 148 | ||||
-rw-r--r-- | generator/shibokengenerator.h | 9 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 2 | ||||
-rw-r--r-- | libshiboken/sbkconverter.cpp | 32 | ||||
-rw-r--r-- | libshiboken/sbkconverter.h | 44 | ||||
-rw-r--r-- | libshiboken/sbkconverter_p.h | 367 |
8 files changed, 591 insertions, 52 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp index 9fe65ca2..cb59b809 100644 --- a/generator/cppgenerator.cpp +++ b/generator/cppgenerator.cpp @@ -799,7 +799,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (func->type() && func->typeReplaced(0) != "PyObject") { // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(func->type()) || isUserPrimitive(func->type())) { + if (func->typeReplaced(0).isEmpty() && (isWrapperType(func->type()) || isUserPrimitive(func->type()) || isCppPrimitive(func->type()))) { s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type()); s << PYTHON_RETURN_VAR ");" << endl; s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl; @@ -1069,9 +1069,9 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla typeCheck = QString("%1(pyIn)").arg(typeCheck); } - if (isUserPrimitive(sourceType)) { + if (isUserPrimitive(sourceType) || isCppPrimitive(sourceType)) { QTextStream pc(&toCppPreConv); - pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn = "; + pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"; writeMinimalConstructorExpression(pc, sourceType); pc << ';' << endl; writeToCppConversion(pc, sourceType, 0, "pyIn", "cppIn"); @@ -1079,7 +1079,7 @@ void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaCla toCppConv.append("cppIn"); } else if (!isWrapperType(sourceType)) { QTextStream tcc(&toCppConv); - writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*BOZO-1043*/"); + writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*BOZO-1061*/"); } // TODO-CONVERTER ----------------------------------------------------------------------- } @@ -1792,8 +1792,10 @@ void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argTyp typeCheck.append(QString("(%1)").arg(argumentName)); // TODO-CONVERTER ----------------------------------------------------------------------- - if (customCheck.isEmpty() && (isWrapperType(argType) || isUserPrimitive(argType))) { + if (customCheck.isEmpty() && (isWrapperType(argType) || isUserPrimitive(argType) || isCppPrimitive(argType))) { typeCheck = QString("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName)).arg(typeCheck); + if (!isNumber && argType->typeEntry()->isCppPrimitive()) + typeCheck.prepend(QString("/*BOZOisNumber*/ %1(%2) && ").arg(cpythonCheckFunction(argType)).arg(argumentName)); } // TODO-CONVERTER ----------------------------------------------------------------------- @@ -1879,16 +1881,17 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, QString cppOutAux = QString("%1_local").arg(cppOut); // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(type) || isUserPrimitive(type)) { + if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) { bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type); - bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && /*TODO-CONVERTERS: is this really needed?*/ !isUserPrimitive(type); + bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && /*TODO-CONVERTERS: is this really needed?*/ !isUserPrimitive(type) && !isCppPrimitive(type); bool mayHaveImplicitConversion = type->isReference() && !isUserPrimitive(type) + && !isCppPrimitive(type) && !(treatAsPointer || isPointerOrObjectType); QString typeName = getFullTypeNameWithoutModifiers(type); if (mayHaveImplicitConversion) { - s << INDENT << typeName << ' ' << cppOutAux << " = "; + s << INDENT << typeName << ' ' << cppOutAux; writeMinimalConstructorExpression(s, type, defaultValue); s << ';' << endl; } @@ -1899,7 +1902,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, } else if (type->isReference() && !type->typeEntry()->isPrimitive()) { s << "* " << cppOut << " = &" << cppOutAux; } else { - s << ' ' << cppOut << " = "; + s << ' ' << cppOut; if (isUserPrimitive(type)) writeMinimalConstructorExpression(s, type->typeEntry(), defaultValue); else @@ -1944,7 +1947,7 @@ void CppGenerator::writePythonToCppTypeConversion(QTextStream& s, QString conversion; QTextStream c(&conversion); - writeToCppConversion(c, type, context, pyIn, "/*BOZO-1906*/"); + writeToCppConversion(c, type, context, pyIn, "/*BOZO-1925*/"); // Value type that has default value. if (type->isValue() && !defaultValue.isEmpty()) @@ -3424,6 +3427,11 @@ void CppGenerator::writeGetterFunction(QTextStream& s, const AbstractMetaField* cppField.append(')'); } } + if (isCppIntegralPrimitive(fieldType)) { + s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl; + s << INDENT; + cppField = "cppOut_local"; + } s << INDENT << "PyObject* pyOut = "; if (newWrapperSameObject) { @@ -3459,7 +3467,7 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* AbstractMetaType* fieldType = metaField->type(); // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(fieldType) || isUserPrimitive(fieldType)) { + if (isWrapperType(fieldType) || isUserPrimitive(fieldType) || isCppPrimitive(fieldType)) { s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; } // TODO-CONVERTER ----------------------------------------------------------------------- @@ -3476,8 +3484,9 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* s << INDENT << '}' << endl << endl; // TODO-CONVERTER ----------------------------------------------------------------------- + QString cppField = QString("%1->%2").arg(CPP_SELF_VAR).arg(metaField->name()); s << INDENT; - if (isWrapperType(fieldType) || isUserPrimitive(fieldType)) { + if (isWrapperType(fieldType) || isUserPrimitive(fieldType) || isCppPrimitive(fieldType)) { if (avoidProtectedHack() && metaField->isProtected()) { s << getFullTypeNameWithoutModifiers(fieldType); s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl; @@ -3485,8 +3494,12 @@ void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* s << INDENT << QString("((%1*)%2)->%3(cppOut)").arg(wrapperName(metaField->enclosingClass())) .arg(CPP_SELF_VAR) .arg(protectedFieldSetterName(metaField)); + } else if (isCppIntegralPrimitive(fieldType)) { + s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl; + s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl; + s << INDENT << cppField << " = cppOut_local;" << endl; } else { - s << PYTHON_TO_CPP_VAR << QString("(pyIn, &(%1->%2))").arg(CPP_SELF_VAR).arg(metaField->name()); + s << PYTHON_TO_CPP_VAR << "(pyIn, &(" << cppField << "))"; } } else { // TODO-CONVERTER -------------------------------------------------------------- QString conversion; diff --git a/generator/headergenerator.cpp b/generator/headergenerator.cpp index e6668853..2b32138f 100644 --- a/generator/headergenerator.cpp +++ b/generator/headergenerator.cpp @@ -595,7 +595,7 @@ void HeaderGenerator::writeTypeConverterImpl(QTextStream& s, const TypeEntry* ty s << '{' << endl; s << INDENT << "PythonToCppFunc toCpp = Shiboken::Conversions::isPythonToCppValueConvertible((SbkObjectType*)"; s << cpythonTypeNameExt(type) << ", pyIn);" << endl; - s << INDENT << typeName << " cppOut = "; + s << INDENT << typeName << " cppOut"; writeMinimalConstructorExpression(s, type); s << ';' << endl; s << INDENT << "toCpp(pyIn, &cppOut);" << endl; diff --git a/generator/shibokengenerator.cpp b/generator/shibokengenerator.cpp index 19a8f7da..e8297d30 100644 --- a/generator/shibokengenerator.cpp +++ b/generator/shibokengenerator.cpp @@ -84,8 +84,10 @@ ShibokenGenerator::ShibokenGenerator() : Generator() m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp("%CHECKTYPE\\[([^\\[]*)\\]\\("); m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp("%ISCONVERTIBLE\\[([^\\[]*)\\]\\("); m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp("%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("); - m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp("((?:[a-zA-Z_%][\\w%]*\\s*[\\*&]?\\s+)*)((?:\\*\\s*)?[a-zA-Z_%][\\w%]*"\ - "(?:\\[[^\\[]+\\])*)(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("); + m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp("(\\s*//[^\\n]*\\n\\s*)*" + "((?:[a-zA-Z_%][\\w%]*\\s*[\\*&]?\\s+)*)" + "((?:\\*\\s*)?[a-zA-Z_%][\\w%]*(?:\\[[^\\[]+\\])*)" + "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("); } ShibokenGenerator::~ShibokenGenerator() @@ -121,7 +123,9 @@ void ShibokenGenerator::initPrimitiveTypesCorrespondences() m_pythonPrimitiveTypeName["short"] = "PyInt"; m_pythonPrimitiveTypeName["ushort"] = "PyInt"; m_pythonPrimitiveTypeName["signed short"] = "PyInt"; + m_pythonPrimitiveTypeName["signed short int"] = "PyInt"; m_pythonPrimitiveTypeName["unsigned short"] = "PyInt"; + m_pythonPrimitiveTypeName["unsigned short int"] = "PyInt"; m_pythonPrimitiveTypeName["long"] = "PyInt"; // PyFloat @@ -591,7 +595,7 @@ void ShibokenGenerator::writeToPythonConversion(QTextStream& s, const AbstractMe const AbstractMetaClass* context, const QString& argumentName) { // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(type) || isUserPrimitive(type)) { + if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) { s << cpythonToPythonConversionFunction(type) << argumentName << ')'; return; } @@ -612,7 +616,7 @@ void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaT const QString& inArgName, const QString& outArgName) { // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(type) || isUserPrimitive(type)) { + if (isWrapperType(type) || isUserPrimitive(type) || isCppPrimitive(type)) { s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')'; return; } @@ -766,11 +770,18 @@ QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) QString ShibokenGenerator::converterObject(const AbstractMetaType* type) { + if (isCString(type)) + return "Shiboken::Conversions::PrimitiveTypeConverter<const char*>()"; + if (isVoidPointer(type)) + return "Shiboken::Conversions::PrimitiveTypeConverter<void*>()"; return converterObject(type->typeEntry()); } QString ShibokenGenerator::converterObject(const TypeEntry* type) { - return convertersVariableName(type->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']'; + if (isCppPrimitive(type)) + return QString("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); + QString converters; + return QString("%1[%2]").arg(convertersVariableName(type->targetLangPackage())).arg(getTypeIndexVariableName(type)); } QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type) @@ -904,6 +915,13 @@ bool ShibokenGenerator::isCString(const AbstractMetaType* type) && type->name() == "char"; } +bool ShibokenGenerator::isVoidPointer(const AbstractMetaType* type) +{ + return type->isNativePointer() + && type->indirections() == 1 + && type->name() == "void"; +} + bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type) { return type->isContainer() @@ -972,6 +990,27 @@ bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType* type) return isUserPrimitive(type->typeEntry()); } +bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type) +{ + if (type->isCppPrimitive()) + return true; + if (!type->isPrimitive()) + return false; + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicAliasedTypeEntry()) + trueType = trueType->basicAliasedTypeEntry(); + return trueType->qualifiedCppName() == "std::string"; +} + +bool ShibokenGenerator::isCppPrimitive(const AbstractMetaType* type) +{ + if (isCString(type) || isVoidPointer(type)) + return true; + if (type->indirections() != 0) + return false; + return isCppPrimitive(type->typeEntry()); +} + bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg) { return shouldDereferenceAbstractMetaTypePointer(arg->type()); @@ -1004,8 +1043,15 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType } // TODO-CONVERTER ----------------------------------------------------------------------- - if (isWrapperType(metaType) || isUserPrimitive(metaType)) + if (isCppPrimitive(metaType)) { + if (isCString(metaType)) + return "SbkString_Check"; + if (isVoidPointer(metaType)) + return "PyObject_Check"; return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); + } else if (isWrapperType(metaType) || isUserPrimitive(metaType)) { + return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); + } // TODO-CONVERTER ----------------------------------------------------------------------- QString baseName = cpythonBaseName(metaType); @@ -1036,6 +1082,8 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene // TODO-CONVERTER ----------------------------------------------------------------------- if (isWrapperType(type)) { return QString("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type)); + } else if (isCppPrimitive(type)) { + return QString("%1_Check").arg(pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type)); } else if (isUserPrimitive(type)) { QString typeCheck; if (!type->targetLangApiName().isEmpty()) @@ -1094,7 +1142,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, b : "isPythonToCppPointerConvertible"; return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ") .arg(isConv).arg(cpythonTypeNameExt(type)); - } else if (isUserPrimitive(type)) { + } else if (isUserPrimitive(type) || isCppPrimitive(type)) { return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ") .arg(converterObject(type)); } @@ -1134,7 +1182,7 @@ QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* isConv = "isPythonToCppValueConvertible"; return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ") .arg(isConv).arg(cpythonTypeNameExt(metaType)); - } else if (isUserPrimitive(metaType)) { + } else if (isUserPrimitive(metaType) || isCppPrimitive(metaType)) { return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ") .arg(converterObject(metaType)); } @@ -1168,7 +1216,7 @@ QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType return QString("Shiboken::Conversions::pythonToCpp%1((SbkObjectType*)%2, ") .arg(isPointer(type) ? "Pointer" : "Copy") .arg(cpythonTypeNameExt(type)); - } else if (isUserPrimitive(type)) { + } else if (isUserPrimitive(type) || isCppPrimitive(type)) { return QString("Shiboken::Conversions::pythonToCpp(%1, ") .arg(converterObject(type)); } @@ -1192,8 +1240,10 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaT conversion = "pointer"; return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3") .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&"); - } else if (isUserPrimitive(type)) { - return QString("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type)); + } else if (isUserPrimitive(type) || isCppPrimitive(type)) { + return QString("Shiboken::Conversions::copyToPython(%1, %2") + .arg(converterObject(type)) + .arg((isCString(type) || isVoidPointer(type)) ? "" : "&"); } // TODO-CONVERTER ----------------------------------------------------------------------- // exclude const on Objects @@ -1220,7 +1270,7 @@ QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* ty conversion = "pointer"; return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3") .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&"); - } else if (isUserPrimitive(type)) { + } else if (isUserPrimitive(type) || isCppPrimitive(type)) { return QString("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type)); } // TODO-CONVERTER ----------------------------------------------------------------------- @@ -1784,10 +1834,13 @@ static bool isVariable(const QString& code) static QString miniNormalizer(const QString& varType) { QString normalized = varType.trimmed(); + if (normalized.isEmpty()) + return normalized; QString suffix; while (normalized.endsWith('*') || normalized.endsWith('&')) { suffix.prepend(normalized.at(normalized.count() - 1)); normalized.chop(1); + normalized = normalized.trimmed(); } return QString("%1 %2").arg(normalized).arg(suffix).trimmed(); } @@ -1834,20 +1887,21 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa if (conversionType) { switch (converterVariable) { case TypeSystemToCppFunction: { - if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType)) { - c << list.at(1) << list.at(2) << " = "; + c << list.at(1); + if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType) && !isCppPrimitive(conversionType)) { + c << list.at(2) << list.at(3) << " = "; c << cpythonToCppConversionFunction(conversionType); c << '('; break; } - QString varType = miniNormalizer(list.at(1)); - QString varName = list.at(2).trimmed(); + QString varType = miniNormalizer(list.at(2)); + QString varName = list.at(3).trimmed(); if (!varType.isEmpty()) { if (varType != conversionType->cppSignature()) { qFatal(qPrintable(QString("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.") .arg(varType).arg(conversionType->cppSignature())), NULL); } - c << getFullTypeName(conversionType) << ' ' << varName << " = "; + c << getFullTypeName(conversionType) << ' ' << varName; writeMinimalConstructorExpression(c, conversionType); c << ';' << endl; Indentation indent(INDENT); @@ -1856,7 +1910,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa c << cpythonToCppConversionFunction(conversionType); QString prefix; if (varName.startsWith('*')) { - varName.chop(1); + varName.remove(0, 1); varName = varName.trimmed(); } else { prefix = '&'; @@ -1876,7 +1930,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa conversion = cpythonToPythonConversionFunction(conversionType); default: { // TODO-CONVERTER ----------------------------------------------------------------------- - if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType)) { + if (!isWrapperType(conversionType) && !isUserPrimitive(conversionType) && !isCppPrimitive(conversionType)) { c << '('; break; } @@ -1898,8 +1952,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa } } } else { - if (list.count() > 2) - c << list.at(1) << list.at(2) << " = "; + if (list.count() > 3) + c << list.at(2) << list.at(3) << " = "; c << QString("Shiboken::Converter< %1 >::%2(").arg(conversionTypeName).arg(conversionName); } replacements.append(qMakePair(conversionString, conversion)); @@ -2322,6 +2376,11 @@ QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* met } QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) { + if (type->isCppPrimitive()) { + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicAliasedTypeEntry()) + type = trueType->basicAliasedTypeEntry(); + } return QString("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); } QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) @@ -2336,7 +2395,9 @@ QString ShibokenGenerator::getFullTypeName(const TypeEntry* type) QString ShibokenGenerator::getFullTypeName(const AbstractMetaType* type) { if (isCString(type)) - return QString("const char*"); + return "const char*"; + if (isVoidPointer(type)) + return "void*"; return getFullTypeName(type->typeEntry()) + QString("*").repeated(type->indirections()); } QString ShibokenGenerator::getFullTypeName(const AbstractMetaClass* metaClass) @@ -2345,6 +2406,10 @@ QString ShibokenGenerator::getFullTypeName(const AbstractMetaClass* metaClass) } QString ShibokenGenerator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) { + if (isCString(type)) + return "const char*"; + if (isVoidPointer(type)) + return "void*"; if (!type->hasInstantiations()) return getFullTypeName(type->typeEntry()); QString typeName = type->cppSignature(); @@ -2411,24 +2476,35 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co // TODO-CONVERTER ----------------------------------------------------------------------- void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor) { - QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - if (ctor.isEmpty()) { - QString errorMsg = QString(MIN_CTOR_ERROR_MSG).arg(type->cppSignature()); - ReportHandler::warning(errorMsg); - s << endl << INDENT << "#error " << errorMsg << endl; + if (defaultCtor.isEmpty() && isCppPrimitive(type)) return; - } - s << ctor; + QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; + if (ctor.isEmpty()) + qFatal(qPrintable(QString(MIN_CTOR_ERROR_MSG).arg(type->cppSignature())), NULL); + s << " = " << ctor; } void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor) { - QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - if (ctor.isEmpty()) { - QString errorMsg = QString(MIN_CTOR_ERROR_MSG).arg(type->qualifiedCppName()); - ReportHandler::warning(errorMsg); - s << endl << INDENT << "#error " << errorMsg << endl; + if (defaultCtor.isEmpty() && isCppPrimitive(type)) return; - } - s << ctor; + QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; + if (ctor.isEmpty()) + qFatal(qPrintable(QString(MIN_CTOR_ERROR_MSG).arg(type->qualifiedCppName())), NULL); + s << " = " << ctor; +} + +bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type) +{ + if (!type->isCppPrimitive()) + return false; + const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + if (trueType->basicAliasedTypeEntry()) + trueType = trueType->basicAliasedTypeEntry(); + QString typeName = trueType->qualifiedCppName(); + return !typeName.contains("double") && !typeName.contains("float") && !typeName.contains("wchar"); +} +bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type) +{ + return isCppIntegralPrimitive(type->typeEntry()); } // TODO-CONVERTER ----------------------------------------------------------------------- diff --git a/generator/shibokengenerator.h b/generator/shibokengenerator.h index 00de9586..8cd91c2e 100644 --- a/generator/shibokengenerator.h +++ b/generator/shibokengenerator.h @@ -289,6 +289,7 @@ public: static bool isPyInt(const TypeEntry* type); static bool isPyInt(const AbstractMetaType* type); static bool isCString(const AbstractMetaType* type); + static bool isVoidPointer(const AbstractMetaType* type); static bool isPairContainer(const AbstractMetaType* type); /** @@ -313,6 +314,14 @@ public: static bool isUserPrimitive(const TypeEntry* type); static bool isUserPrimitive(const AbstractMetaType* type); + /// Returns true if the type is a C++ primitive, a void*, a const char*, or a std::string. + static bool isCppPrimitive(const TypeEntry* type); + static bool isCppPrimitive(const AbstractMetaType* type); + + /// Returns true if the type is a C++ integral primitive, i.e. bool, char, int, long, and their unsigned counterparts. + static bool isCppIntegralPrimitive(const TypeEntry* type); + static bool isCppIntegralPrimitive(const AbstractMetaType* type); + /// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method. static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg); /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++. diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp index 181b7025..fc83d44c 100644 --- a/libshiboken/basewrapper.cpp +++ b/libshiboken/basewrapper.cpp @@ -462,6 +462,7 @@ void DeallocVisitor::done() } namespace Module { void init(); } +namespace Conversions { void init(); } void init() { @@ -470,6 +471,7 @@ void init() return; Module::init(); + Conversions::init(); initTypeResolver(); PyEval_InitThreads(); diff --git a/libshiboken/sbkconverter.cpp b/libshiboken/sbkconverter.cpp index c5e64f3d..34705d9e 100644 --- a/libshiboken/sbkconverter.cpp +++ b/libshiboken/sbkconverter.cpp @@ -26,9 +26,35 @@ #include "sbkdbg.h" +static SbkConverter** PrimitiveTypeConverters; + namespace Shiboken { namespace Conversions { +void init() +{ + static SbkConverter* primitiveTypeConverters[] = { + Primitive<PY_LONG_LONG>::createConverter(), + Primitive<bool>::createConverter(), + Primitive<char>::createConverter(), + Primitive<const char*>::createConverter(), + Primitive<double>::createConverter(), + Primitive<float>::createConverter(), + Primitive<int>::createConverter(), + Primitive<long>::createConverter(), + Primitive<short>::createConverter(), + Primitive<signed char>::createConverter(), + Primitive<std::string>::createConverter(), + Primitive<unsigned PY_LONG_LONG>::createConverter(), + Primitive<unsigned char>::createConverter(), + Primitive<unsigned int>::createConverter(), + Primitive<unsigned long>::createConverter(), + Primitive<unsigned short>::createConverter(), + Primitive<void*>::createConverter() + }; + PrimitiveTypeConverters = primitiveTypeConverters; +} + static SbkConverter* createConverterObject(PyTypeObject* type, PythonToCppFunc toCppPointerConvFunc, IsConvertibleToCppFunc toCppPointerCheckFunc, @@ -113,7 +139,6 @@ PyObject* referenceToPython(SbkObjectType* type, const void* cppIn) static inline PyObject* CopyCppToPython(SbkConverter* converter, const void* cppIn) { - assert(cppIn); return converter->copyToPython(cppIn); } PyObject* copyToPython(SbkObjectType* type, const void* cppIn) @@ -228,4 +253,9 @@ bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCppFunc) return toCppFunc != (*conv).second; } +SbkConverter* primitiveTypeConverter(int index) +{ + return PrimitiveTypeConverters[index]; +} + } } // namespace Shiboken::Conversions diff --git a/libshiboken/sbkconverter.h b/libshiboken/sbkconverter.h index 1d539248..6c10df2a 100644 --- a/libshiboken/sbkconverter.h +++ b/libshiboken/sbkconverter.h @@ -36,6 +36,8 @@ #define SbkObject_TypeCheck(tp, ob) \ (Py_TYPE(ob) == (tp) || PyType_IsSubtype(Py_TYPE(ob), (tp))) +#define SbkString_Check(pyObj) (pyObj == Py_None || PyString_Check(pyObj)) + extern "C" { @@ -83,7 +85,6 @@ typedef PythonToCppFunc (*IsConvertibleToCppFunc)(PyObject*); } // extern "C" - namespace Shiboken { namespace Conversions { @@ -211,6 +212,47 @@ LIBSHIBOKEN_API void nonePythonToCppNullPtr(PyObject*, void* cppOut); */ LIBSHIBOKEN_API bool isImplicitConversion(SbkObjectType* type, PythonToCppFunc toCpp); +/// Returns the converter for a primitive type. +LIBSHIBOKEN_API SbkConverter* primitiveTypeConverter(int index); + +#define SBK_PY_LONG_LONG_IDX 0 +#define SBK_BOOL_IDX 1 +#define SBK_CHAR_IDX 2 +#define SBK_CONSTCHARPTR_IDX 3 +#define SBK_DOUBLE_IDX 4 +#define SBK_FLOAT_IDX 5 +#define SBK_INT_IDX 6 +#define SBK_SIGNEDINT_IDX 6 +#define SBK_LONG_IDX 7 +#define SBK_SHORT_IDX 8 +#define SBK_SIGNEDCHAR_IDX 9 +#define SBK_STD_STRING_IDX 10 +#define SBK_UNSIGNEDPY_LONG_LONG_IDX 11 +#define SBK_UNSIGNEDCHAR_IDX 12 +#define SBK_UNSIGNEDINT_IDX 13 +#define SBK_UNSIGNEDLONG_IDX 14 +#define SBK_UNSIGNEDSHORT_IDX 15 +#define SBK_VOIDPTR_IDX 16 + +template<typename T> SbkConverter* PrimitiveTypeConverter() { return 0; } +template<> inline SbkConverter* PrimitiveTypeConverter<PY_LONG_LONG>() { return primitiveTypeConverter(SBK_PY_LONG_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<bool>() { return primitiveTypeConverter(SBK_BOOL_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<char>() { return primitiveTypeConverter(SBK_CHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<const char*>() { return primitiveTypeConverter(SBK_CONSTCHARPTR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<double>() { return primitiveTypeConverter(SBK_DOUBLE_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<float>() { return primitiveTypeConverter(SBK_FLOAT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<int>() { return primitiveTypeConverter(SBK_INT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<long>() { return primitiveTypeConverter(SBK_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<short>() { return primitiveTypeConverter(SBK_SHORT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<signed char>() { return primitiveTypeConverter(SBK_SIGNEDCHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<std::string>() { return primitiveTypeConverter(SBK_STD_STRING_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<unsigned PY_LONG_LONG>() { return primitiveTypeConverter(SBK_UNSIGNEDPY_LONG_LONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<unsigned char>() { return primitiveTypeConverter(SBK_UNSIGNEDCHAR_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<unsigned int>() { return primitiveTypeConverter(SBK_UNSIGNEDINT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<unsigned long>() { return primitiveTypeConverter(SBK_UNSIGNEDLONG_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<unsigned short>() { return primitiveTypeConverter(SBK_UNSIGNEDSHORT_IDX); } +template<> inline SbkConverter* PrimitiveTypeConverter<void*>() { return primitiveTypeConverter(SBK_VOIDPTR_IDX); } + } } // namespace Shiboken::Conversions #endif // SBK_CONVERTER_H diff --git a/libshiboken/sbkconverter_p.h b/libshiboken/sbkconverter_p.h index 199538cc..8abdc297 100644 --- a/libshiboken/sbkconverter_p.h +++ b/libshiboken/sbkconverter_p.h @@ -25,8 +25,11 @@ #include <Python.h> #include <list> +#include <limits> #include "sbkconverter.h" +#include "sbkdbg.h" + extern "C" { @@ -87,4 +90,368 @@ struct SbkConverter } // extern "C" +// Helper template for checking if a value overflows when cast 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& value) { return false; } +}; +template<> +struct OverFlowChecker<double, true> { + static bool check(const double& value) { 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(); + } +}; + +// Basic primitive type converters --------------------------------------------------------- +template<typename T> PyTypeObject* SbkType() { return 0; } +template<> inline PyTypeObject* SbkType<PY_LONG_LONG>() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType<bool>() { return &PyBool_Type; } +template<> inline PyTypeObject* SbkType<char>() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType<const char*>() { return &PyString_Type; } +template<> inline PyTypeObject* SbkType<double>() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType<float>() { return &PyFloat_Type; } +template<> inline PyTypeObject* SbkType<int>() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType<long>() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType<short>() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType<signed char>() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType<unsigned PY_LONG_LONG>() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType<unsigned char>() { return &PyInt_Type; } +template<> inline PyTypeObject* SbkType<unsigned int>() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType<unsigned long>() { return &PyLong_Type; } +template<> inline PyTypeObject* SbkType<unsigned short>() { return &PyInt_Type; } + +template <typename T> struct Primitive {}; + +template <typename T> +struct OnePrimitive +{ + static PyObject* toPython(const void*) { return 0; } + static PythonToCppFunc isConvertible(PyObject*) { return 0; } + static void toCpp(PyObject*, void*) {} + static SbkConverter* createConverter() + { + SbkConverter* converter = Shiboken::Conversions::createConverter(SbkType<T>(), Primitive<T>::toPython); + Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive<T>::toCpp, Primitive<T>::isConvertible); + return converter; + } +}; +template <typename T> +struct TwoPrimitive : OnePrimitive<T> +{ + static PythonToCppFunc isOtherConvertible(PyObject*) { return 0; } + static void otherToCpp(PyObject*, void*) {} + static SbkConverter* createConverter() + { + SbkConverter* converter = OnePrimitive<T>::createConverter(); + Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive<T>::otherToCpp, Primitive<T>::isOtherConvertible); + return converter; + } +}; + +// Integers -------------------------------------------------------------------------------- + +// Note: if there wasn't for the old-style classes, a simple PyNumber_Check would suffice. +#define SbkNumber_Check(X) (PyNumber_Check(X) \ + && (!PyInstance_Check(X) || PyObject_HasAttrString(X, "__trunc__"))) + +template <typename INT> +struct IntPrimitive : TwoPrimitive<INT> +{ + static PyObject* toPython(const void* cppIn) + { + return PyInt_FromLong((long)*((INT*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + double result = PyFloat_AS_DOUBLE(pyIn); + // If cast to long directly it could overflow silently. + if (OverFlowChecker<INT>::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + *((INT*)cppOut) = static_cast<INT>(result); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (PyFloat_Check(pyIn)) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + PY_LONG_LONG result = PyLong_AsLongLong(pyIn); + if (OverFlowChecker<INT>::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + *((INT*)cppOut) = static_cast<INT>(result); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } +}; +template <> struct Primitive<int> : IntPrimitive<int> {}; +template <> struct Primitive<long> : IntPrimitive<long> {}; +template <> struct Primitive<short> : IntPrimitive<short> {}; +template <> struct Primitive<unsigned short> : IntPrimitive<unsigned short> {}; + +// Unsigned Long Integers ------------------------------------------------------------------ + +template <typename LONG> +struct UnsignedLongPrimitive : IntPrimitive<LONG> +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromUnsignedLong(*((LONG*)cppIn)); + } +}; +template <> struct Primitive<unsigned int> : UnsignedLongPrimitive<unsigned int> {}; +template <> struct Primitive<unsigned long> : UnsignedLongPrimitive<unsigned long> {}; + +// Big integers ---------------------------------------------------------------------------- + +template <> +struct Primitive<PY_LONG_LONG> : OnePrimitive<PY_LONG_LONG> +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromLongLong(*((PY_LONG_LONG*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((PY_LONG_LONG*)cppOut) = (PY_LONG_LONG) PyLong_AsLongLong(pyIn); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } +}; + +template <> +struct Primitive<unsigned PY_LONG_LONG> : OnePrimitive<unsigned PY_LONG_LONG> +{ + static PyObject* toPython(const void* cppIn) + { + return PyLong_FromUnsignedLongLong(*((unsigned PY_LONG_LONG*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((unsigned PY_LONG_LONG*)cppOut) = (unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(pyIn); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } +}; + +// Floating point -------------------------------------------------------------------------- + +template <typename FLOAT> +struct FloatPrimitive : TwoPrimitive<FLOAT> +{ + static PyObject* toPython(const void* cppIn) + { + return PyFloat_FromDouble((double)*((FLOAT*)cppIn)); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((FLOAT*)cppOut) = (FLOAT) PyLong_AsLong(pyIn); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (PyInt_Check(pyIn) || PyLong_Check(pyIn)) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *((FLOAT*)cppOut) = (FLOAT) PyFloat_AsDouble(pyIn); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } +}; +template <> struct Primitive<float> : FloatPrimitive<float> {}; +template <> struct Primitive<double> : FloatPrimitive<double> {}; + +// Boolean --------------------------------------------------------------------------------- + +template <> +struct Primitive<bool> : OnePrimitive<bool> +{ + static PyObject* toPython(const void* cppIn) + { + return PyBool_FromLong(*((bool*)cppIn)); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return toCpp; + return 0; + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((bool*)cppOut) = (bool) PyInt_AS_LONG(pyIn); + } +}; + +// Characters ------------------------------------------------------------------------------ + +template <typename CHAR> +struct CharPrimitive : IntPrimitive<CHAR> +{ + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((CHAR*)cppOut) = (CHAR) PyString_AS_STRING(pyIn)[0]; + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (PyString_Check(pyIn) && PyString_Size(pyIn) == 1) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + PY_LONG_LONG result = PyLong_AsLongLong(pyIn); + if (OverFlowChecker<CHAR>::check(result)) + PyErr_SetObject(PyExc_OverflowError, 0); + *((CHAR*)cppOut) = (CHAR) result; + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (SbkNumber_Check(pyIn)) + return otherToCpp; + return 0; + } + static SbkConverter* createConverter() + { + SbkConverter* converter = IntPrimitive<CHAR>::createConverter(); + Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive<CHAR>::otherToCpp, CharPrimitive<CHAR>::isOtherConvertible); + return converter; + } + +}; +template <> struct Primitive<signed char> : CharPrimitive<signed char> {}; +template <> struct Primitive<unsigned char> : CharPrimitive<unsigned char> {}; +template <> struct Primitive<char> : CharPrimitive<char> { + using CharPrimitive<char>::toPython; + static PyObject* toPython(const void* cppIn) { + return PyString_FromFormat("%c", *((const char*)cppIn)); + } +}; + + + +// Strings --------------------------------------------------------------------------------- + +template <> +struct Primitive<const char*> : TwoPrimitive<const char*> +{ + static PyObject* toPython(const void* cppIn) + { + if (!cppIn) + Py_RETURN_NONE; + return PyString_FromString((const char*)cppIn); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((const char**)cppOut) = 0; + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (pyIn == Py_None) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *((const char**)cppOut) = (const char*) PyString_AsString(pyIn); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (PyString_Check(pyIn)) + return otherToCpp; + return 0; + } +}; + +template <> +struct Primitive<std::string> : TwoPrimitive<std::string> +{ + static PyObject* toPython(const void* cppIn) + { + return PyString_FromString(((std::string*)cppIn)->c_str()); + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + *((std::string*)cppOut) = std::string(); + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + if (pyIn == Py_None) + return toCpp; + return 0; + } + static void otherToCpp(PyObject* pyIn, void* cppOut) + { + *((std::string*)cppOut) = std::string(PyString_AsString(pyIn)); + } + static PythonToCppFunc isOtherConvertible(PyObject* pyIn) + { + if (PyString_Check(pyIn)) + return otherToCpp; + return 0; + } +}; + +// Void pointer ---------------------------------------------------------------------------- + +template <> +struct Primitive<void*> : OnePrimitive<void*> +{ + static PyObject* toPython(const void* cppIn) + { + SbkDbg() << cppIn; + if (!cppIn) + Py_RETURN_NONE; + PyObject* result = (PyObject*) cppIn; + Py_INCREF(result); + return result; + } + static void toCpp(PyObject* pyIn, void* cppOut) + { + SbkDbg() << pyIn; + *((void**)cppOut) = pyIn; + } + static PythonToCppFunc isConvertible(PyObject* pyIn) + { + return toCpp; + } +}; + #endif // SBK_CONVERTER_P_H |