5#include <QtCore/qsequentialiterable.h>
9#include <private/qv4functionobject_p.h>
10#include <private/qv4arrayobject_p.h>
11#include <private/qqmlengine_p.h>
12#include <private/qv4scopedvalue_p.h>
13#include <private/qv4jscall_p.h>
14#include <private/qqmlmetatype_p.h>
15#include <private/qqmltype_p_p.h>
16#include <private/qqmlvaluetypewrapper_p.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
56Q_STATIC_LOGGING_CATEGORY(lcListValueConversion,
"qt.qml.listvalueconversion")
65 QV4::Scope scope(p->internalClass->engine);
67 const QMetaType valueMetaType = p->valueMetaType();
68 const QMetaSequence metaSequence = p->metaSequence();
70 Heap::ReferenceObject::Flags flags = Heap::ReferenceObject::EnforcesLocation;
71 if (metaSequence.canSetValueAtIndex())
72 flags |= Heap::ReferenceObject::CanWriteBack;
78 if (valueMetaType == QMetaType::fromType<QVariant>()) {
79 flags |= Heap::ReferenceObject::IsVariant;
80 metaSequence.valueAtIndex(container, index, &result);
82 result = QVariant(valueMetaType);
83 metaSequence.valueAtIndex(container, index, result.data());
86 QV4::ScopedValue v(scope, scope.engine->fromVariant(result, p, index, flags));
87 if (QQmlValueTypeWrapper *ref = v->as<QQmlValueTypeWrapper>()) {
88 if (CppStackFrame *frame = scope.engine->currentStackFrame)
89 ref->d()->setLocation(frame->v4Function, frame->statementNumber());
92 return v->asReturnedValue();
97 if (type == QMetaType::fromType<QVariant>())
99 *variant = QVariant(type);
100 return variant->data();
105 if (type == QMetaType::fromType<QVariant>())
107 return variant->constData();
113 QQmlEngine *engine = v4->qmlEngine();
117 retn.setDescription(description);
119 QV4::CppStackFrame *stackFrame = v4->currentStackFrame;
121 retn.setLine(stackFrame->lineNumber());
122 retn.setUrl(QUrl(stackFrame->source()));
123 QQmlEnginePrivate::warning(engine, retn);
131 return p->metaSequence().size(container);
142 PropertyKey next(
const Object *o, Property *pd =
nullptr, PropertyAttributes *attrs =
nullptr)
override
144 Heap::
Sequence *p =
static_cast<
const Sequence *>(o)->d();
147 if (p->isReference() && !p->loadReference())
148 return PropertyKey::invalid();
150 const qsizetype size = sizeInline(p);
151 if (size > 0 && qIsAtMostSizetypeLimit(arrayIndex, size - 1)) {
152 const uint index = arrayIndex;
155 *attrs = QV4::Attr_Data;
157 pd->value = doGetIndexed(p, index);
158 return PropertyKey::fromArrayIndex(index);
161 if (memberIndex == 0) {
163 return o->engine()->id_length()->propertyKey();
167 return PropertyKey::invalid();
171void Heap::
Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence)
173 m_listType = listType.iface();
174 Q_ASSERT(m_listType);
175 m_metaSequence = metaSequence.iface();
176 Q_ASSERT(m_metaSequence);
179void Heap::
Sequence::
init(QMetaType listType, QMetaSequence metaSequence,
const void *container)
181 ReferenceObject::init(
nullptr, -1, NoFlag);
182 initTypes(listType, metaSequence);
184 createInlineStorage(container);
186 createElementWrappers(container);
190 QMetaType listType, QMetaSequence metaSequence,
const void *container,
191 Heap::Object *object,
int propertyIndex, Heap::ReferenceObject::Flags flags)
193 ReferenceObject::init(object, propertyIndex, flags | IsDirty);
194 initTypes(listType, metaSequence);
197 if (CppStackFrame *frame = internalClass->engine->currentStackFrame)
198 setLocation(frame->v4Function, frame->statementNumber());
199 createInlineStorage(container);
200 if (!container && (flags & EnforcesLocation))
201 QV4::ReferenceObject::readReference(
this);
203 createElementWrappers(container);
207void Heap::
Sequence::createInlineStorage(
const void *container)
211 QV4::Scope scope(internalClass->engine);
212 QV4::Scoped<QV4::Sequence> o(scope,
this);
213 o->setArrayType(Heap::ArrayData::Custom);
215 m_container = listType().create(container);
218void Heap::
Sequence::createElementWrappers(
const void *container)
225 const QMetaSequence metaSequence(m_metaSequence);
226 const QMetaType valueMetaType = metaSequence.valueMetaType();
227 const qsizetype size = metaSequence.size(container);
229 QV4::Scope scope(internalClass->engine);
230 if (!qIsAtMostUintLimit(size)) {
231 generateWarning(scope.engine, QLatin1String(
"Sequence length out of range"));
235 QV4::Scoped<QV4::Sequence> self(scope,
this);
236 self->arrayReserve(size);
237 QV4::ScopedValue v(scope);
238 if (valueMetaType == QMetaType::fromType<QVariant>()) {
240 for (qsizetype i = 0; i < size; ++i) {
241 metaSequence.valueAtIndex(container, i, &var);
242 v = scope.engine->metaTypeToJS(var.metaType(), var.constData());
243 self->arraySet(i, v);
246 QVariant var(valueMetaType);
247 for (qsizetype i = 0; i < size; ++i) {
248 metaSequence.valueAtIndex(container, i, var.data());
249 v = scope.engine->metaTypeToJS(valueMetaType, var.constData());
250 self->arraySet(i, v);
259 const QMetaType listType(m_listType);
260 const QMetaSequence metaSequence(m_metaSequence);
262 return internalClass->engine->memoryManager->allocate<QV4::Sequence>(
263 listType, metaSequence, m_container);
266 QVariant list(listType);
268 const QMetaType valueMetaType(m_metaSequence->valueMetaType);
270 void *elementData = createVariantData(valueMetaType, &element);
272 QV4::Scope scope(internalClass->engine);
273 if (qIsAtMostSizetypeLimit(m_size)) {
274 QV4::Scoped<QV4::Sequence> self(scope,
this);
275 QV4::ScopedValue v(scope);
276 for (uint i = 0; i < m_size; ++i) {
277 v = self->get(PropertyKey::fromArrayIndex(i));
278 ExecutionEngine::metaTypeFromJS(v, valueMetaType, elementData);
279 metaSequence.addValue(list.data(), elementData);
282 generateWarning(scope.engine, QLatin1String(
"Index out of range during toVariant()"));
285 return scope.engine->memoryManager->allocate<QV4::Sequence>(
286 listType, metaSequence, list.constData());
291 if (isStoredInline() && m_container)
292 listType().destroy(m_container);
293 ReferenceObject::destroy();
301 m_container = listType().create();
310 const QMetaType variantReferenceType = variant.metaType();
311 if (variantReferenceType != listType()) {
316 const QQmlType newType = QQmlMetaType::qmlListType(variantReferenceType);
317 if (newType.isSequentialContainer()) {
319 listType().destroy(m_container);
320 m_listType = newType.qListTypeId().iface();
321 m_metaSequence = newType.listMetaSequence().iface();
322 m_container = listType().create(variant.constData());
329 variantReferenceType.destruct(m_container);
330 variantReferenceType.construct(m_container, variant.constData());
332 m_container = variantReferenceType.create(variant.constData());
341 return QVariant(listType(), m_container);
344template<
typename Action>
345void convertAndDo(
const QVariant &item,
const QMetaType v, Action action)
347 if (item.metaType() == v) {
348 action(item.constData());
349 }
else if (v == QMetaType::fromType<QVariant>()) {
352 QVariant converted = item;
353 if (!converted.convert(v))
354 converted = QVariant(v);
355 action(converted.constData());
361 convertAndDo(item, p->valueMetaType(), [p](
const void *data) {
369 const void *data = createVariantData(p->valueMetaType(), &item);
370 const QMetaSequence m = p->metaSequence();
372 for (qsizetype i = 0; i < num; ++i)
373 m.addValueAtEnd(container, data);
378 convertAndDo(item, p->valueMetaType(), [p, index](
const void *data) {
385 const QMetaSequence m = p->metaSequence();
388 if (m.canEraseRangeAtIterator() && m.hasRandomAccessIterator() && num > 1) {
389 void *i = m.end(container);
390 m.advanceIterator(i, -num);
391 void *j = m.end(container);
392 m.eraseRangeAtIterator(container, i, j);
393 m.destroyIterator(i);
394 m.destroyIterator(j);
396 for (
int i = 0; i < num; ++i)
397 m.removeValueAtEnd(container);
403 Q_ASSERT(isReference());
405 return enforcesLocation() || QV4::ReferenceObject::readReference(
this);
410 Q_ASSERT(isReference());
411 return isAttachedToProperty() && QV4::ReferenceObject::writeBack(
this);
797 for (
int i =
argc - 1;
i >= 0; --
i) {
935
936
937
938
965 QSequentialIterable iterable;
966 if (!QMetaType::view(metaType, data, QMetaType::fromType<QSequentialIterable>(), &iterable))
969 const QMetaType elementMetaType = iterable.valueMetaType();
970 QV4::Scope scope(sequence->engine());
971 QV4::ScopedValue v(scope);
972 for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
973 QVariant element(elementMetaType);
974 v = sequence->get(i);
975 ExecutionEngine::metaTypeFromJS(v, elementMetaType, element.data());
976 iterable.addValue(element, QSequentialIterable::AtEnd);
982
983
984
985
986
987
988
1078 "QJSValue even though they are not directly convertible"));
1087 warn(
QLatin1String(
"Could not convert array value at position %1 from %2 to %3"));
1100 if (p->listType() != typeHint)
1186#include "moc_qv4sequenceobject_p.cpp"
static Heap::Sequence * resolveHeapSequence(const Sequence *sequence, QMetaType typeHint)
static void removeLastInline(Heap::Sequence *p, qsizetype num)
static void * createVariantData(QMetaType type, QVariant *variant)
static void generateWarning(QV4::ExecutionEngine *v4, const QString &description)
static void appendInline(Heap::Sequence *p, const QVariant &item)
void convertAndDo(const QVariant &item, const QMetaType v, Action action)
bool convertToIterable(QMetaType metaType, void *data, QV4::Object *sequence)
static const void * retrieveVariantData(QMetaType type, const QVariant *variant)
static void appendDefaultConstructedInline(Heap::Sequence *p, qsizetype num)
static void replaceInline(Heap::Sequence *p, qsizetype index, const QVariant &item)
static qsizetype sizeInline(const Heap::Sequence *p)
static ReturnedValue doGetIndexed(Heap::Sequence *p, qsizetype index)
void init(QMetaType listType, QMetaSequence metaSequence, const void *container)
bool isStoredInline() const
QVariant toVariant() const
void init(QMetaType listType, QMetaSequence metaSequence, const void *container, Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
const void * storagePointer() const
bool setVariant(const QVariant &variant)
PropertyKey next(const Object *o, Property *pd=nullptr, PropertyAttributes *attrs=nullptr) override
~SequenceOwnPropertyKeyIterator() override=default