diff options
23 files changed, 484 insertions, 1079 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index 646c2f311..b1557af87 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -268,7 +268,6 @@ <add-conversion type="QByteArray" file="../glue/qtcore.cpp" snippet="conversion-qbytearray"/> <add-conversion type="PyFloat" check="PyFloat_CheckExact(%in)" file="../glue/qtcore.cpp" snippet="conversion-pyfloat"/> <add-conversion type="PyLong" check="PyLong_CheckExact(%in)" file="../glue/qtcore.cpp" snippet="conversion-qlonglong"/> - <add-conversion type="SbkEnumType" file="../glue/qtcore.cpp" snippet="conversion-sbkobject"/> <add-conversion type="SbkObject" file="../glue/qtcore.cpp" snippet="conversion-sbkobject"/> <add-conversion type="PyDict" check="PyDict_CheckExact(%in)" file="../glue/qtcore.cpp" snippet="conversion-pydict"/> <add-conversion type="PyList" check="PyList_Check(%in)" file="../glue/qtcore.cpp" snippet="conversion-pylist"/> diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index ddb5a9ffa..f15fb6f8a 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -145,11 +145,7 @@ else { // @snippet metatype-from-type // @snippet metatype-from-metatype-type -Shiboken::AutoDecRef intArg; -if (usingNewEnum()) - intArg.reset(PyObject_GetAttrString(%PYARG_1, "value")); -else - intArg.reset(PyObject_CallMethod(%PYARG_1, "__int__", nullptr)); +Shiboken::AutoDecRef intArg(PyObject_GetAttrString(%PYARG_1, "value")); %0 = new %TYPE(PyLong_AsLong(intArg)); // @snippet metatype-from-metatype-type @@ -1187,7 +1183,7 @@ Py_END_ALLOW_THREADS if (atexit.isNull()) { qWarning("Module atexit not found for registering __moduleShutdown"); PyErr_Clear(); - }else{ + } else { regFunc.reset(PyObject_GetAttrString(atexit, "register")); if (regFunc.isNull()) { qWarning("Function atexit.register not found for registering __moduleShutdown"); diff --git a/sources/pyside6/PySide6/glue/qtgui.cpp b/sources/pyside6/PySide6/glue/qtgui.cpp index d610933ba..38e01f24c 100644 --- a/sources/pyside6/PySide6/glue/qtgui.cpp +++ b/sources/pyside6/PySide6/glue/qtgui.cpp @@ -313,10 +313,7 @@ if (_i < 0 || _i >= %CPPSELF.count()) { return 0; } QKeyCombination item = (*%CPPSELF)[_i]; -if (usingNewEnum()) - return %CONVERTTOPYTHON[QKeyCombination](item); -auto combined = item.toCombined(); -return %CONVERTTOPYTHON[int](combined); +return %CONVERTTOPYTHON[QKeyCombination](item); // @snippet qkeysequence-getitem // @snippet qkeysequence-repr diff --git a/sources/pyside6/libpyside/pysideqflags.cpp b/sources/pyside6/libpyside/pysideqflags.cpp index 6c0314e66..bff061bca 100644 --- a/sources/pyside6/libpyside/pysideqflags.cpp +++ b/sources/pyside6/libpyside/pysideqflags.cpp @@ -6,7 +6,6 @@ #include <autodecref.h> #include <sbkenum.h> #include <sbkconverter.h> -#include <sbkenum_p.h> extern "C" { struct SbkConverter; @@ -34,9 +33,7 @@ extern "C" { long val = 0; if (PyTuple_GET_SIZE(args)) { PyObject *arg = PyTuple_GET_ITEM(args, 0); - if (Shiboken::isShibokenEnum(arg)) {// faster call - val = Shiboken::Enum::getValue(arg); - } else if (PyNumber_Check(arg)) { + if (PyNumber_Check(arg)) { Shiboken::AutoDecRef number(PyNumber_Long(arg)); val = PyLong_AsLong(number); } else { diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp index ad2a42802..fc630153c 100644 --- a/sources/pyside6/libpyside/pysidesignal.cpp +++ b/sources/pyside6/libpyside/pysidesignal.cpp @@ -927,8 +927,6 @@ QByteArray getTypeName(PyObject *obType) return QByteArrayLiteral("QVariantList"); if (type == &PyDict_Type) return QByteArrayLiteral("QVariantMap"); - if (Py_TYPE(type) == SbkEnumType_TypeF()) - return Shiboken::Enum::getCppName(type); return QByteArrayLiteral("PyObject"); } if (obType == Py_None) // Must be checked before as Shiboken::String::check accepts Py_None diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp index aa20c23d6..d0f7fb383 100644 --- a/sources/pyside6/libpyside/signalmanager.cpp +++ b/sources/pyside6/libpyside/signalmanager.cpp @@ -20,7 +20,6 @@ #include <sbkstring.h> #include <sbkstaticstrings.h> #include <sbkerrors.h> -#include <sbkenum_p.h> #include <QtCore/QByteArrayView> #include <QtCore/QDebug> diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index b5f951490..7e292f9b2 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -914,7 +914,7 @@ std::optional<AbstractMetaEnum> typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); // PYSIDE-2088, MSVC signedness issue in Qt const bool castToUnsigned = enumItem->isSigned() - && enumTypeEntry->cppType().contains(u"unsigned"); + && enumTypeEntry->cppType().contains(u"unsigned"_s); const EnumeratorList &enums = enumItem->enumerators(); for (const EnumeratorModelItem &valueItem : enums) { diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp index 8947bffd5..dd208f452 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.cpp @@ -129,6 +129,16 @@ const AbstractMetaEnumValueList &AbstractMetaEnum::values() const return d->m_enumValues; } +AbstractMetaEnumValueList AbstractMetaEnum::nonRejectedValues() const +{ + auto te = d->m_typeEntry; + AbstractMetaEnumValueList result = d->m_enumValues; + auto pred = [te](const AbstractMetaEnumValue &v) { + return te->isEnumValueRejected(v.name()); }; + result.erase(std::remove_if(result.begin(), result.end(), pred), result.end()); + return result; +} + void AbstractMetaEnum::addEnumValue(const AbstractMetaEnumValue &enumValue) { d->m_enumValues << enumValue; diff --git a/sources/shiboken6/ApiExtractor/abstractmetaenum.h b/sources/shiboken6/ApiExtractor/abstractmetaenum.h index da371b31b..b99dbee57 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetaenum.h +++ b/sources/shiboken6/ApiExtractor/abstractmetaenum.h @@ -62,6 +62,7 @@ public: ~AbstractMetaEnum(); const AbstractMetaEnumValueList &values() const; + AbstractMetaEnumValueList nonRejectedValues() const; void addEnumValue(const AbstractMetaEnumValue &enumValue); std::optional<AbstractMetaEnumValue> findEnumValue(QStringView value) const; diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 1f1c6b2fd..9f5cabd4b 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -2129,13 +2129,11 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass << classContext.wrapperName() << ").name());\n"; } - s << '\n'; - if (!typeEntry->isValue() && !typeEntry->isSmartPointer()) return; // Python to C++ copy (value, not pointer neither reference) conversion. - s << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n"; + s << "\n// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n"; sourceTypeName = metaClass->name(); targetTypeName = sourceTypeName + u"_COPY"_s; QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); @@ -3681,8 +3679,6 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, QString pyTypeName = toNative.sourceTypeName(); if (pyTypeName == u"Py_None" || pyTypeName == u"PyNone") typeCheck = u"%in == Py_None"_s; - else if (pyTypeName == u"SbkEnumType") - typeCheck = u"Shiboken::isShibokenEnum(%in)"_s; else if (pyTypeName == u"SbkObject") typeCheck = u"Shiboken::Object::checkType(%in)"_s; } @@ -5665,13 +5661,14 @@ void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloa } } -void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums, - ErrorReturn errorReturn) const +void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums) const { if (enums.isEmpty()) return; bool preambleWrittenE = false; bool preambleWrittenF = false; + bool etypeUsed = false; + for (const AbstractMetaEnum &cppEnum : std::as_const(enums)) { if (cppEnum.isPrivate()) continue; @@ -5686,12 +5683,13 @@ void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList preambleWrittenF = true; } ConfigurableScope configScope(s, cppEnum.typeEntry()); - writeEnumInitialization(s, cppEnum, errorReturn); + etypeUsed |= writeEnumInitialization(s, cppEnum); } + if (preambleWrittenE && !etypeUsed) + s << sbkUnusedVariableCast(u"EType"_s); } -void CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum &cppEnum, - ErrorReturn errorReturn) const +bool CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum &cppEnum) const { const auto enclosingClass = cppEnum.targetLangEnclosingClass(); const bool hasUpperEnclosingClass = enclosingClass @@ -5709,6 +5707,137 @@ void CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum s << (cppEnum.isAnonymous() ? "anonymous enum identified by enum value" : "enum"); s << " '" << cppEnum.name() << "'.\n"; + const bool isSigned = cppEnum.isSigned() + && !cppEnum.typeEntry()->cppType().contains(u"unsigned"_s); + const bool isAccessible = !avoidProtectedHack() || !cppEnum.isProtected(); + const auto enumValues = cppEnum.nonRejectedValues(); + + const QString prefix = cppEnum.name(); + + QString tmp; + if (const auto userType = cppEnum.typeEntry()->cppType(); !userType.isEmpty()) { + tmp = userType; + } else { + if (!isSigned && !cppEnum.underlyingType().contains(u"unsigned"_s)) + tmp += u"unsigned "_s; + tmp += cppEnum.underlyingType(); + } + const QString simpleIntType = getSimplifiedIntTypeName(tmp); + QStringList pythonEnumNames; + + // Create a list of values + const QString initializerValues = prefix + u"_InitializerValues"_s; + const QString initializerName = prefix + u"_Initializer"_s; + + // Build maybe array of enum names. + if (cppEnum.enumKind() != AnonymousEnum) { + s << "const char *" << initializerName << "[] = {\n" << indent; + for (const auto &enumValue : enumValues) { + QString name = mangleName(enumValue.name()); + s << '\"' << name << "\",\n"; + } + s << "nullptr};\n" << outdent; + } + + // Calculate formatting and record used number range. + int maxNameLen = 0; + unsigned long long valueMaskPos = 0; + long long valueMaskNeg = 0; + + for (const auto &enumValue : enumValues) { + QString name = mangleName(enumValue.name()); + + // calculate formatting + if (name.length() > maxNameLen) + maxNameLen = name.length(); + + // calculate used number range + QString numStr = enumValue.value().toString(); + if (numStr.startsWith(u"-"_s)) { + auto val = numStr.toLongLong(); + if (val < valueMaskNeg) + valueMaskNeg = val; + } else { + auto val = numStr.toULongLong(); + if (val > valueMaskPos) + valueMaskPos = val; + } + } + + // update signedness for the reduced number type. + const bool isSignedShort = valueMaskNeg < 0; + const QString usedIntType = calcMinimalIntTypeName(valueMaskPos, valueMaskNeg); + const int targetHexLen = calcUsedBits(valueMaskPos, valueMaskNeg) / 4; + + if (usedIntType != simpleIntType) + s << "// " << usedIntType << " used instead of " << simpleIntType << "\n"; + + // Calculating formatting columns + QString enumValuePrefix; + if (isAccessible) { + enumValuePrefix = usedIntType + u"("_s; + if (cppEnum.enclosingClass()) + enumValuePrefix += cppEnum.enclosingClass()->qualifiedCppName() + u"::"_s; + if (!cppEnum.isAnonymous()) + enumValuePrefix += cppEnum.name() + u"::"_s; + } + const int needSpace = enumValuePrefix.length() + 2; // braces + + // Build array of enum values + if (enumValues.isEmpty()) { + s << usedIntType << " *" << initializerValues << "{};\n"; + } else { + s << usedIntType << ' ' << initializerValues << "[] = {\n" << indent; + for (qsizetype idx = 0, last = enumValues.size() - 1; idx <= last; ++idx) { + const auto &enumValue = enumValues[idx]; + + QString valueStr = enumValue.value().toString(); + + QString enumValueText = enumValuePrefix; + if (isAccessible) + enumValueText += enumValue.name() + u')'; + else + enumValueText += valueStr; + + bool hasSign = valueStr.startsWith(u"-"_s); + if (hasSign) + valueStr.removeFirst(); + auto val = valueStr.toULongLong(); + QString valueHex = QString(u"0x%1"_s).arg(val, targetHexLen, 16, QChar(u'0')); + if (hasSign) + valueStr = u'-' + valueHex + u" -"_s + valueStr; + else + valueStr = u' ' + valueHex + u" "_s + valueStr; + if (idx != last) + enumValueText += u','; + int targetCol = needSpace + maxNameLen - enumValueText.length(); + s << enumValueText << QByteArray(targetCol, ' ') << " // " << valueStr << "\n"; + } + s << "};\n" << outdent; + } + + // Build initialization of anonymous enums + if (cppEnum.enumKind() == AnonymousEnum) { + int idx = 0; + for (const auto &enumValue : enumValues) { + const QString mangledName = mangleName(enumValue.name()); + const QString pyValue = initializerValues + u'[' + QString::number(idx++) + u']'; + if (enclosingClass || hasUpperEnclosingClass) { + s << "PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(" + << enclosingObjectVariable + << ")->tp_dict, \"" << mangledName << "\",\n" << indent + << (isSignedShort ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong") << "(" + << pyValue << "));\n" << outdent; + } else { + s << "PyModule_AddObject(module, \"" << mangledName << "\",\n" << indent + << (isSignedShort ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong") << "(" + << pyValue << "));\n" << outdent; + } + } + } + + bool etypeUsed = false; + QString enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry); if (!cppEnum.isAnonymous()) { int packageLevel = packageName().count(u'.') + 1; @@ -5725,73 +5854,14 @@ void CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum } s << "EType = Shiboken::Enum::" - << ((enclosingClass - || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum") - << '(' << enclosingObjectVariable << ',' << '\n' << indent - << '"' << cppEnum.name() << "\",\n" - << '"' << packageLevel << ':' << getClassTargetFullName(cppEnum) << "\",\n" - << '"' << cppEnum.qualifiedCppName() << '"'; - if (flags) - s << ",\nFType"; - s << ");\n" << outdent - << "if (!EType)\n" - << indent << errorReturn << outdent << '\n'; - } - - for (const AbstractMetaEnumValue &enumValue : cppEnum.values()) { - if (enumTypeEntry->isEnumValueRejected(enumValue.name())) - continue; - - QString enumValueText; - if (!avoidProtectedHack() || !cppEnum.isProtected()) { - enumValueText = cppEnum.typeEntry()->cppType(); - if (enumValueText.isEmpty()) - enumValueText = u"Shiboken::Enum::EnumValueType"_s; - enumValueText += u'('; - if (cppEnum.enclosingClass()) - enumValueText += cppEnum.enclosingClass()->qualifiedCppName() + u"::"_s; - // Fully qualify the value which is required for C++ 11 enum classes. - if (!cppEnum.isAnonymous()) - enumValueText += cppEnum.name() + u"::"_s; - enumValueText += enumValue.name(); - enumValueText += u')'; - } else { - enumValueText += enumValue.value().toString(); - } - - const QString mangledName = mangleName(enumValue.name()); - switch (cppEnum.enumKind()) { - case AnonymousEnum: - if (enclosingClass || hasUpperEnclosingClass) { - s << "{\n" << indent - << "PyObject *anonEnumItem = PyLong_FromLong(" << enumValueText << ");\n" - << "if (PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(" - << enclosingObjectVariable - << ")->tp_dict, \"" << mangledName << "\", anonEnumItem) < 0)\n" - << indent << errorReturn << outdent - << "Py_DECREF(anonEnumItem);\n" << outdent - << "}\n"; - } else { - s << "if (PyModule_AddIntConstant(module, \"" << mangledName << "\", "; - s << enumValueText << ") < 0)\n" << indent << errorReturn << outdent; - } - break; - case CEnum: - case EnumClass: - s << "if (!Shiboken::Enum::createEnumItemOld(EType,\n" << indent - << "\"" << mangledName << "\", " << enumValueText << "))\n" << errorReturn - << outdent; - break; - } - } - if (cppEnum.enumKind() != AnonymousEnum) { - s << "// PYSIDE-1735: Resolving the whole enum class at the end for API compatibility.\n" - << "EType = morphLastEnumToPython();\n" - << enumVarTypeObj << " = EType;\n"; - } else { - s << "// PYSIDE-1735: Skip an Anonymous enum class for Python coercion.\n" + << "createPythonEnum" + << '(' << enclosingObjectVariable << ",\n" << indent + << '"' << packageLevel << ':' << getClassTargetFullName(cppEnum) << "\",\n" + << initializerName << ", " << initializerValues << ");\n" << outdent << enumVarTypeObj << " = EType;\n"; + etypeUsed = true; } + if (cppEnum.typeEntry()->flags()) { s << "// PYSIDE-1735: Mapping the flags class to the same enum class.\n" << cpythonTypeNameExt(cppEnum.typeEntry()->flags()) << " =\n" @@ -5803,6 +5873,8 @@ void CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum if (cppEnum.typeEntry()->flags()) s << "/flags"; s << ".\n\n"; + + return etypeUsed; } void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass) @@ -6159,8 +6231,9 @@ void CppGenerator::writeClassRegister(TextStream &s, // Set typediscovery struct or fill the struct of another one if (needsTypeDiscoveryFunction(metaClass)) { - s << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(" << cpythonTypeName(metaClass) - << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);\n\n"; + s << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(\n" << indent + << cpythonTypeName(metaClass) + << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << outdent << "\n\n"; } AbstractMetaEnumList classEnums = metaClass->enums(); @@ -6170,7 +6243,7 @@ void CppGenerator::writeClassRegister(TextStream &s, s << "// Pass the ..._EnumFlagInfo to the class.\n" << "SbkObjectType_SetEnumFlagInfo(pyType, " << chopType(pyTypeName) << "_EnumFlagInfo);\n\n"; - writeEnumsInitialization(s, classEnums, ErrorReturn::Void); + writeEnumsInitialization(s, classEnums); if (metaClass->hasSignals()) writeSignalInitialization(s, metaClass); @@ -6997,7 +7070,7 @@ bool CppGenerator::finishGeneration() } } - writeEnumsInitialization(s, globalEnums, ErrorReturn::Default); + writeEnumsInitialization(s, globalEnums); s << "// Register primitive types converters.\n"; const PrimitiveTypeEntryCList &primitiveTypeList = primitiveTypes(); diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 9f07529d9..f88c846ed 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -448,10 +448,8 @@ private: void writeRichCompareFunction(TextStream &s, const GeneratorContext &context) const; void writeSmartPointerRichCompareFunction(TextStream &s, const GeneratorContext &context) const; - void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums, - ErrorReturn errorReturn) const; - void writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum, - ErrorReturn errorReturn) const; + void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums) const; + bool writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum) const; static void writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass); diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index fde07ef80..c9e95e2c8 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -1883,6 +1883,44 @@ QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleN return getModuleHeaderFileBaseName(moduleName) + QStringLiteral("_p.h"); } +QString ShibokenGenerator::getSimplifiedIntTypeName(const QString &name) + +{ + bool isSigned = !name.contains(u"unsigned"_s); + if (name.contains(u"long"_s)) { + if (name.contains(u"long long"_s)) + return isSigned ? u"int64_t"_s : u"uint64_t"_s; + return isSigned ? u"int32_t"_s : u"uint32_t"_s; + } + if (name.contains(u"short"_s)) + return isSigned ? u"int16_t"_s : u"uint16_t"_s; + if (name.contains(u"char"_s)) + return isSigned ? u"int8_t"_s : u"uint8_t"_s; + return isSigned ? u"int32_t"_s : u"uint32_t"_s; +} + +QString ShibokenGenerator::calcMinimalIntTypeName(uint64_t maxNumber, int64_t minNumber) +{ + // Calculate the really needed bits. + // Note: By the minimization, it depends on the real data if the result is + // signed or unsigned. The underlying type is no longer relevant. + assert(minNumber <= 0); + unsigned long long valueMask = maxNumber - minNumber; + int usedBits = (valueMask >> 32) ? 64 : (valueMask >> 16) ? 32 : (valueMask >> 8) ? 16 : 8; + return (minNumber < 0 ? u"int"_s : u"uint"_s) + QString::number(usedBits) + u"_t"_s; +} + +int ShibokenGenerator::calcUsedBits(uint64_t maxNumber, int64_t minNumber) +{ + // Calculate the really needed bits. + // Note: By the minimization, it depends on the real data if the result is + // signed or unsigned. The underlying type is no longer relevant. + assert(minNumber <= 0); + unsigned long long valueMask = maxNumber - minNumber; + int usedBits = (valueMask >> 32) ? 64 : (valueMask >> 16) ? 32 : (valueMask >> 8) ? 16 : 8; + return usedBits; +} + IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const { IncludeGroupList result; diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h index 4189753cc..12d908ddb 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.h +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h @@ -272,6 +272,13 @@ protected: static QString getModuleHeaderFileName(const QString &moduleName = QString()); static QString getPrivateModuleHeaderFileName(const QString &moduleName = QString()); + /// Turn "unsigned? long? (long|int|short|char)" into "u?int(8|16|32|64)_t"" + static QString getSimplifiedIntTypeName(const QString &typeName); + + /// Determine the minimal needed data type for a given number range. + static QString calcMinimalIntTypeName(uint64_t maxNumber, int64_t minNumber); + static int calcUsedBits(uint64_t maxNumber, int64_t minNumber); + /// Includes for header (native wrapper class) or binding source QList<IncludeGroup> classIncludes(const AbstractMetaClassCPtr &metaClass) const; diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt index 69a0af5ca..2e558a39d 100644 --- a/sources/shiboken6/libshiboken/CMakeLists.txt +++ b/sources/shiboken6/libshiboken/CMakeLists.txt @@ -70,7 +70,7 @@ sbkarrayconverter.cpp sbkarrayconverter.h sbkarrayconverter_p.h sbkcontainer.cpp sbkcontainer.h sbkconverter.cpp sbkconverter.h sbkconverter_p.h sbkcppstring.cpp sbkcppstring.h sbkcpptonumpy.h -sbkenum.cpp sbkenum.h sbkenum_p.h +sbkenum.cpp sbkenum.h sbkerrors.cpp sbkerrors.h sbkfeature_base.cpp sbkfeature_base.h sbkmodule.cpp sbkmodule.h @@ -158,7 +158,6 @@ install(FILES sbkconverter.h sbkcpptonumpy.h sbkenum.h - sbkenum_p.h sbkerrors.h sbkfeature_base.h sbkmodule.h diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index b01d01685..9e5d1b89e 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -721,9 +721,6 @@ void init() //Init private data Pep384_Init(); - if (PyType_Ready(SbkEnumType_TypeF()) < 0) - Py_FatalError("[libshiboken] Failed to initialize Shiboken.SbkEnumType metatype."); - if (PyType_Ready(SbkObjectType_TypeF()) < 0) Py_FatalError("[libshiboken] Failed to initialize Shiboken.BaseWrapperType metatype."); diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp index e3b8904a5..9616712f6 100644 --- a/sources/shiboken6/libshiboken/pep384impl.cpp +++ b/sources/shiboken6/libshiboken/pep384impl.cpp @@ -8,7 +8,6 @@ #include "basewrapper.h" #include "basewrapper_p.h" #include "sbkenum.h" -#include "sbkenum_p.h" #include "sbkconverter.h" #include "voidptr.h" diff --git a/sources/shiboken6/libshiboken/sbkconverter.h b/sources/shiboken6/libshiboken/sbkconverter.h index c4a99a818..dd8d01379 100644 --- a/sources/shiboken6/libshiboken/sbkconverter.h +++ b/sources/shiboken6/libshiboken/sbkconverter.h @@ -7,7 +7,6 @@ #include "sbkpython.h" #include "shibokenmacros.h" #include "sbkenum.h" -#include "sbkenum_p.h" #include "basewrapper_p.h" #include <limits> diff --git a/sources/shiboken6/libshiboken/sbkenum.cpp b/sources/shiboken6/libshiboken/sbkenum.cpp index 1b83e8a84..502b6c669 100644 --- a/sources/shiboken6/libshiboken/sbkenum.cpp +++ b/sources/shiboken6/libshiboken/sbkenum.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "sbkenum.h" -#include "sbkenum_p.h" #include "sbkstring.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" @@ -16,377 +15,23 @@ #include <vector> #include <sstream> -#define SbkEnumType_Check(o) (Py_TYPE(Py_TYPE(o)) == SbkEnumType_TypeF()) -using enum_func = PyObject *(*)(PyObject *, PyObject *); - using namespace Shiboken; extern "C" { -// forward -struct lastEnumCreated; - -// forward -static PyTypeObject *recordCurrentEnum(PyObject *scopeOrModule, - const char *name, - PyTypeObject *enumType, - PyTypeObject *flagsType); - struct SbkEnumType { PyTypeObject type; }; -static void cleanupEnumTypes(); - -struct SbkEnumObject -{ - PyObject_HEAD - Enum::EnumValueType ob_value; - PyObject *ob_name; -}; - -static PyTypeObject *SbkEnum_TypeF(); // forward - -static PyObject *SbkEnumObject_repr(PyObject *self) -{ - const SbkEnumObject *enumObj = reinterpret_cast<SbkEnumObject *>(self); - auto name = Py_TYPE(self)->tp_name; - if (enumObj->ob_name) { - return String::fromFormat("%s.%s", name, PyBytes_AS_STRING(enumObj->ob_name)); - } - return String::fromFormat("%s(%ld)", name, enumObj->ob_value); -} - -static PyObject *SbkEnumObject_name(PyObject *self, void *) -{ - auto *enum_self = reinterpret_cast<SbkEnumObject *>(self); - - if (enum_self->ob_name == nullptr) - Py_RETURN_NONE; - - Py_INCREF(enum_self->ob_name); - return enum_self->ob_name; -} - -static PyObject *SbkEnum_tp_new(PyTypeObject *type, PyObject *args, PyObject *) -{ - long itemValue = 0; - if (!PyArg_ParseTuple(args, "|l:__new__", &itemValue)) - return nullptr; - - if (type == SbkEnum_TypeF()) { - PyErr_Format(PyExc_TypeError, "You cannot use %s directly", type->tp_name); - return nullptr; - } - - SbkEnumObject *self = PyObject_New(SbkEnumObject, type); - if (!self) - return nullptr; - self->ob_value = itemValue; - AutoDecRef item(Enum::getEnumItemFromValue(type, itemValue)); - self->ob_name = item.object() ? SbkEnumObject_name(item, nullptr) : nullptr; - return reinterpret_cast<PyObject *>(self); -} - -static const char *SbkEnum_SignatureStrings[] = { - "Shiboken.Enum(self,itemValue:int=0)", - nullptr}; // Sentinel - -static void enum_object_dealloc(PyObject *ob) -{ - auto *self = reinterpret_cast<SbkEnumObject *>(ob); - Py_XDECREF(self->ob_name); - Sbk_object_dealloc(ob); -} - -static PyObject *_enum_op(enum_func f, PyObject *a, PyObject *b) { - PyObject *valA = a; - PyObject *valB = b; - PyObject *result = nullptr; - bool enumA = false; - bool enumB = false; - - // We are not allowing floats - if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) { - // Check if both variables are SbkEnumObject - if (SbkEnumType_Check(valA)) { - valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value); - enumA = true; - } - if (SbkEnumType_Check(valB)) { - valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value); - enumB = true; - } - } - - // Without an enum we are not supporting the operation - if (!(enumA || enumB)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - - result = f(valA, valB); - - // Decreasing the reference of the used variables a and b. - if (enumA) - Py_DECREF(valA); - if (enumB) - Py_DECREF(valB); - return result; -} - -/* Notes: - * On Py3k land we use long type when using integer numbers. However, on older - * versions of Python (version 2) we need to convert it to int type, - * respectively. - * - * Thus calling PyLong_FromLong() will result in calling PyLong_FromLong in - * Py3k. - */ -static PyObject *enum_int(PyObject *v) -{ - return PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(v)->ob_value); -} - -static PyObject *enum_and(PyObject *self, PyObject *b) -{ - return _enum_op(PyNumber_And, self, b); -} - -static PyObject *enum_or(PyObject *self, PyObject *b) -{ - return _enum_op(PyNumber_Or, self, b); -} - -static PyObject *enum_xor(PyObject *self, PyObject *b) -{ - return _enum_op(PyNumber_Xor, self, b); -} - -static int enum_bool(PyObject *v) -{ - return (reinterpret_cast<SbkEnumObject *>(v)->ob_value > 0); -} - -static PyObject *enum_add(PyObject *self, PyObject *v) -{ - return _enum_op(PyNumber_Add, self, v); -} - -static PyObject *enum_subtract(PyObject *self, PyObject *v) -{ - return _enum_op(PyNumber_Subtract, self, v); -} - -static PyObject *enum_multiply(PyObject *self, PyObject *v) -{ - return _enum_op(PyNumber_Multiply, self, v); -} - -static PyObject *enum_richcompare(PyObject *self, PyObject *other, int op) -{ - PyObject *valA = self; - PyObject *valB = other; - PyObject *result = nullptr; - bool enumA = false; - bool enumB = false; - - // We are not allowing floats - if (!PyFloat_Check(valA) && !PyFloat_Check(valB)) { - - // Check if both variables are SbkEnumObject - if (SbkEnumType_Check(valA)) { - valA = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valA)->ob_value); - enumA = true; - } - if (SbkEnumType_Check(valB)) { - valB = PyLong_FromLong(reinterpret_cast<SbkEnumObject *>(valB)->ob_value); - enumB =true; - } - } - - // Without an enum we are not supporting the operation - if (!(enumA || enumB)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - result = PyObject_RichCompare(valA, valB, op); - - // Decreasing the reference of the used variables a and b. - if (enumA) - Py_DECREF(valA); - if (enumB) - Py_DECREF(valB); - - return result; -} - -static Py_hash_t enum_hash(PyObject *pyObj) -{ - Py_hash_t val = reinterpret_cast<SbkEnumObject *>(pyObj)->ob_value; - if (val == -1) - val = -2; - return val; -} - -static PyGetSetDef SbkEnumGetSetList[] = { - {const_cast<char *>("name"), SbkEnumObject_name, nullptr, nullptr, nullptr}, - {nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel -}; - -static void SbkEnumTypeDealloc(PyObject *pyObj); -static PyTypeObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds); - -static PyType_Slot SbkEnumType_Type_slots[] = { - {Py_tp_dealloc, reinterpret_cast<void *>(SbkEnumTypeDealloc)}, - {Py_tp_base, reinterpret_cast<void *>(&PyType_Type)}, - {Py_tp_alloc, reinterpret_cast<void *>(PyType_GenericAlloc)}, - {Py_tp_new, reinterpret_cast<void *>(SbkEnumTypeTpNew)}, - {Py_tp_free, reinterpret_cast<void *>(PyObject_GC_Del)}, - {0, nullptr} -}; - -// PYSIDE-535: The tp_itemsize field is inherited and does not need to be set. -// In PyPy, it _must_ not be set, because it would have the meaning that a -// `__len__` field must be defined. Not doing so creates a hard-to-find crash. -static PyType_Spec SbkEnumType_Type_spec = { - "1:Shiboken.EnumMeta", - 0, - 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - SbkEnumType_Type_slots, -}; - -PyTypeObject *SbkEnumType_TypeF(void) -{ - static auto *type = SbkType_FromSpec(&SbkEnumType_Type_spec); - return type; -} - -static void SbkEnumTypeDealloc(PyObject *pyObj) -{ - auto *enumType = reinterpret_cast<SbkEnumType *>(pyObj); - auto *setp = PepType_SETP(enumType); - - PyObject_GC_UnTrack(pyObj); -#ifndef Py_LIMITED_API -# if PY_VERSION_HEX >= 0x030A0000 - Py_TRASHCAN_BEGIN(pyObj, 1); -# else - Py_TRASHCAN_SAFE_BEGIN(pyObj); -# endif -#endif - if (setp->converter) - Conversions::deleteConverter(setp->converter); - PepType_SETP_delete(enumType); -#ifndef Py_LIMITED_API -# if PY_VERSION_HEX >= 0x030A0000 - Py_TRASHCAN_END; -# else - Py_TRASHCAN_SAFE_END(pyObj); -# endif -#endif - if (PepRuntime_38_flag) { - // PYSIDE-939: Handling references correctly. - // This was not needed before Python 3.8 (Python issue 35810) - Py_DECREF(Py_TYPE(pyObj)); - } -} - -PyTypeObject *SbkEnumTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds) -{ - init_enum(); - return PepType_Type_tp_new(metatype, args, kwds); -} - -} // extern "C" - -/////////////////////////////////////////////////////////////// -// -// PYSIDE-15: Pickling Support for Qt Enum objects -// This works very well and fixes the issue. -// -extern "C" { - -static PyObject *enum_unpickler = nullptr; - -// Pickling: reduce the Qt Enum object -static PyObject *enum___reduce__(PyObject *obj) -{ - init_enum(); - return Py_BuildValue("O(Ni)", - enum_unpickler, - Py_BuildValue("s", Py_TYPE(obj)->tp_name), - PyLong_AS_LONG(obj)); -} - -} // extern "C" - -namespace Shiboken { namespace Enum { - -// Unpickling: rebuild the Qt Enum object -PyObject *unpickleEnum(PyObject *enum_class_name, PyObject *value) -{ - AutoDecRef parts(PyObject_CallMethod(enum_class_name, - "split", "s", ".")); - if (parts.isNull()) - return nullptr; - PyObject *top_name = PyList_GetItem(parts, 0); // borrowed ref - if (top_name == nullptr) - return nullptr; - PyObject *module = PyImport_GetModule(top_name); - if (module == nullptr) { - PyErr_Format(PyExc_ImportError, "could not import module %.200s", - String::toCString(top_name)); - return nullptr; - } - AutoDecRef cur_thing(module); - int len = PyList_Size(parts); - for (int idx = 1; idx < len; ++idx) { - PyObject *name = PyList_GetItem(parts, idx); // borrowed ref - PyObject *thing = PyObject_GetAttr(cur_thing, name); - if (thing == nullptr) { - PyErr_Format(PyExc_ImportError, "could not import Qt Enum type %.200s", - String::toCString(enum_class_name)); - return nullptr; - } - cur_thing.reset(thing); - } - PyObject *klass = cur_thing; - return PyObject_CallFunctionObjArgs(klass, value, nullptr); -} - -int enumOption{}; - -} // namespace Enum -} // namespace Shiboken - -extern "C" { - // Initialization static bool _init_enum() { AutoDecRef shibo(PyImport_ImportModule("shiboken6.Shiboken")); - auto mod = shibo.object(); - // publish Shiboken.Enum so that the signature gets initialized - if (PyObject_SetAttrString(mod, "Enum", reinterpret_cast<PyObject *>(SbkEnum_TypeF())) < 0) - return false; - if (InitSignatureStrings(SbkEnum_TypeF(), SbkEnum_SignatureStrings) < 0) - return false; - enum_unpickler = PyObject_GetAttrString(mod, "_unpickle_enum"); - if (enum_unpickler == nullptr) - return false; - return true; + return !shibo.isNull(); } -static PyMethodDef SbkEnumObject_Methods[] = { - {"__reduce__", reinterpret_cast<PyCFunction>(enum___reduce__), - METH_NOARGS, nullptr}, - {nullptr, nullptr, 0, nullptr} // Sentinel -}; - static PyObject *PyEnumModule{}; static PyObject *PyEnumMeta{}; static PyObject *PyEnum{}; @@ -433,15 +78,14 @@ void init_enum() static bool isInitialized = false; if (isInitialized) return; - if (!(isInitialized || enum_unpickler || _init_enum())) - Py_FatalError("could not load enum pickling helper function"); - Py_AtExit(cleanupEnumTypes); + if (!(isInitialized || _init_enum())) + Py_FatalError("could not init enum"); // PYSIDE-1735: Determine whether we should use the old or the new enum implementation. static PyObject *option = PySys_GetObject("pyside6_option_python_enum"); if (!option || !PyLong_Check(option)) { PyErr_Clear(); - option = PyLong_FromLong(0); + option = PyLong_FromLong(1); } int ignoreOver{}; Enum::enumOption = PyLong_AsLongAndOverflow(option, &ignoreOver); @@ -467,460 +111,6 @@ int enumIsFlag(PyObject *ob_type) return 0; } -// PYSIDE-1735: Helper function to ask what enum we are using -bool usingNewEnum() -{ - return true; -} - -} // extern "C" - -// -/////////////////////////////////////////////////////////////// - -namespace Shiboken { - -class DeclaredEnumTypes -{ -public: - struct EnumEntry - { - char *name; // full name as allocated. type->tp_name might be a substring. - PyTypeObject *type; - }; - - DeclaredEnumTypes(const DeclaredEnumTypes &) = delete; - DeclaredEnumTypes(DeclaredEnumTypes &&) = delete; - DeclaredEnumTypes &operator=(const DeclaredEnumTypes &) = delete; - DeclaredEnumTypes &operator=(DeclaredEnumTypes &&) = delete; - - DeclaredEnumTypes(); - ~DeclaredEnumTypes(); - static DeclaredEnumTypes &instance(); - void addEnumType(const EnumEntry &e) { m_enumTypes.push_back(e); } - - void cleanup(); - -private: - std::vector<EnumEntry> m_enumTypes; -}; - -namespace Enum { - -// forward -static PyObject *newItemOld(PyTypeObject *enumType, EnumValueType itemValue, - const char *itemName); - -// forward -static PyTypeObject * newTypeWithNameOld(const char *name, - const char *cppName, - PyTypeObject *numbers_fromFlag); - -bool check(PyObject *pyObj) -{ - init_enum(); - - static PyTypeObject *meta = getPyEnumMeta(); - return Py_TYPE(Py_TYPE(pyObj)) == reinterpret_cast<PyTypeObject *>(meta); -} - -PyObject *getEnumItemFromValue(PyTypeObject *enumType, EnumValueType itemValue) -{ - init_enum(); - - auto *obEnumType = reinterpret_cast<PyObject *>(enumType); - AutoDecRef val2members(PyObject_GetAttrString(obEnumType, "_value2member_map_")); - if (val2members.isNull()) { - PyErr_Clear(); - return nullptr; - } - AutoDecRef ob_value(PyLong_FromLongLong(itemValue)); - auto *result = PyDict_GetItem(val2members, ob_value); - Py_XINCREF(result); - return result; -} - -static PyTypeObject *createEnum(const char *fullName, const char *cppName, - PyTypeObject *flagsType) -{ - init_enum(); - PyTypeObject *enumType = newTypeWithNameOld(fullName, cppName, flagsType); - if (PyType_Ready(enumType) < 0) { - Py_XDECREF(enumType); - return nullptr; - } - return enumType; -} - -PyTypeObject *createGlobalEnum(PyObject *module, const char *name, const char *fullName, - const char *cppName, PyTypeObject *flagsType) -{ - PyTypeObject *enumType = createEnum(fullName, cppName, flagsType); - if (enumType && PyModule_AddObject(module, name, reinterpret_cast<PyObject *>(enumType)) < 0) { - Py_DECREF(enumType); - return nullptr; - } - flagsType = recordCurrentEnum(module, name, enumType, flagsType); - if (flagsType && PyModule_AddObject(module, PepType_GetNameStr(flagsType), - reinterpret_cast<PyObject *>(flagsType)) < 0) { - Py_DECREF(enumType); - return nullptr; - } - return enumType; -} - -PyTypeObject *createScopedEnum(PyTypeObject *scope, const char *name, const char *fullName, - const char *cppName, PyTypeObject *flagsType) -{ - PyTypeObject *enumType = createEnum(fullName, cppName, flagsType); - if (enumType && PyDict_SetItemString(scope->tp_dict, name, - reinterpret_cast<PyObject *>(enumType)) < 0) { - Py_DECREF(enumType); - return nullptr; - } - auto *obScope = reinterpret_cast<PyObject *>(scope); - flagsType = recordCurrentEnum(obScope, name, enumType, flagsType); - if (flagsType && PyDict_SetItemString(scope->tp_dict, - PepType_GetNameStr(flagsType), - reinterpret_cast<PyObject *>(flagsType)) < 0) { - Py_DECREF(enumType); - return nullptr; - } - return enumType; -} - -static PyObject *createEnumItem(PyTypeObject *enumType, const char *itemName, - EnumValueType itemValue) -{ - init_enum(); - PyObject *enumItem = newItemOld(enumType, itemValue, itemName); - if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) { - Py_DECREF(enumItem); - return nullptr; - } - return enumItem; -} - -bool createEnumItemOld(PyTypeObject *enumType, const char *itemName, EnumValueType itemValue) -{ - Shiboken::AutoDecRef enumItem(createEnumItem(enumType, itemName, itemValue)); - return !enumItem.isNull(); -} - -// This exists temporary as the old way to create an enum item. -// For the public interface, we use a new function -static PyObject *newItemOld(PyTypeObject *enumType, - EnumValueType itemValue, const char *itemName) -{ - bool newValue = true; - SbkEnumObject *enumObj; - if (!itemName) { - enumObj = reinterpret_cast<SbkEnumObject *>( - getEnumItemFromValue(enumType, itemValue)); - if (enumObj) - return reinterpret_cast<PyObject *>(enumObj); - - newValue = false; - } - - enumObj = PyObject_New(SbkEnumObject, enumType); - if (!enumObj) - return nullptr; - - enumObj->ob_name = itemName ? PyBytes_FromString(itemName) : nullptr; - enumObj->ob_value = itemValue; - - if (newValue) { - auto dict = enumType->tp_dict; // Note: 'values' is borrowed - PyObject *values = PyDict_GetItemWithError(dict, PyName::values()); - if (values == nullptr) { - if (PyErr_Occurred()) - return nullptr; - AutoDecRef new_values(values = PyDict_New()); - if (values == nullptr) - return nullptr; - if (PyDict_SetItem(dict, PyName::values(), values) < 0) - return nullptr; - } - PyDict_SetItemString(values, itemName, reinterpret_cast<PyObject *>(enumObj)); - } - - return reinterpret_cast<PyObject *>(enumObj); -} - -PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue, - const char *itemName) -{ - init_enum(); - - auto *obEnumType = reinterpret_cast<PyObject *>(enumType); - if (!itemName) - return PyObject_CallFunction(obEnumType, "L", itemValue); - - static PyObject *const _member_map_ = String::createStaticString("_member_map_"); - auto *member_map = PyDict_GetItem(enumType->tp_dict, _member_map_); - if (!(member_map && PyDict_Check(member_map))) - return nullptr; - auto *result = PyDict_GetItemString(member_map, itemName); - Py_XINCREF(result); - return result; -} - -} // namespace Shiboken -} // namespace Enum - -static PyType_Slot SbkNewEnum_slots[] = { - {Py_tp_repr, reinterpret_cast<void *>(SbkEnumObject_repr)}, - {Py_tp_str, reinterpret_cast<void *>(SbkEnumObject_repr)}, - {Py_tp_getset, reinterpret_cast<void *>(SbkEnumGetSetList)}, - {Py_tp_methods, reinterpret_cast<void *>(SbkEnumObject_Methods)}, - {Py_tp_new, reinterpret_cast<void *>(SbkEnum_tp_new)}, - {Py_nb_add, reinterpret_cast<void *>(enum_add)}, - {Py_nb_subtract, reinterpret_cast<void *>(enum_subtract)}, - {Py_nb_multiply, reinterpret_cast<void *>(enum_multiply)}, - {Py_nb_positive, reinterpret_cast<void *>(enum_int)}, - {Py_nb_bool, reinterpret_cast<void *>(enum_bool)}, - {Py_nb_and, reinterpret_cast<void *>(enum_and)}, - {Py_nb_xor, reinterpret_cast<void *>(enum_xor)}, - {Py_nb_or, reinterpret_cast<void *>(enum_or)}, - {Py_nb_int, reinterpret_cast<void *>(enum_int)}, - {Py_nb_index, reinterpret_cast<void *>(enum_int)}, - {Py_tp_richcompare, reinterpret_cast<void *>(enum_richcompare)}, - {Py_tp_hash, reinterpret_cast<void *>(enum_hash)}, - {Py_tp_dealloc, reinterpret_cast<void *>(enum_object_dealloc)}, - {0, nullptr} -}; -static PyType_Spec SbkNewEnum_spec = { - "1:Shiboken.Enum", - sizeof(SbkEnumObject), - 0, - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - SbkNewEnum_slots, -}; - -static PyTypeObject *SbkEnum_TypeF() -{ - static auto type = SbkType_FromSpecWithMeta(&SbkNewEnum_spec, SbkEnumType_TypeF()); - return type; -} - -namespace Shiboken { namespace Enum { - -static void -copyNumberMethods(PyTypeObject *flagsType, - PyType_Slot number_slots[], - int *pidx) -{ - int idx = *pidx; -#define PUT_SLOT(name) \ - number_slots[idx].slot = (name); \ - number_slots[idx].pfunc = PyType_GetSlot(flagsType, (name)); \ - ++idx; - - PUT_SLOT(Py_nb_absolute); - PUT_SLOT(Py_nb_add); - PUT_SLOT(Py_nb_and); - PUT_SLOT(Py_nb_bool); - PUT_SLOT(Py_nb_divmod); - PUT_SLOT(Py_nb_float); - PUT_SLOT(Py_nb_floor_divide); - PUT_SLOT(Py_nb_index); - PUT_SLOT(Py_nb_inplace_add); - PUT_SLOT(Py_nb_inplace_and); - PUT_SLOT(Py_nb_inplace_floor_divide); - PUT_SLOT(Py_nb_inplace_lshift); - PUT_SLOT(Py_nb_inplace_multiply); - PUT_SLOT(Py_nb_inplace_or); - PUT_SLOT(Py_nb_inplace_power); - PUT_SLOT(Py_nb_inplace_remainder); - PUT_SLOT(Py_nb_inplace_rshift); - PUT_SLOT(Py_nb_inplace_subtract); - PUT_SLOT(Py_nb_inplace_true_divide); - PUT_SLOT(Py_nb_inplace_xor); - PUT_SLOT(Py_nb_int); - PUT_SLOT(Py_nb_invert); - PUT_SLOT(Py_nb_lshift); - PUT_SLOT(Py_nb_multiply); - PUT_SLOT(Py_nb_negative); - PUT_SLOT(Py_nb_or); - PUT_SLOT(Py_nb_positive); - PUT_SLOT(Py_nb_power); - PUT_SLOT(Py_nb_remainder); - PUT_SLOT(Py_nb_rshift); - PUT_SLOT(Py_nb_subtract); - PUT_SLOT(Py_nb_true_divide); - PUT_SLOT(Py_nb_xor); -#undef PUT_SLOT - *pidx = idx; -} - -static PyTypeObject * newTypeWithNameOld(const char *name, - const char *cppName, - PyTypeObject *numbers_fromFlag) -{ - // Careful: SbkType_FromSpec does not allocate the string. - PyType_Slot newslots[99] = {}; // enough but not too big for the stack - PyType_Spec newspec; - DeclaredEnumTypes::EnumEntry entry{strdup(name), nullptr}; - newspec.name = entry.name; // Note that SbkType_FromSpec might use a substring. - newspec.basicsize = SbkNewEnum_spec.basicsize; - newspec.itemsize = SbkNewEnum_spec.itemsize; - newspec.flags = SbkNewEnum_spec.flags; - // we must append all the number methods, so rebuild everything: - int idx = 0; - while (SbkNewEnum_slots[idx].slot) { - newslots[idx].slot = SbkNewEnum_slots[idx].slot; - newslots[idx].pfunc = SbkNewEnum_slots[idx].pfunc; - ++idx; - } - if (numbers_fromFlag) - copyNumberMethods(numbers_fromFlag, newslots, &idx); - newspec.slots = newslots; - AutoDecRef bases(PyTuple_New(1)); - static auto basetype = reinterpret_cast<PyObject *>(SbkEnum_TypeF()); - Py_INCREF(basetype); - PyTuple_SetItem(bases, 0, basetype); - auto *type = SbkType_FromSpecBasesMeta(&newspec, bases, SbkEnumType_TypeF()); - entry.type = type; - - auto *enumType = reinterpret_cast<SbkEnumType *>(type); - auto *setp = PepType_SETP(enumType); - setp->cppName = cppName; - DeclaredEnumTypes::instance().addEnumType(entry); - return entry.type; -} - -// PySIDE-1735: This function is in the API and should be removed in 6.4 . -// Python enums are created differently. -PyTypeObject *newTypeWithName([[maybe_unused]] const char *name, - [[maybe_unused]] const char *cppName, - [[maybe_unused]] PyTypeObject *numbers_fromFlag) -{ - // old enums are gone, remove completely? - PyErr_Format(PyExc_RuntimeError, "function `%s` can no longer be used because old " - "Enums are no longer supported", __FUNCTION__); - return nullptr; -} - -const char *getCppName(PyTypeObject *enumType) -{ - assert(Py_TYPE(enumType) == SbkEnumType_TypeF()); - auto *type = reinterpret_cast<SbkEnumType *>(enumType); - auto *setp = PepType_SETP(type); - return setp->cppName; -} - -EnumValueType getValue(PyObject *enumItem) -{ - init_enum(); - - assert(Enum::check(enumItem)); - - AutoDecRef pyValue(PyObject_GetAttrString(enumItem, "value")); - return PyLong_AsLongLong(pyValue); -} - -void setTypeConverter(PyTypeObject *type, SbkConverter *converter, bool isFlag) -{ - if (isFlag) { - auto *flagsType = reinterpret_cast<PySideQFlagsType *>(type); - PepType_PFTP(flagsType)->converter = converter; - } - else { - auto *enumType = reinterpret_cast<SbkEnumType *>(type); - PepType_SETP(enumType)->converter = converter; - } -} - -} // namespace Enum - -DeclaredEnumTypes &DeclaredEnumTypes::instance() -{ - static DeclaredEnumTypes me; - return me; -} - -DeclaredEnumTypes::DeclaredEnumTypes() = default; - -DeclaredEnumTypes::~DeclaredEnumTypes() -{ - cleanup(); -} - -void DeclaredEnumTypes::cleanup() -{ - static bool was_called = false; - if (was_called) - return; - - for (const auto &e : m_enumTypes) { - std::free(e.name); - } - m_enumTypes.clear(); - was_called = true; -} - -} // namespace Shiboken - -static void cleanupEnumTypes() -{ - DeclaredEnumTypes::instance().cleanup(); -} - -/////////////////////////////////////////////////////////////////////// -// -// PYSIDE-1735: Re-implementation of Enums using Python -// ==================================================== -// -// This is a very simple, first implementation of a replacement -// for the Qt-like Enums using the Python Enum module. -// -// The basic idea: -// --------------- -// * We create the Enums as always -// * After creation of each enum, a special function is called that -// * grabs the last generated enum -// * reads all Enum items -// * generates a class statement for the Python Enum -// * creates a new Python Enum class -// * replaces the already inserted Enum with the new one. -// -// There are lots of ways to optimize that. Will be added later. -// -extern "C" { - -struct lastEnumCreated { - PyObject *scopeOrModule; - const char *name; - PyTypeObject *enumType; - PyTypeObject *flagsType; -}; - -static lastEnumCreated lec{}; - -static PyTypeObject *recordCurrentEnum(PyObject *scopeOrModule, - const char *name, - PyTypeObject *enumType, - PyTypeObject *flagsType) -{ - lec.scopeOrModule = scopeOrModule; - lec.name = name; - lec.enumType = enumType; - lec.flagsType = flagsType; - - // We return nullptr as flagsType to disable flag creation. - return nullptr; -} - -static bool is_old_version() -{ - auto *version = PySys_GetObject("version_info"); - auto *major = PyTuple_GetItem(version, 0); - auto *minor = PyTuple_GetItem(version, 1); - auto number = PyLong_AsLong(major) * 1000 + PyLong_AsLong(minor); - return number <= 3008; -} - /////////////////////////////////////////////////////////////////////// // // Support for Missing Values @@ -942,6 +132,7 @@ static bool is_old_version() // We create each constant only once and keep the result in a dict // "_sbk_missing_". This is similar to a competitor's "_sip_missing_". // + static PyObject *missing_func(PyObject * /* self */ , PyObject *args) { // In order to relax matters to be more compatible with C++, we need @@ -1017,16 +208,100 @@ static PyObject *create_missing_func(PyObject *klass) // //////////////////////////////////////////////////////////////////////// -PyTypeObject *morphLastEnumToPython() +} // extern "C" + +namespace Shiboken { + +namespace Enum { + +int enumOption{}; + +bool check(PyObject *pyObj) +{ + init_enum(); + + static PyTypeObject *meta = getPyEnumMeta(); + return Py_TYPE(Py_TYPE(pyObj)) == reinterpret_cast<PyTypeObject *>(meta); +} + +PyObject *getEnumItemFromValue(PyTypeObject *enumType, EnumValueType itemValue) +{ + init_enum(); + + auto *obEnumType = reinterpret_cast<PyObject *>(enumType); + AutoDecRef val2members(PyObject_GetAttrString(obEnumType, "_value2member_map_")); + if (val2members.isNull()) { + PyErr_Clear(); + return nullptr; + } + AutoDecRef ob_value(PyLong_FromLongLong(itemValue)); + auto *result = PyDict_GetItem(val2members, ob_value); + Py_XINCREF(result); + return result; +} + +PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue, + const char *itemName) +{ + init_enum(); + + auto *obEnumType = reinterpret_cast<PyObject *>(enumType); + if (!itemName) + return PyObject_CallFunction(obEnumType, "L", itemValue); + + static PyObject *const _member_map_ = String::createStaticString("_member_map_"); + auto *member_map = PyDict_GetItem(enumType->tp_dict, _member_map_); + if (!(member_map && PyDict_Check(member_map))) + return nullptr; + auto *result = PyDict_GetItemString(member_map, itemName); + Py_XINCREF(result); + return result; +} + +EnumValueType getValue(PyObject *enumItem) +{ + init_enum(); + + assert(Enum::check(enumItem)); + + AutoDecRef pyValue(PyObject_GetAttrString(enumItem, "value")); + return PyLong_AsLongLong(pyValue); +} + +void setTypeConverter(PyTypeObject *type, SbkConverter *converter, bool isFlag) +{ + if (isFlag) { + auto *flagsType = reinterpret_cast<PySideQFlagsType *>(type); + PepType_PFTP(flagsType)->converter = converter; + } + else { + auto *enumType = reinterpret_cast<SbkEnumType *>(type); + PepType_SETP(enumType)->converter = converter; + } +} + +static PyTypeObject *createEnumForPython(PyObject *scopeOrModule, + const char *fullName, + PyObject *pyEnumItems) { - /// The Python Enum internal structure is way too complicated. - /// It is much easier to generate Python code and execute it. + const char *colon = strchr(fullName, ':'); + assert(colon); + int package_level = atoi(fullName); + const char *mod = colon + 1; - // Pick up the last generated Enum and convert it into a PyEnum - auto *enumType = lec.enumType; - // This is temporary; SbkEnumType will be removed, soon. + const char *qual = mod; + for (int idx = package_level; idx > 0; --idx) { + const char *dot = strchr(qual, '.'); + if (!dot) + break; + qual = dot + 1; + } + int mlen = qual - mod - 1; + AutoDecRef module(Shiboken::String::fromCString(mod, mlen)); + AutoDecRef qualname(Shiboken::String::fromCString(qual)); + const char *dot = strrchr(qual, '.'); + AutoDecRef name(Shiboken::String::fromCString(dot ? dot + 1 : qual)); - auto *scopeOrModule = lec.scopeOrModule; static PyObject *enumName = String::createStaticString("IntEnum"); if (PyType_Check(scopeOrModule)) { // For global objects, we have no good solution, yet where to put the int info. @@ -1034,15 +309,9 @@ PyTypeObject *morphLastEnumToPython() auto *sotp = PepType_SOTP(type); if (!sotp->enumFlagsDict) initEnumFlagsDict(type); - enumName = PyDict_GetItem(sotp->enumTypeDict, String::fromCString(lec.name)); + enumName = PyDict_GetItem(sotp->enumTypeDict, name); } - PyObject *key, *value; - Py_ssize_t pos = 0; - PyObject *values = PyDict_GetItem(enumType->tp_dict, PyName::values()); - if (!values) - return nullptr; - AutoDecRef PyEnumType(PyObject_GetAttr(PyEnumModule, enumName)); assert(PyEnumType.object()); bool isFlag = PyObject_IsSubclass(PyEnumType, PyFlag); @@ -1055,24 +324,13 @@ PyTypeObject *morphLastEnumToPython() PyEnumType.reset(surrogate); } - // Walk the values dict and create a Python enum type. - AutoDecRef name(PyUnicode_FromString(lec.name)); - AutoDecRef args(PyList_New(0)); + // Walk the enumItemStrings and create a Python enum type. auto *pyName = name.object(); - auto *pyArgs = args.object(); - while (PyDict_Next(values, &pos, &key, &value)) { - auto *key_value = PyTuple_New(2); - PyTuple_SET_ITEM(key_value, 0, key); - Py_INCREF(key); - auto *obj = reinterpret_cast<SbkEnumObject *>(value); - auto *num = PyLong_FromLongLong(obj->ob_value); - PyTuple_SET_ITEM(key_value, 1, num); - PyList_Append(pyArgs, key_value); - } + // We now create the new type. Since Python 3.11, we need to pass in // `boundary=KEEP` because the default STRICT crashes on us. // See QDir.Filter.Drives | QDir.Filter.Files - AutoDecRef callArgs(Py_BuildValue("(OO)", pyName, pyArgs)); + AutoDecRef callArgs(Py_BuildValue("(OO)", pyName, pyEnumItems)); AutoDecRef callDict(PyDict_New()); static PyObject *boundary = String::createStaticString("boundary"); if (PyFlag_KEEP) @@ -1091,31 +349,111 @@ PyTypeObject *morphLastEnumToPython() } auto *newType = reinterpret_cast<PyTypeObject *>(obNewType); - auto *obEnumType = reinterpret_cast<PyObject *>(enumType); - AutoDecRef qual_name(PyObject_GetAttr(obEnumType, PyMagicName::qualname())); - PyObject_SetAttr(obNewType, PyMagicName::qualname(), qual_name); - AutoDecRef module(PyObject_GetAttr(obEnumType, PyMagicName::module())); + PyObject_SetAttr(obNewType, PyMagicName::qualname(), qualname); PyObject_SetAttr(obNewType, PyMagicName::module(), module); // See if we should re-introduce shortcuts in the enclosing object. const bool useGlobalShortcut = (Enum::enumOption & Enum::ENOPT_GLOBAL_SHORTCUT) != 0; const bool useScopedShortcut = (Enum::enumOption & Enum::ENOPT_SCOPED_SHORTCUT) != 0; if (useGlobalShortcut || useScopedShortcut) { + // We have to use the iterator protokol because the values dict is a mappingproxy. + AutoDecRef values(PyObject_GetAttr(obNewType, PyMagicName::members())); + AutoDecRef mapIterator(PyObject_GetIter(values)); + AutoDecRef mapKey{}; bool isModule = PyModule_Check(scopeOrModule); - pos = 0; - while (PyDict_Next(values, &pos, &key, &value)) { - AutoDecRef entry(PyObject_GetAttr(obNewType, key)); - if ((useGlobalShortcut && isModule) || (useScopedShortcut && !isModule)) - if (PyObject_SetAttr(scopeOrModule, key, entry) < 0) + while ((mapKey.reset(PyIter_Next(mapIterator))), mapKey.object()) { + if ((useGlobalShortcut && isModule) || (useScopedShortcut && !isModule)) { + AutoDecRef value(PyObject_GetItem(values, mapKey)); + if (PyObject_SetAttr(scopeOrModule, mapKey, value) < 0) return nullptr; + } } } - // PYSIDE-1735: Old Python versions can't stand the early enum deallocation. - static bool old_python_version = is_old_version(); - if (old_python_version) - Py_INCREF(obEnumType); return newType; } -} // extern "C" +template <typename IntT> +static PyObject *toPyObject(IntT v) +{ + if constexpr (sizeof(IntT) == 8) { + if constexpr (std::is_unsigned_v<IntT>) + return PyLong_FromUnsignedLongLong(v); + return PyLong_FromLongLong(v); + } + if constexpr (std::is_unsigned_v<IntT>) + return PyLong_FromUnsignedLong(v); + return PyLong_FromLong(v); +} + +template <typename IntT> +static PyTypeObject *createPythonEnumHelper(PyObject *module, + const char *fullName, const char *enumItemStrings[], IntT enumValues[]) +{ + AutoDecRef args(PyList_New(0)); + auto *pyEnumItems = args.object(); + for (size_t idx = 0; enumItemStrings[idx] != nullptr; ++idx) { + const char *kv = enumItemStrings[idx]; + auto *key = PyUnicode_FromString(kv); + auto *value = toPyObject(enumValues[idx]); + auto *key_value = PyTuple_New(2); + PyTuple_SET_ITEM(key_value, 0, key); + PyTuple_SET_ITEM(key_value, 1, value); + PyList_Append(pyEnumItems, key_value); + } + return createEnumForPython(module, fullName, pyEnumItems); +} + +// Now we have to concretize these functions explicitly, +// otherwise templates will not work across modules. + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int64_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint64_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int32_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint32_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int16_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint16_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int8_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint8_t enumValues[]) +{ + return createPythonEnumHelper(module, fullName, enumItemStrings, enumValues); +} + +} // namespace Enum +} // namespace Shiboken diff --git a/sources/shiboken6/libshiboken/sbkenum.h b/sources/shiboken6/libshiboken/sbkenum.h index b14e6dd42..4f21d3338 100644 --- a/sources/shiboken6/libshiboken/sbkenum.h +++ b/sources/shiboken6/libshiboken/sbkenum.h @@ -15,71 +15,89 @@ LIBSHIBOKEN_API bool PyEnumMeta_Check(PyObject *ob); /// exposed for the signature module LIBSHIBOKEN_API void init_enum(); -extern LIBSHIBOKEN_API PyTypeObject *SbkEnumType_TypeF(void); struct SbkConverter; struct SbkEnumType; -struct SbkEnumTypePrivate; -} // extern "C" - -namespace Shiboken +struct SbkEnumTypePrivate { + SbkConverter *converter; +}; + +/// PYSIDE-1735: Pass on the Python enum/flag information. +LIBSHIBOKEN_API void initEnumFlagsDict(PyTypeObject *type); + +/// PYSIDE-1735: Make sure that we can import the Python enum implementation. +LIBSHIBOKEN_API PyTypeObject *getPyEnumMeta(); +/// PYSIDE-1735: Helper function supporting QEnum +LIBSHIBOKEN_API int enumIsFlag(PyObject *ob_enum); -inline bool isShibokenEnum(PyObject *pyObj) -{ - return Py_TYPE(Py_TYPE(pyObj)) == SbkEnumType_TypeF(); } -namespace Enum +namespace Shiboken { namespace Enum { + +enum : int { + ENOPT_OLD_ENUM = 0x00, // PySide 6.6: no longer supported + ENOPT_NEW_ENUM = 0x01, + ENOPT_INHERIT_INT = 0x02, + ENOPT_GLOBAL_SHORTCUT = 0x04, + ENOPT_SCOPED_SHORTCUT = 0x08, + ENOPT_NO_FAKESHORTCUT = 0x10, + ENOPT_NO_FAKERENAMES = 0x20, + ENOPT_NO_ZERODEFAULT = 0x40, + ENOPT_NO_MISSING = 0x80, +}; + +LIBSHIBOKEN_API extern int enumOption; + +using EnumValueType = long long; + +LIBSHIBOKEN_API bool check(PyObject *obj); + +LIBSHIBOKEN_API PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue, + const char *itemName = nullptr); + +LIBSHIBOKEN_API EnumValueType getValue(PyObject *enumItem); +LIBSHIBOKEN_API PyObject *getEnumItemFromValue(PyTypeObject *enumType, + EnumValueType itemValue); + +/// Sets the enum/flag's type converter. +LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *type, SbkConverter *converter, bool isFlag); + +/// Creating Python enums for different types. +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int64_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint64_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int32_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint32_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int16_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint16_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], int8_t enumValues[]); + +LIBSHIBOKEN_API PyTypeObject *createPythonEnum(PyObject *module, + const char *fullName, const char *enumItemStrings[], uint8_t enumValues[]); + +/// This template removes duplication by inlining necessary type casts. +template <typename IntT> +inline PyTypeObject *createPythonEnum(PyTypeObject *scope, + const char *fullName, const char *enumItemStrings[], IntT enumValues[]) { - using EnumValueType = long long; - - LIBSHIBOKEN_API bool check(PyObject *obj); - /** - * Creates a new enum type (and its flags type, if any is given) - * and registers it to Python and adds it to \p module. - * \param module Module to where the new enum type will be added. - * \param name Name of the enum. - * \param fullName Name of the enum that includes all scope information (e.g.: "module.Enum"). - * \param cppName Full qualified C++ name of the enum. - * \param flagsType Optional Python type for the flags associated with the enum. - * \return The new enum type or NULL if it fails. - */ - LIBSHIBOKEN_API PyTypeObject *createGlobalEnum(PyObject *module, - const char *name, - const char *fullName, - const char *cppName, - PyTypeObject *flagsType = nullptr); - /// This function does the same as createGlobalEnum, but adds the enum to a Shiboken type or namespace. - LIBSHIBOKEN_API PyTypeObject *createScopedEnum(PyTypeObject *scope, - const char *name, - const char *fullName, - const char *cppName, - PyTypeObject *flagsType = nullptr); - - /// Creates a new enum item for a given enum type. - LIBSHIBOKEN_API bool createEnumItemOld(PyTypeObject *enumType, - const char *itemName, - EnumValueType itemValue); - - LIBSHIBOKEN_API PyObject *newItem(PyTypeObject *enumType, EnumValueType itemValue, - const char *itemName = nullptr); - - LIBSHIBOKEN_API PyTypeObject *newTypeWithName(const char *name, const char *cppName, - PyTypeObject *numbers_fromFlag=nullptr); - LIBSHIBOKEN_API const char *getCppName(PyTypeObject *type); - LIBSHIBOKEN_API PyObject *getCppNameNew(PyTypeObject *type); - - LIBSHIBOKEN_API EnumValueType getValue(PyObject *enumItem); - LIBSHIBOKEN_API PyObject *getEnumItemFromValue(PyTypeObject *enumType, - EnumValueType itemValue); - - /// Sets the enum/flag's type converter. - LIBSHIBOKEN_API void setTypeConverter(PyTypeObject *type, SbkConverter *converter, bool isFlag); - - LIBSHIBOKEN_API PyObject *unpickleEnum(PyObject *, PyObject *); + auto *obScope = reinterpret_cast<PyObject *>(scope); + return createPythonEnum(obScope, fullName, enumItemStrings, enumValues); } +} // namespace Enum } // namespace Shiboken #endif // SKB_PYENUM_H diff --git a/sources/shiboken6/libshiboken/sbkenum_p.h b/sources/shiboken6/libshiboken/sbkenum_p.h deleted file mode 100644 index 3e3640b93..000000000 --- a/sources/shiboken6/libshiboken/sbkenum_p.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2021 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#ifndef SBKENUM_P_H -#define SBKENUM_P_H - -#include "sbkpython.h" -#include "shibokenmacros.h" - -struct SbkEnumTypePrivate -{ - SbkConverter *converter; - const char *cppName; -}; - -extern "C" { - -/// PYSIDE-1735: Pass on the Python enum/flag information. -LIBSHIBOKEN_API void initEnumFlagsDict(PyTypeObject *type); - -/// PYSIDE-1735: Patching the Enum / Flags implementation. Remove in 6.4 -LIBSHIBOKEN_API PyTypeObject *morphLastEnumToPython(); - -/// PYSIDE-1735: Make sure that we can import the Python enum implementation. -LIBSHIBOKEN_API PyTypeObject *getPyEnumMeta(); -/// PYSIDE-1735: Helper function supporting QEnum -LIBSHIBOKEN_API int enumIsFlag(PyObject *ob_enum); -/// PYSIDE-1735: Helper function to ask what enum we are using -LIBSHIBOKEN_API bool usingNewEnum(); - -} - -namespace Shiboken { namespace Enum { - -enum : int { - ENOPT_OLD_ENUM = 0x00, // no longer supported - ENOPT_NEW_ENUM = 0x01, - ENOPT_INHERIT_INT = 0x02, - ENOPT_GLOBAL_SHORTCUT = 0x04, - ENOPT_SCOPED_SHORTCUT = 0x08, - ENOPT_NO_FAKESHORTCUT = 0x10, - ENOPT_NO_FAKERENAMES = 0x20, - ENOPT_NO_ZERODEFAULT = 0x40, - ENOPT_NO_MISSING = 0x80, -}; - -LIBSHIBOKEN_API extern int enumOption; - -}} - -#endif // SBKENUM_P_H diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp index 1242cbda4..fb2fb95aa 100644 --- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp +++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp @@ -4,7 +4,7 @@ #include "basewrapper.h" #include "basewrapper_p.h" #include "autodecref.h" -#include "sbkenum_p.h" +#include "sbkenum.h" #include "sbkstring.h" #include "sbkstaticstrings.h" #include "sbkstaticstrings_p.h" diff --git a/sources/shiboken6/libshiboken/shiboken.h b/sources/shiboken6/libshiboken/shiboken.h index 13a15e1f4..6c0ecbe30 100644 --- a/sources/shiboken6/libshiboken/shiboken.h +++ b/sources/shiboken6/libshiboken/shiboken.h @@ -14,7 +14,6 @@ #include "sbkarrayconverter.h" #include "sbkconverter.h" #include "sbkenum.h" -#include "sbkenum_p.h" // PYSIDE-1735: This is during the migration, only. #include "sbkerrors.h" #include "sbkmodule.h" #include "sbkstring.h" diff --git a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml index 81919d6c3..de5003d5b 100644 --- a/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml +++ b/sources/shiboken6/shibokenmodule/typesystem_shiboken.xml @@ -114,12 +114,6 @@ </inject-code> </add-function> - <add-function signature="_unpickle_enum(PyObject*, PyObject*)" return-type="PyObject*"> - <inject-code> - %PYARG_0 = Shiboken::Enum::unpickleEnum(%1, %2); - </inject-code> - </add-function> - <extra-includes> <include file-name="sbkversion.h" location="local"/> <include file-name="voidptr.h" location="local"/> |
