From 4be29bdbd5fc5d9751ff07718dcf04c256d4bd34 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 26 Apr 2017 13:49:37 +0300 Subject: [PATCH] Don't wrap std::vector into a QVariant when passing it to a Q_INVOKABLE Task-number: QTBUG-60386 Change-Id: Idd5a8939a575c254636042b5cb1900d2d8673072 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 63 +++++++++++++++++++++++++ src/qml/jsruntime/qv4sequenceobject.cpp | 16 +++++++ src/qml/jsruntime/qv4sequenceobject_p.h | 1 + 3 files changed, 80 insertions(+) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index d86a51e3a4..270aaba8f8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -74,7 +74,9 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE // The code in this file does not violate strict aliasing, but GCC thinks it does @@ -1076,12 +1078,21 @@ private: inline void cleanup(); + template + void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine); + union { float floatValue; double doubleValue; quint32 intValue; bool boolValue; QObject *qobjectPtr; + std::vector *stdVectorIntPtr; + std::vector *stdVectorRealPtr; + std::vector *stdVectorBoolPtr; + std::vector *stdVectorQStringPtr; + std::vector *stdVectorQUrlPtr; + std::vector *stdVectorQModelIndexPtr; char allocData[MaxSizeOf8data(); + else if (type == qMetaTypeId>()) + return stdVectorIntPtr; + else if (type == qMetaTypeId>()) + return stdVectorRealPtr; + else if (type == qMetaTypeId>()) + return stdVectorBoolPtr; + else if (type == qMetaTypeId>()) + return stdVectorQStringPtr; + else if (type == qMetaTypeId>()) + return stdVectorQUrlPtr; + else if (type == qMetaTypeId>()) + return stdVectorQModelIndexPtr; else if (type != 0) return (void *)&allocData; return 0; @@ -1560,6 +1583,19 @@ void CallArgument::initAsType(int callType) } } +template +void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine) +{ + if (object && object->isListType()) { + T* ptr = static_cast(QV4::SequencePrototype::getRawContainerPtr(object, callType)); + if (ptr) { + (this->*member) = ptr; + type = callType; + queryEngine = false; + } + } +} + void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value) { if (type != 0) { @@ -1641,6 +1677,33 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == QMetaType::Void) { *qvariantPtr = QVariant(); + } else if (callType == qMetaTypeId>() + || callType == qMetaTypeId>() + || callType == qMetaTypeId>() + || callType == qMetaTypeId>() + || callType == qMetaTypeId>() + || callType == qMetaTypeId>()) { + queryEngine = true; + const QV4::Object* object = value.as(); + if (callType == qMetaTypeId>()) { + stdVectorIntPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine); + } else if (callType == qMetaTypeId>()) { + stdVectorRealPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine); + } else if (callType == qMetaTypeId>()) { + stdVectorBoolPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine); + } else if (callType == qMetaTypeId>()) { + stdVectorQStringPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine); + } else if (callType == qMetaTypeId>()) { + stdVectorQUrlPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine); + } else if (callType == qMetaTypeId>()) { + stdVectorQModelIndexPtr = nullptr; + fromContainerValue>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine); + } } else { queryEngine = true; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 2281fa22b6..8afc672aa2 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -524,6 +524,9 @@ public: return QVariant::fromValue(result); } + void* getRawContainerPtr() const + { return d()->container; } + void loadReference() const { Q_ASSERT(d()->object); @@ -746,6 +749,19 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo #undef SEQUENCE_TO_VARIANT +#define SEQUENCE_GET_RAWCONTAINERPTR(ElementType, ElementTypeName, SequenceType, unused) \ + if (const QQml##ElementTypeName##List *list = [&]() -> const QQml##ElementTypeName##List* \ + { if (typeHint == qMetaTypeId()) return object->as(); return nullptr;}()) \ + return list->getRawContainerPtr(); \ + else + +void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint) +{ + FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_GET_RAWCONTAINERPTR) { /* else */ return nullptr; } +} + +#undef SEQUENCE_GET_RAWCONTAINERPTR + #define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \ if (object->as()) { \ return qMetaTypeId(); \ diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 6f96b9f760..dcab34d092 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -80,6 +80,7 @@ struct SequencePrototype : public QV4::Object static int metaTypeForSequence(const Object *object); static QVariant toVariant(Object *object); static QVariant toVariant(const Value &array, int typeHint, bool *succeeded); + static void* getRawContainerPtr(const Object *object, int typeHint); }; }