Use QMetaTypeModuleHelper as the interface to do type conversions

Move the type conversions from QVariant::Helper to QMetaType. Only do
this for Qt Gui in a first step.

This makes it possible to completely remove the Handler struct in
QVariant, and now allows QMetaType to also convert Gui types.

Moving the conversion of Core types into QMetaType will require
further work.

Change-Id: I061f789deca1b595d92bb29227eb54b8e71a3ee3
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Lars Knoll 2020-07-12 12:19:34 +02:00
parent a701b0ed30
commit 73fd7f2efc
7 changed files with 127 additions and 242 deletions

View File

@ -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);

View File

@ -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<const From *>(from); \
To &result = *static_cast<To *>(to); \
assign_and_return \
}
#define QMETATYPE_CONVERTER_FUNCTION(To, assign_and_return) \
{ \
To &result = *static_cast<To *>(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 {

View File

@ -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<typename T>
@ -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<QModulesPrivate::Names>(name), handler);
}
/*!
\class QVariant
\inmodule QtCore
@ -2530,13 +2473,13 @@ inline T qVariantToHelper(const QVariant::Private &d)
return *v_cast<T>(&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 <typename T>
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<T>();
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<int>(d, handlerManager, ok, d.data.i);
return qNumVariantToHelper<int>(d, ok, d.data.i);
}
/*!
@ -3016,7 +2958,7 @@ int QVariant::toInt(bool *ok) const
*/
uint QVariant::toUInt(bool *ok) const
{
return qNumVariantToHelper<uint>(d, handlerManager, ok, d.data.u);
return qNumVariantToHelper<uint>(d, ok, d.data.u);
}
/*!
@ -3033,7 +2975,7 @@ uint QVariant::toUInt(bool *ok) const
*/
qlonglong QVariant::toLongLong(bool *ok) const
{
return qNumVariantToHelper<qlonglong>(d, handlerManager, ok, d.data.ll);
return qNumVariantToHelper<qlonglong>(d, ok, d.data.ll);
}
/*!
@ -3050,7 +2992,7 @@ qlonglong QVariant::toLongLong(bool *ok) const
*/
qulonglong QVariant::toULongLong(bool *ok) const
{
return qNumVariantToHelper<qulonglong>(d, handlerManager, ok, d.data.ull);
return qNumVariantToHelper<qulonglong>(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<double>(d, handlerManager, ok, d.data.d);
return qNumVariantToHelper<double>(d, ok, d.data.d);
}
/*!
@ -3109,7 +3058,7 @@ double QVariant::toDouble(bool *ok) const
*/
float QVariant::toFloat(bool *ok) const
{
return qNumVariantToHelper<float>(d, handlerManager, ok, d.data.f);
return qNumVariantToHelper<float>(d, ok, d.data.f);
}
/*!
@ -3128,7 +3077,7 @@ float QVariant::toFloat(bool *ok) const
*/
qreal QVariant::toReal(bool *ok) const
{
return qNumVariantToHelper<qreal>(d, handlerManager, ok, d.data.real);
return qNumVariantToHelper<qreal>(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);
}

View File

@ -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

View File

@ -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

View File

@ -91,8 +91,6 @@
QT_BEGIN_NAMESPACE
Q_CORE_EXPORT const QVariant::Handler *qcoreVariantHandler();
namespace {
struct GuiTypesFilter {
template<typename T>
@ -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<QColor>(d);
*static_cast<QByteArray *>(result) = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb).toLatin1();
return true;
}
break;
case QMetaType::QString: {
QString *str = static_cast<QString *>(result);
switch (d->type().id()) {
#if QT_CONFIG(shortcut)
case QMetaType::QKeySequence:
*str = (*v_cast<QKeySequence>(d)).toString(QKeySequence::NativeText);
return true;
#endif
case QMetaType::QFont:
*str = v_cast<QFont>(d)->toString();
return true;
case QMetaType::QColor: {
const QColor *c = v_cast<QColor>(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<QPixmap *>(result) = QPixmap::fromImage(*v_cast<QImage>(d));
return true;
} else if (d->type().id() == QMetaType::QBitmap) {
*static_cast<QPixmap *>(result) = *v_cast<QBitmap>(d);
return true;
} else if (d->type().id() == QMetaType::QBrush) {
if (v_cast<QBrush>(d)->style() == Qt::TexturePattern) {
*static_cast<QPixmap *>(result) = v_cast<QBrush>(d)->texture();
return true;
}
}
break;
case QMetaType::QImage:
if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QImage *>(result) = v_cast<QPixmap>(d)->toImage();
return true;
} else if (d->type().id() == QMetaType::QBitmap) {
*static_cast<QImage *>(result) = v_cast<QBitmap>(d)->toImage();
return true;
}
break;
case QMetaType::QBitmap:
if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QBitmap *>(result) = *v_cast<QPixmap>(d);
return true;
} else if (d->type().id() == QMetaType::QImage) {
*static_cast<QBitmap *>(result) = QBitmap::fromImage(*v_cast<QImage>(d));
return true;
}
break;
#if QT_CONFIG(shortcut)
case QMetaType::Int:
if (d->type().id() == QMetaType::QKeySequence) {
const QKeySequence &seq = *v_cast<QKeySequence>(d);
*static_cast<int *>(result) = seq.isEmpty() ? 0 : seq[0];
return true;
}
break;
#endif
case QMetaType::QFont:
if (d->type().id() == QMetaType::QString) {
QFont *f = static_cast<QFont *>(result);
f->fromString(*v_cast<QString>(d));
return true;
}
break;
case QMetaType::QColor:
if (d->type().id() == QMetaType::QString) {
static_cast<QColor *>(result)->setNamedColor(*v_cast<QString>(d));
return static_cast<QColor *>(result)->isValid();
} else if (d->type().id() == QMetaType::QByteArray) {
static_cast<QColor *>(result)->setNamedColor(QLatin1String(*v_cast<QByteArray>(d)));
return true;
} else if (d->type().id() == QMetaType::QBrush) {
if (v_cast<QBrush>(d)->style() == Qt::SolidPattern) {
*static_cast<QColor *>(result) = v_cast<QBrush>(d)->color();
return true;
}
}
break;
case QMetaType::QBrush:
if (d->type().id() == QMetaType::QColor) {
*static_cast<QBrush *>(result) = QBrush(*v_cast<QColor>(d));
return true;
} else if (d->type().id() == QMetaType::QPixmap) {
*static_cast<QBrush *>(result) = QBrush(*v_cast<QPixmap>(d));
return true;
}
break;
#if QT_CONFIG(shortcut)
case QMetaType::QKeySequence: {
QKeySequence *seq = static_cast<QKeySequence *>(result);
switch (d->type().id()) {
case QMetaType::QString:
*seq = QKeySequence(*v_cast<QString>(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)

View File

@ -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<QWidget*>();
qMetaTypeWidgetsHelper = &qVariantWidgetsHelper;
QVariantPrivate::registerHandler(QModulesPrivate::Widgets, &widgets_handler);
}
Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant)