diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index c410c510e6..8d15b4a2aa 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1036,6 +1036,10 @@ bool QMetaType::hasRegisteredDebugStreamOperator() const */ bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId) { + if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) { + if (moduleHelper->convert(from, fromTypeId, to, toTypeId)) + return true; + } const QMetaType::ConverterFunction * const f = customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId)); return f && (*f)(from, to); diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h index dedec4d469..9e391e6476 100644 --- a/src/corelib/kernel/qmetatype_p.h +++ b/src/corelib/kernel/qmetatype_p.h @@ -128,10 +128,31 @@ QT_WARNING_POP #undef QT_DECLARE_GUI_MODULE_TYPES_ITER #undef QT_DECLARE_WIDGETS_MODULE_TYPES_ITER +#define QMETATYPE_CONVERTER(To, From, assign_and_return) \ + case makePair(QMetaType::To, QMetaType::From): \ + if (onlyCheck) \ + return true; \ + { \ + const From &source = *static_cast(from); \ + To &result = *static_cast(to); \ + assign_and_return \ + } +#define QMETATYPE_CONVERTER_FUNCTION(To, assign_and_return) \ + { \ + To &result = *static_cast(r); \ + assign_and_return \ + } + class QMetaTypeModuleHelper { public: + static constexpr auto makePair(int from, int to) -> quint64 + { + return (quint64(from) << 32) + quint64(to); + }; + virtual QtPrivate::QMetaTypeInterface *interfaceForType(int) const = 0; + virtual bool convert(const void *, int, void *, int) const { return false; } }; namespace QtMetaTypePrivate { diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 760c4ea9b6..975a053ba0 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -89,23 +89,6 @@ QT_BEGIN_NAMESPACE -namespace { -class HandlersManager -{ - static const QVariant::Handler *Handlers[QModulesPrivate::ModulesCount]; -public: - const QVariant::Handler *operator[] (const uint typeId) const - { - return Handlers[QModulesPrivate::moduleForType(typeId)]; - } - - void registerHandler(const QModulesPrivate::Names name, const QVariant::Handler *handler) - { - Handlers[name] = handler; - } -}; -} // namespace - namespace { struct CoreTypesFilter { template @@ -377,7 +360,7 @@ static bool convert(const QVariant::Private *d, int t, void *result) Q_ASSERT(d->type().id() != t); Q_ASSERT(result); - if (d->type().id() >= QMetaType::User || t >= QMetaType::User) { + if (d->type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) { if (QMetaType::convert(constData(*d), d->type().id(), result, t)) return true; } @@ -1373,16 +1356,6 @@ static bool convert(const QVariant::Private *d, int t, void *result) return true; } -const QVariant::Handler qt_kernel_variant_handler = { - convert -}; - -static bool dummyConvert(const QVariant::Private *, int, void *) -{ Q_ASSERT_X(false, "QVariant", "Trying to convert an unknown type"); return false; } -const QVariant::Handler qt_dummy_variant_handler = { - dummyConvert, -}; - // the type of d has already been set, but other field are not set static void customConstruct(QVariant::Private *d, const void *copy) { @@ -1417,39 +1390,9 @@ static void customClear(QVariant::Private *d) } } -static bool customConvert(const QVariant::Private *d, int t, void *result) -{ - if (d->type().id() >= QMetaType::User || t >= QMetaType::User) { - if (QMetaType::convert(constData(*d), d->type().id(), result, t)) - return true; - } - - return convert(d, t, result); -} - -const QVariant::Handler qt_custom_variant_handler = { - customConvert -}; } // annonymous used to hide QVariant handlers -static HandlersManager handlerManager; - -static_assert(!QModulesPrivate::Core, "Initialization assumes that ModulesNames::Core is 0"); -const QVariant::Handler *HandlersManager::Handlers[QModulesPrivate::ModulesCount] - = { &qt_kernel_variant_handler, &qt_dummy_variant_handler, - &qt_dummy_variant_handler, &qt_custom_variant_handler }; - -Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler() -{ - return &qt_kernel_variant_handler; -} - -Q_CORE_EXPORT void QVariantPrivate::registerHandler(const int /* Modules::Names */name, const QVariant::Handler *handler) -{ - handlerManager.registerHandler(static_cast(name), handler); -} - /*! \class QVariant \inmodule QtCore @@ -2530,13 +2473,13 @@ inline T qVariantToHelper(const QVariant::Private &d) return *v_cast(&d); T ret; - if (d.type().id() >= QMetaType::User || targetType.id() >= QMetaType::User) { + if (d.type().id() >= QMetaType::LastCoreType || targetType.id() >= QMetaType::LastCoreType) { const void * const from = constData(d); if (QMetaType::convert(from, d.type().id(), &ret, targetType.id())) return ret; } - handlerManager[d.type().id()]->convert(&d, targetType.id(), &ret); + convert(&d, targetType.id(), &ret); return ret; } @@ -2954,8 +2897,7 @@ QBitArray QVariant::toBitArray() const } template -inline T qNumVariantToHelper(const QVariant::Private &d, - const HandlersManager &handlerManager, bool *ok, const T& val) +inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok, const T& val) { const uint t = qMetaTypeId(); if (ok) @@ -2965,11 +2907,11 @@ inline T qNumVariantToHelper(const QVariant::Private &d, return val; T ret = 0; - if ((d.type().id() >= QMetaType::User || t >= QMetaType::User) + if ((d.type().id() >= QMetaType::LastCoreType || t >= QMetaType::LastCoreType) && QMetaType::convert(constData(d), d.type().id(), &ret, t)) return ret; - bool success = handlerManager[d.type().id()]->convert(&d, t, &ret); + bool success = convert(&d, t, &ret); if (ok) *ok = success; return ret; @@ -2994,7 +2936,7 @@ inline T qNumVariantToHelper(const QVariant::Private &d, */ int QVariant::toInt(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.i); + return qNumVariantToHelper(d, ok, d.data.i); } /*! @@ -3016,7 +2958,7 @@ int QVariant::toInt(bool *ok) const */ uint QVariant::toUInt(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.u); + return qNumVariantToHelper(d, ok, d.data.u); } /*! @@ -3033,7 +2975,7 @@ uint QVariant::toUInt(bool *ok) const */ qlonglong QVariant::toLongLong(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.ll); + return qNumVariantToHelper(d, ok, d.data.ll); } /*! @@ -3050,7 +2992,7 @@ qlonglong QVariant::toLongLong(bool *ok) const */ qulonglong QVariant::toULongLong(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.ull); + return qNumVariantToHelper(d, ok, d.data.ull); } /*! @@ -3071,7 +3013,14 @@ bool QVariant::toBool() const return d.data.b; bool res = false; - handlerManager[d.type().id()]->convert(&d, Bool, &res); + + if (d.type().id() >= QMetaType::LastCoreType) { + const void * const from = constData(); + if (QMetaType::convert(from, d.type().id(), &res, QMetaType::Bool)) + return res; + } + + ::convert(&d, Bool, &res); return res; } @@ -3090,7 +3039,7 @@ bool QVariant::toBool() const */ double QVariant::toDouble(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.d); + return qNumVariantToHelper(d, ok, d.data.d); } /*! @@ -3109,7 +3058,7 @@ double QVariant::toDouble(bool *ok) const */ float QVariant::toFloat(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.f); + return qNumVariantToHelper(d, ok, d.data.f); } /*! @@ -3128,7 +3077,7 @@ float QVariant::toFloat(bool *ok) const */ qreal QVariant::toReal(bool *ok) const { - return qNumVariantToHelper(d, handlerManager, ok, d.data.real); + return qNumVariantToHelper(d, ok, d.data.real); } /*! @@ -3378,7 +3327,7 @@ bool QVariant::canConvert(int targetTypeId) const return true; } - if ((d.type().id() >= QMetaType::User || targetTypeId >= QMetaType::User) + if ((d.type().id() >= QMetaType::LastCoreType|| targetTypeId >= QMetaType::LastCoreType) && QMetaType::hasRegisteredConverterFunction(d.type().id(), targetTypeId)) { return true; } @@ -3608,8 +3557,14 @@ bool QVariant::convert(int targetTypeId) return true; } - int converterType = std::max(oldValue.userType(), targetTypeId); - bool isOk = handlerManager[converterType]->convert(&oldValue.d, targetTypeId, data()); + bool isOk = false; + if (oldValue.metaType().id() >= QMetaType::LastCoreType || targetTypeId >= QMetaType::LastCoreType) { + const void * const from = oldValue.constData(); + isOk = QMetaType::convert(from, oldValue.metaType().id(), data(), targetTypeId); + } + if (!isOk) + isOk = ::convert(&oldValue.d, targetTypeId, data()); + d.is_null = !isOk; return isOk; } @@ -3621,7 +3576,12 @@ bool QVariant::convert(int targetTypeId) */ bool QVariant::convert(const int type, void *ptr) const { - return handlerManager[type]->convert(&d, type, ptr); + if (d.type().id() >= QMetaType::LastCoreType || type >= QMetaType::LastCoreType) { + const void * const from = constData(); + if (QMetaType::convert(from, d.type().id(), ptr, type)) + return true; + } + return ::convert(&d, type, ptr); } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index dbe99b023e..e4bfa7c896 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -499,11 +499,6 @@ class Q_CORE_EXPORT QVariant } }; public: - typedef bool (*f_convert)(const QVariant::Private *d, int t, void *); - struct Handler { - f_convert convert; - }; - inline bool operator==(const QVariant &v) const { return equals(v); } inline bool operator!=(const QVariant &v) const diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 18fc0fbf80..f517e3b695 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -97,12 +97,6 @@ inline void v_construct(QVariant::Private *x, const T &t) } } -Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler(); - -namespace QVariantPrivate { -Q_CORE_EXPORT void registerHandler(const int /* Modules::Names */ name, const QVariant::Handler *handler); -} - QT_END_NAMESPACE #endif // QVARIANT_P_H diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index af16c49b9c..ae6def7176 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -91,8 +91,6 @@ QT_BEGIN_NAMESPACE -Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler(); - namespace { struct GuiTypesFilter { template @@ -101,161 +99,89 @@ struct GuiTypesFilter { }; }; -static bool convert(const QVariant::Private *d, int t, void *result) -{ - switch (t) { - case QMetaType::QByteArray: - if (d->type().id() == QMetaType::QColor) { - const QColor *c = v_cast(d); - *static_cast(result) = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb).toLatin1(); - return true; - } - break; - case QMetaType::QString: { - QString *str = static_cast(result); - switch (d->type().id()) { -#if QT_CONFIG(shortcut) - case QMetaType::QKeySequence: - *str = (*v_cast(d)).toString(QKeySequence::NativeText); - return true; -#endif - case QMetaType::QFont: - *str = v_cast(d)->toString(); - return true; - case QMetaType::QColor: { - const QColor *c = v_cast(d); - *str = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb); - return true; - } - default: - break; - } - break; - } - case QMetaType::QPixmap: - if (d->type().id() == QMetaType::QImage) { - *static_cast(result) = QPixmap::fromImage(*v_cast(d)); - return true; - } else if (d->type().id() == QMetaType::QBitmap) { - *static_cast(result) = *v_cast(d); - return true; - } else if (d->type().id() == QMetaType::QBrush) { - if (v_cast(d)->style() == Qt::TexturePattern) { - *static_cast(result) = v_cast(d)->texture(); - return true; - } - } - break; - case QMetaType::QImage: - if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = v_cast(d)->toImage(); - return true; - } else if (d->type().id() == QMetaType::QBitmap) { - *static_cast(result) = v_cast(d)->toImage(); - return true; - } - break; - case QMetaType::QBitmap: - if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = *v_cast(d); - return true; - } else if (d->type().id() == QMetaType::QImage) { - *static_cast(result) = QBitmap::fromImage(*v_cast(d)); - return true; - } - break; -#if QT_CONFIG(shortcut) - case QMetaType::Int: - if (d->type().id() == QMetaType::QKeySequence) { - const QKeySequence &seq = *v_cast(d); - *static_cast(result) = seq.isEmpty() ? 0 : seq[0]; - return true; - } - break; -#endif - case QMetaType::QFont: - if (d->type().id() == QMetaType::QString) { - QFont *f = static_cast(result); - f->fromString(*v_cast(d)); - return true; - } - break; - case QMetaType::QColor: - if (d->type().id() == QMetaType::QString) { - static_cast(result)->setNamedColor(*v_cast(d)); - return static_cast(result)->isValid(); - } else if (d->type().id() == QMetaType::QByteArray) { - static_cast(result)->setNamedColor(QLatin1String(*v_cast(d))); - return true; - } else if (d->type().id() == QMetaType::QBrush) { - if (v_cast(d)->style() == Qt::SolidPattern) { - *static_cast(result) = v_cast(d)->color(); - return true; - } - } - break; - case QMetaType::QBrush: - if (d->type().id() == QMetaType::QColor) { - *static_cast(result) = QBrush(*v_cast(d)); - return true; - } else if (d->type().id() == QMetaType::QPixmap) { - *static_cast(result) = QBrush(*v_cast(d)); - return true; - } - break; -#if QT_CONFIG(shortcut) - case QMetaType::QKeySequence: { - QKeySequence *seq = static_cast(result); - switch (d->type().id()) { - case QMetaType::QString: - *seq = QKeySequence(*v_cast(d)); - return true; - case QMetaType::Int: - *seq = QKeySequence(d->data.i); - return true; - default: - break; - } - break; - } -#endif -#ifndef QT_NO_ICON - case QMetaType::QIcon: { - return false; - } -#endif - default: - break; - } - return qcoreVariantHandler()->convert(d, t, result); -} - -const QVariant::Handler qt_gui_variant_handler = { - convert -}; - -#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ - QT_METATYPE_INTERFACE_INIT(RealName), static const struct : QMetaTypeModuleHelper { +#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \ + QT_METATYPE_INTERFACE_INIT(RealName), + QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { switch (type) { QT_FOR_EACH_STATIC_GUI_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE) default: return nullptr; } } +#undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES + + bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override + { + Q_ASSERT(fromTypeId != toTypeId); + + bool onlyCheck = (from == nullptr && to == nullptr); + + using Int = int; + switch (makePair(toTypeId, fromTypeId)) { + QMETATYPE_CONVERTER(QByteArray, QColor, + result = source.name(source.alpha() != 255 ? + QColor::HexArgb : QColor::HexRgb).toLatin1(); + return true; + ); + QMETATYPE_CONVERTER(QColor, QByteArray, + result.setNamedColor(QLatin1String(source)); + return result.isValid(); + ); + QMETATYPE_CONVERTER(QString, QColor, + result = source.name(source.alpha() != 255 ? + QColor::HexArgb : QColor::HexRgb); + return true; + ); + QMETATYPE_CONVERTER(QColor, QString, + result.setNamedColor(source); + return result.isValid(); + ); +#if QT_CONFIG(shortcut) + QMETATYPE_CONVERTER(QString, QKeySequence, + result = source.toString(QKeySequence::NativeText); + return true; + ); + QMETATYPE_CONVERTER(QKeySequence, QString, result = source; return true;); + QMETATYPE_CONVERTER(Int, QKeySequence, + result = source.isEmpty() ? 0 : source[0]; + return true; + ); + QMETATYPE_CONVERTER(QKeySequence, Int, result = source; return true;); +#endif + QMETATYPE_CONVERTER(QString, QFont, result = source.toString(); return true;); + QMETATYPE_CONVERTER(QFont, QString, return result.fromString(source);); + QMETATYPE_CONVERTER(QPixmap, QImage, result = QPixmap::fromImage(source); return true;); + QMETATYPE_CONVERTER(QImage, QPixmap, result = source.toImage(); return true;); + QMETATYPE_CONVERTER(QPixmap, QBitmap, result = source; return true;); + QMETATYPE_CONVERTER(QBitmap, QPixmap, result = source; return true;); + QMETATYPE_CONVERTER(QImage, QBitmap, result = source.toImage(); return true;); + QMETATYPE_CONVERTER(QBitmap, QImage, result = QBitmap::fromImage(source); return true;); + QMETATYPE_CONVERTER(QPixmap, QBrush, result = source.texture(); return true;); + QMETATYPE_CONVERTER(QBrush, QPixmap, result = source; return true;); + QMETATYPE_CONVERTER(QColor, QBrush, + if (source.style() == Qt::SolidPattern) { + result = source.color(); + return true; + } + return false; + ); + QMETATYPE_CONVERTER(QBrush, QColor, result = source; return true;); + default: + break; + } + return false; + } } qVariantGuiHelper; - -#undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES } // namespace used to hide QVariant handler extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper; void qRegisterGuiVariant() { - QVariantPrivate::registerHandler(QModulesPrivate::Gui, &qt_gui_variant_handler); qMetaTypeGuiHelper = &qVariantGuiHelper; } Q_CONSTRUCTOR_FUNCTION(qRegisterGuiVariant) diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp index 27d4d9e2fe..935a53935f 100644 --- a/src/widgets/kernel/qwidgetsvariant.cpp +++ b/src/widgets/kernel/qwidgetsvariant.cpp @@ -49,20 +49,6 @@ QT_BEGIN_NAMESPACE namespace { -static bool convert(const QVariant::Private *d, int type, void *result, bool *ok) -{ - Q_UNUSED(d); - Q_UNUSED(type); - Q_UNUSED(result); - if (ok) - *ok = false; - return false; -} - -static const QVariant::Handler widgets_handler = { - convert -}; - static const struct : QMetaTypeModuleHelper { QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override { @@ -84,7 +70,6 @@ void qRegisterWidgetsVariant() { qRegisterMetaType(); qMetaTypeWidgetsHelper = &qVariantWidgetsHelper; - QVariantPrivate::registerHandler(QModulesPrivate::Widgets, &widgets_handler); } Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant)