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 <simon.hausmann@qt.io>
This commit is contained in:
Ville Voutilainen 2017-04-26 13:49:37 +03:00
parent c3e8fc1038
commit 4be29bdbd5
3 changed files with 80 additions and 0 deletions

View File

@ -74,7 +74,9 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qabstractitemmodel.h>
#include <vector>
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 <class T, class M>
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<int> *stdVectorIntPtr;
std::vector<qreal> *stdVectorRealPtr;
std::vector<bool> *stdVectorBoolPtr;
std::vector<QString> *stdVectorQStringPtr;
std::vector<QUrl> *stdVectorQUrlPtr;
std::vector<QModelIndex> *stdVectorQModelIndexPtr;
char allocData[MaxSizeOf8<QVariant,
QString,
@ -1511,6 +1522,18 @@ void *CallArgument::dataPtr()
{
if (type == -1)
return qvariantPtr->data();
else if (type == qMetaTypeId<std::vector<int>>())
return stdVectorIntPtr;
else if (type == qMetaTypeId<std::vector<qreal>>())
return stdVectorRealPtr;
else if (type == qMetaTypeId<std::vector<bool>>())
return stdVectorBoolPtr;
else if (type == qMetaTypeId<std::vector<QString>>())
return stdVectorQStringPtr;
else if (type == qMetaTypeId<std::vector<QUrl>>())
return stdVectorQUrlPtr;
else if (type == qMetaTypeId<std::vector<QModelIndex>>())
return stdVectorQModelIndexPtr;
else if (type != 0)
return (void *)&allocData;
return 0;
@ -1560,6 +1583,19 @@ void CallArgument::initAsType(int callType)
}
}
template <class T, class M>
void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
{
if (object && object->isListType()) {
T* ptr = static_cast<T*>(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<std::vector<int>>()
|| callType == qMetaTypeId<std::vector<qreal>>()
|| callType == qMetaTypeId<std::vector<bool>>()
|| callType == qMetaTypeId<std::vector<QString>>()
|| callType == qMetaTypeId<std::vector<QUrl>>()
|| callType == qMetaTypeId<std::vector<QModelIndex>>()) {
queryEngine = true;
const QV4::Object* object = value.as<Object>();
if (callType == qMetaTypeId<std::vector<int>>()) {
stdVectorIntPtr = nullptr;
fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<qreal>>()) {
stdVectorRealPtr = nullptr;
fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<bool>>()) {
stdVectorBoolPtr = nullptr;
fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<QString>>()) {
stdVectorQStringPtr = nullptr;
fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
stdVectorQUrlPtr = nullptr;
fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
} else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
stdVectorQModelIndexPtr = nullptr;
fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
}
} else {
queryEngine = true;
}

View File

@ -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<SequenceType>()) return object->as<QQml##ElementTypeName##List>(); 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<QQml##ElementTypeName##List>()) { \
return qMetaTypeId<SequenceType>(); \

View File

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