aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-06-21 14:08:12 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-06-23 21:22:58 +0200
commit8889089d0fd8ab93f623a98992588087e45399a5 (patch)
treef5f99110badcf61ed4a09b68eb86c87eaca803c4 /src
parenta850b68d918d57d919168649e8bbaa97489f3026 (diff)
QtQml: Further refine value type creation methods
The methods that populate a default-constructed value type should be called "populateValueType" and they don't have to unconditionally destroy the old value. Change-Id: Icbc0b4bccf00bb9d0f6c838239ac23a1ec9367aa Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp10
-rw-r--r--src/qml/qml/qqmlglobal.cpp181
-rw-r--r--src/qml/qml/qqmlglobal_p.h12
3 files changed, 133 insertions, 70 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 4849886ff9..b2d74c8b5d 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -2681,13 +2681,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
d->readReference();
if (void *gadgetPtr = d->gadgetPtr()) {
- if (QQmlValueTypeProvider::createValueType(metaType, data, valueType, gadgetPtr))
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, gadgetPtr))
return true;
if (QMetaType::canConvert(valueType, metaType))
return QMetaType::convert(valueType, gadgetPtr, metaType, data);
} else {
QVariant empty(valueType);
- if (QQmlValueTypeProvider::createValueType(metaType, data, valueType, empty.data()))
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, valueType, empty.data()))
return true;
if (QMetaType::canConvert(valueType, metaType))
return QMetaType::convert(valueType, empty.data(), metaType, data);
@@ -2753,8 +2753,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
proto = proto->getPrototypeOf();
}
}
- } else if (QQmlValueTypeProvider::createValueType(
- metaType, data, var.metaType(), var.data())) {
+ } else if (QQmlValueTypeProvider::populateValueType(
+ metaType, data, var.metaType(), var.data())) {
return true;
}
} else if (value.isNull() && isPointer) {
@@ -2767,7 +2767,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
*reinterpret_cast<QJSPrimitiveValue *>(data) = createPrimitive(&value);
return true;
} else if (!isPointer) {
- if (QQmlValueTypeProvider::createValueType(metaType, data, value))
+ if (QQmlValueTypeProvider::populateValueType(metaType, data, value))
return true;
}
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 232cffd7fe..730687fc2f 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -440,55 +440,43 @@ static QVariant byProperties(
return QVariant();
}
-/*!
- * \internal
- * Specialization that creates the value type in place at \a target, which is expected to be
- * already initialized. This is more efficient if we can do byProperties() since it can use a
- * pre-constructed object. It also avoids the creation of a QVariant in most cases. It is less
- * efficient if you're going to create a QVariant anyway.
- */
-bool QQmlValueTypeProvider::createValueType(
- QMetaType targetMetaType, void *target, const QV4::Value &source)
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, const QV4::Value &source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
{
- if (!isConstructibleMetaType(targetMetaType))
- return false;
-
- auto destruct = [targetMetaType, target]() {
- targetMetaType.destruct(target);
- return target;
- };
-
- const QQmlType type = QQmlMetaType::qmlType(targetMetaType);
- if (const QMetaObject *targetMeta = QQmlMetaType::metaObjectForValueType(type)) {
+ if (const QMetaObject *targetMetaObject = QQmlMetaType::metaObjectForValueType(targetType)) {
const auto warn = [&]() {
qWarning().noquote()
<< "Could not find any constructor for value type"
- << targetMeta->className() << "to call with value" << source.toQStringNoThrow();
+ << targetMetaObject->className() << "to call with value"
+ << source.toQStringNoThrow();
};
- if (type.canPopulateValueType()) {
- if (source.isObject() && targetMeta) {
- doWriteProperties(targetMeta, target, source);
+ if (targetType.canPopulateValueType()) {
+ if (source.isObject() && targetMetaObject) {
+ doWriteProperties(targetMetaObject, defaultConstruct(), source);
return true;
}
- if (type.canConstructValueType()) {
- if (fromMatchingType(targetMeta, source, destruct))
+ if (targetType.canConstructValueType()) {
+ if (fromMatchingType(targetMetaObject, source, std::forward<Allocate>(allocate)))
return true;
warn();
}
- } else if (type.canConstructValueType()) {
- if (fromMatchingType(targetMeta, source, destruct))
+ } else if (targetType.canConstructValueType()) {
+ if (fromMatchingType(targetMetaObject, source, std::forward<Allocate>(allocate)))
return true;
warn();
}
}
- if (const auto valueTypeFunction = type.createValueTypeFunction()) {
+ if (const auto valueTypeFunction = targetType.createValueTypeFunction()) {
const QVariant result
- = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
- if (result.metaType() == targetMetaType) {
- targetMetaType.construct(destruct(), result.constData());
+ = valueTypeFunction(QJSValuePrivate::fromReturnedValue(source.asReturnedValue()));
+ const QMetaType resultType = result.metaType();
+ if (resultType == targetType.typeId()) {
+ resultType.construct(allocate(), result.constData());
return true;
}
}
@@ -496,37 +484,24 @@ bool QQmlValueTypeProvider::createValueType(
return false;
}
-bool QQmlValueTypeProvider::createValueType(
- QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
+template<typename Allocate, typename DefaultConstruct>
+bool createOrConstructValueType(
+ const QQmlType &targetType, QMetaType sourceMetaType, void *source,
+ Allocate &&allocate, DefaultConstruct &&defaultConstruct)
{
- if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
- const QJSValue *val = static_cast<const QJSValue *>(source);
- return createValueType(
- targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
- }
-
- if (!isConstructibleMetaType(targetMetaType))
- return false;
-
- auto destruct = [targetMetaType, target]() {
- targetMetaType.destruct(target);
- return target;
- };
-
- const QQmlType type = QQmlMetaType::qmlType(targetMetaType);
- if (const QMetaObject *targetMetaObject = QQmlMetaType::metaObjectForValueType(type)) {
+ if (const QMetaObject *targetMetaObject = QQmlMetaType::metaObjectForValueType(targetType)) {
const auto warn = [&]() {
qWarning().noquote()
<< "Could not find any constructor for value type"
<< targetMetaObject->className() << "to call with value" << source;
};
- if (type.canPopulateValueType()) {
+ if (targetType.canPopulateValueType()) {
if (const QMetaObject *sourceMetaObject
= QQmlMetaType::metaObjectForValueType(sourceMetaType)) {
doWriteProperties(
- targetMetaObject, target, sourceMetaObject,
+ targetMetaObject, defaultConstruct(), sourceMetaObject,
[&source](const QMetaObject *sourceMetaObject, int sourceProperty) {
return sourceMetaObject->property(sourceProperty).readOnGadget(source);
});
@@ -535,26 +510,31 @@ bool QQmlValueTypeProvider::createValueType(
if (sourceMetaType == QMetaType::fromType<QVariantMap>()) {
doWriteProperties(
- targetMetaObject, target, *static_cast<const QVariantMap *>(source));
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantMap *>(source));
return true;
}
if (sourceMetaType == QMetaType::fromType<QVariantHash>()) {
doWriteProperties(
- targetMetaObject, target, *static_cast<const QVariantHash *>(source));
+ targetMetaObject, defaultConstruct(),
+ *static_cast<const QVariantHash *>(source));
return true;
}
if (sourceMetaType.flags() & QMetaType::PointerToQObject) {
- doWriteProperties(targetMetaObject, target, *static_cast<QObject *const *>(source));
+ doWriteProperties(
+ targetMetaObject, defaultConstruct(),
+ *static_cast<QObject *const *>(source));
return true;
}
}
- if (type.canConstructValueType()) {
- if (fromMatchingType(targetMetaObject, destruct, [&](QMetaType, auto callback) {
- return callback(sourceMetaType, source);
- })) {
+ if (targetType.canConstructValueType()) {
+ if (fromMatchingType(targetMetaObject, std::forward<Allocate>(allocate),
+ [&](QMetaType, auto callback) {
+ return callback(sourceMetaType, source);
+ })) {
return true;
}
warn();
@@ -564,13 +544,92 @@ bool QQmlValueTypeProvider::createValueType(
return false;
}
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source)
+{
+ if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
+ const QJSValue *val = static_cast<const QJSValue *>(source);
+ return populateValueType(
+ targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
+ }
+
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), sourceMetaType, source,
+ [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \internal
+ * Populate the value type in place at \a target, which is expected to be
+ * allocated and default-constructed, for example the result of a QVariant(QMetaType).
+ * This is efficient if we can do byProperties() since it can use the pre-constructed object.
+ * It also avoids the creation of a QVariant in most cases. It is not
+ * efficient if you're going to create a QVariant anyway.
+ */
+bool QQmlValueTypeProvider::populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source)
+{
+ if (!isConstructibleMetaType(targetMetaType))
+ return false;
+
+ return createOrConstructValueType(
+ QQmlMetaType::qmlType(targetMetaType), source, [targetMetaType, target]() {
+ targetMetaType.destruct(target);
+ return target;
+ }, [target]() {
+ return target;
+ });
+}
+
+/*!
+ * \internal
+ * Specialization that constructs the value type on the heap using new and returns a pointer to it.
+ */
+void *QQmlValueTypeProvider::heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source)
+{
+ void *target;
+ if (createOrConstructValueType(
+ targetType, source, [&]() {
+ const QMetaType metaType = targetType.typeId();
+ const ushort align = metaType.alignOf();
+ target = align > __STDCPP_DEFAULT_NEW_ALIGNMENT__
+ ? operator new(metaType.sizeOf(), std::align_val_t(align))
+ : operator new(metaType.sizeOf());
+ return target;
+ }, [&]() {
+ target = targetType.typeId().create();
+ return target;
+ })) {
+ return target;
+ }
+
+ return nullptr;
+}
+
QVariant QQmlValueTypeProvider::constructValueType(
- QMetaType resultMetaType, const QMetaObject *resultMetaObject,
+ QMetaType targetMetaType, const QMetaObject *targetMetaObject,
int ctorIndex, void *ctorArg)
{
QVariant result;
- fromVerifiedType(resultMetaObject, ctorIndex, ctorArg,
- [&]() { return createVariantData(resultMetaType, &result); });
+ fromVerifiedType(targetMetaObject, ctorIndex, ctorArg,
+ [&]() { return createVariantData(targetMetaType, &result); });
return result;
}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index ce18cfb1e1..bed5bd10b1 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -16,8 +16,9 @@
//
#include <private/qmetaobject_p.h>
-#include <private/qtqmlglobal_p.h>
#include <private/qqmlmetaobject_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qtqmlglobal_p.h>
#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
@@ -205,10 +206,13 @@ inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
class QQmlValueTypeProvider
{
public:
- static bool createValueType(QMetaType targetMetaType, void *target, const QV4::Value &source);
- static bool createValueType(
- QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, const QV4::Value &source);
+ static bool populateValueType(
+ QMetaType targetMetaType, void *target, QMetaType sourceMetaType, void *source);
+ static Q_QML_PRIVATE_EXPORT void *heapCreateValueType(
+ const QQmlType &targetType, const QV4::Value &source);
static QVariant constructValueType(
QMetaType targetMetaType, const QMetaObject *targetMetaObject,
int ctorIndex, void *ctorArg);