57 Heap::ArrayData *arrayData = object.arrayData();
59 const uint length = arrayData->length();
60 if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
61 object.scope.engine->throwRangeError(QLatin1String(
"Too many elements."));
65 ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1,
false);
66 QV4::Scope scope(object.scope.engine);
67 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(object.scope.engine, o));
68 arrayData->vtable()->put(
69 object.object, length, wrappedObject);
166ReturnedValue QmlListWrapper::createOwned(ExecutionEngine *engine,
const QQmlProperty &prop)
168 Q_ASSERT(prop.propertyMetaType().flags() & QMetaType::IsQmlList);
169 QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
170 QQmlListProperty<QObject> listProp;
171 privProp->core.readProperty(privProp->object, &listProp);
172 const qsizetype listSize = listProp.count(&listProp);
174 Scoped<QV4::QmlListWrapper> listWrapper(scope, QV4::QmlListWrapper::create(engine, privProp->propertyType()));
177 Heap::ArrayData *arrayData = listWrapper->arrayData();
178 ArrayData::realloc(listWrapper, Heap::ArrayData::Simple, listSize,
false);
179 for (qsizetype i = 0; i != listSize; ++i) {
180 QObject *o = listProp.at(&listProp, i);
181 ScopedObject scopedO(scope, QV4::QObjectWrapper::wrap(engine, o));
182 arrayData->vtable()->put(listWrapper, i, scopedO);
184 return listWrapper.asReturnedValue();
201ReturnedValue QmlListWrapper::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
203 Q_ASSERT(m->as<QmlListWrapper>());
204 const QmlListWrapper *w =
static_cast<
const QmlListWrapper *>(m);
205 QV4::ExecutionEngine *v4 = w->engine();
207 if (id.isArrayIndex()) {
208 const uint index = id.asArrayIndex();
209 const quint32 count = w->d()->property()->count
210 ? w->d()->property()->count(w->d()->property())
212 if (index < count && w->d()->property()->at) {
215 return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
219 *hasProperty =
false;
220 return Value::undefinedValue().asReturnedValue();
223 return Object::virtualGet(m, id, receiver, hasProperty);
234bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
236 Q_ASSERT(m->as<QmlListWrapper>());
238 const auto *w =
static_cast<
const QmlListWrapper *>(m);
239 QV4::ExecutionEngine *v4 = w->engine();
241 QQmlListProperty<QObject> *prop = w->d()->property();
243 if (id.isArrayIndex()) {
244 if (!prop->count || !prop->replace)
247 const uint index = id.asArrayIndex();
248 const int count = prop->count(prop);
249 if (count < 0 || index >= uint(count))
252 if (value.isNull()) {
253 prop->replace(prop, index,
nullptr);
257 QV4::Scope scope(v4);
258 QV4::ScopedObject so(scope, value.toObject(scope.engine));
259 if (
auto *wrapper = so->as<QV4::QObjectWrapper>()) {
260 QObject *object = wrapper->object();
262 prop->replace(prop, index, object);
266 const QMetaType elementType = w->d()->elementType();
267 const QMetaObject *elementMeta = elementType.metaObject();
268 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
269 qCWarning(lcIncompatibleElement)
270 <<
"Cannot insert" << object <<
"into a QML list of" << elementType.name();
271 prop->replace(prop, index,
nullptr);
275 prop->replace(prop, index, object);
282 return Object::virtualPut(m, id, value, receiver);
324 defineDefaultProperty(QStringLiteral(
"pop"), method_pop, 0);
325 defineDefaultProperty(QStringLiteral(
"push"), method_push, 1);
326 defineDefaultProperty(QStringLiteral(
"shift"), method_shift, 0);
327 defineDefaultProperty(QStringLiteral(
"splice"), method_splice, 2);
328 defineDefaultProperty(QStringLiteral(
"unshift"), method_unshift, 1);
329 defineDefaultProperty(QStringLiteral(
"indexOf"), method_indexOf, 1);
330 defineDefaultProperty(QStringLiteral(
"lastIndexOf"), method_lastIndexOf, 1);
331 defineDefaultProperty(QStringLiteral(
"sort"), method_sort, 1);
332 defineAccessorProperty(QStringLiteral(
"length"), method_get_length, method_set_length);
335ReturnedValue
PropertyListPrototype::method_pop(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
338 ScopedObject instance(scope, thisObject->toObject(scope.engine));
342 QmlListWrapper *w = instance->as<QmlListWrapper>();
346 QQmlListProperty<QObject> *property = w->d()->property();
348 if (!property->count)
349 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
350 const qsizetype len = property->count(property);
355 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
357 scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
359 if (!property->removeLast)
360 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
361 property->removeLast(property);
363 return result->asReturnedValue();
366ReturnedValue
PropertyListPrototype::method_push(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
369 ScopedObject instance(scope, thisObject->toObject(scope.engine));
372 QmlListWrapper *w = instance->as<QmlListWrapper>();
376 QQmlListProperty<QObject> *property = w->d()->property();
377 if (!property->append)
378 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
379 if (!property->count)
380 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
382 for (
int i = 0; i < argc; ++i) {
383 const Value &arg = argv[i];
384 if (!arg.isNull() && !arg.as<QObjectWrapper>())
388 const qsizetype length = property->count(property);
389 if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
390 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
392 const QMetaType elementType = w->d()->elementType();
393 const QMetaObject *elementMeta = elementType.metaObject();
394 for (
int i = 0; i < argc; ++i) {
395 if (argv[i].isNull()) {
396 property->append(property,
nullptr);
400 QObject *object = argv[i].as<QV4::QObjectWrapper>()->object();
402 property->append(property,
nullptr);
406 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
407 qCWarning(lcIncompatibleElement)
408 <<
"Cannot append" << object <<
"to a QML list of" << elementType.name();
409 property->append(property,
nullptr);
413 property->append(property, object);
416 const auto actualLength = property->count(property);
417 if (actualLength != length + argc)
418 qmlWarning(property->object) <<
"List didn't append all objects";
420 return Encode(uint(actualLength));
423ReturnedValue
PropertyListPrototype::method_shift(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
426 ScopedObject instance(scope, thisObject->toObject(scope.engine));
429 QmlListWrapper *w = instance->as<QmlListWrapper>();
433 QQmlListProperty<QObject> *property = w->d()->property();
435 if (!property->count)
436 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
437 const qsizetype len = property->count(property);
442 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
443 ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
445 if (!property->replace)
446 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
447 if (!property->removeLast)
448 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
450 for (qsizetype i = 1; i < len; ++i)
451 property->replace(property, i - 1, property->at(property, i));
452 property->removeLast(property);
454 return result->asReturnedValue();
457ReturnedValue
PropertyListPrototype::method_splice(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
460 ScopedObject instance(scope, thisObject->toObject(scope.engine));
463 QmlListWrapper *w = instance->as<QmlListWrapper>();
467 QQmlListProperty<QObject> *property = w->d()->property();
469 if (!property->count)
470 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
471 const qsizetype len = property->count(property);
473 const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
476 start =
static_cast<qsizetype>(qMax(0., len + rs));
478 start =
static_cast<qsizetype>(qMin(rs,
static_cast<
double>(len)));
480 qsizetype deleteCount = 0;
481 qsizetype itemCount = 0;
483 deleteCount = len - start;
484 }
else if (argc > 1){
485 itemCount = argc - 2;
486 double dc = argv[1].toInteger();
487 deleteCount =
static_cast<qsizetype>(qMin(qMax(dc, 0.),
double(len - start)));
490 if (itemCount > deleteCount
491 && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
492 return scope.engine->throwTypeError();
495 if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
496 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
499 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
501 for (qsizetype i = 0; i < itemCount; ++i) {
502 const auto arg = argv[i + 2];
503 if (!arg.isNull() && !arg.as<QObjectWrapper>())
507 ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
508 newArray->arrayReserve(deleteCount);
509 ScopedValue v(scope);
510 QV4::ScopedValue wrappedObject(scope);
511 for (qsizetype i = 0; i < deleteCount; ++i) {
512 wrappedObject = QObjectWrapper::wrap(scope.engine, property->at(property, start + i));
516 newArray->setArrayLengthUnchecked(deleteCount);
518 if (!property->replace)
519 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
520 if (!property->removeLast)
521 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
522 if (!property->append)
523 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
525 if (itemCount < deleteCount) {
526 for (qsizetype k = start; k < len - deleteCount; ++k)
527 property->replace(property, k + itemCount, property->at(property, k + deleteCount));
528 for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
529 property->removeLast(property);
530 }
else if (itemCount > deleteCount) {
531 for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
532 property->append(property,
nullptr);
533 for (qsizetype k = len - deleteCount; k > start; --k) {
535 property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
539 const QMetaType elementType = w->d()->elementType();
540 const QMetaObject *elementMeta = elementType.metaObject();
541 for (qsizetype i = 0; i < itemCount; ++i) {
542 const auto arg = argv[i + 2];
544 property->replace(property, start + i,
nullptr);
548 QObject *object = arg.as<QObjectWrapper>()->object();
550 property->replace(property, start + i,
nullptr);
554 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
555 qCWarning(lcIncompatibleElement)
556 <<
"Cannot splice" << object <<
"into a QML list of" << elementType.name();
557 property->replace(property, start + i,
nullptr);
561 property->replace(property, start + i, object);
564 return newArray->asReturnedValue();
567ReturnedValue
PropertyListPrototype::method_unshift(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
570 ScopedObject instance(scope, thisObject->toObject(scope.engine));
574 QmlListWrapper *w = instance->as<QmlListWrapper>();
578 QQmlListProperty<QObject> *property = w->d()->property();
580 if (!property->count)
581 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
582 const qsizetype len = property->count(property);
584 if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
585 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
587 if (!property->append)
588 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
589 if (!property->replace)
590 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
592 for (
int i = 0; i < argc; ++i) {
593 const auto arg = argv[i];
594 if (!arg.isNull() && !arg.as<QObjectWrapper>())
598 for (
int i = 0; i < argc; ++i)
599 property->append(property,
nullptr);
600 if (property->count(property) != argc + len)
601 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
603 for (qsizetype k = len; k > 0; --k)
604 property->replace(property, k + argc - 1, property->at(property, k - 1));
606 const QMetaType elementType = w->d()->elementType();
607 const QMetaObject *elementMeta = elementType.metaObject();
608 for (
int i = 0; i < argc; ++i) {
609 const auto *wrapper = argv[i].as<QObjectWrapper>();
610 QObject *object = wrapper ? wrapper->object() :
nullptr;
612 property->replace(property, i, object);
616 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
617 qCWarning(lcIncompatibleElement)
618 <<
"Cannot unshift" << object <<
"into a QML list of" << elementType.name();
619 property->replace(property, i,
nullptr);
623 property->replace(property, i, object);
626 return Encode(uint(len + argc));
638 QObject *searchValue;
639 if (argv[0].isNull()) {
640 searchValue =
nullptr;
642 Scoped<QObjectWrapper> wrapper(scope, argv[0]);
644 searchValue = wrapper->object();
649 ScopedObject instance(scope, thisObject->toObject(scope.engine));
653 QmlListWrapper *w = instance->as<QmlListWrapper>();
657 QQmlListProperty<QObject> *property = w->d()->property();
659 if (!property->count)
660 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
661 const qsizetype len = property->count(property);
666 return iterate(scope.engine, property, len, searchValue);
669ReturnedValue
PropertyListPrototype::method_indexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
671 return firstOrLastIndexOf(
672 b, thisObject, argv, argc,
673 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
674 qsizetype len, QObject *searchValue) -> ReturnedValue {
675 qsizetype fromIndex = 0;
677 double f = argv[1].toInteger();
678 if (hasExceptionOrIsInterrupted(engine))
679 return Encode::undefined();
683 f = qMax(len + f, 0.);
684 fromIndex = qsizetype(f);
687 for (qsizetype i = fromIndex; i < len; ++i) {
688 if (property->at(property, i) == searchValue) {
689 if (qIsAtMostUintLimit(i))
690 return Encode(uint(i));
691 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
699ReturnedValue
PropertyListPrototype::method_lastIndexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
701 return firstOrLastIndexOf(
702 b, thisObject, argv, argc,
703 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
704 qsizetype len, QObject *searchValue) -> ReturnedValue {
705 qsizetype fromIndex = len - 1;
707 double f = argv[1].toInteger();
708 if (hasExceptionOrIsInterrupted(engine))
709 return Encode::undefined();
711 f = qMin(f, (
double)(len - 1));
717 fromIndex = qsizetype(f);
720 for (qsizetype i = fromIndex; i >= 0; --i) {
721 if (property->at(property, i) == searchValue) {
722 if (qIsAtMostUintLimit(i))
723 return Encode(uint(i));
724 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
732ReturnedValue
PropertyListPrototype::method_sort(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
735 ScopedObject instance(scope, thisObject->toObject(scope.engine));
739 QmlListWrapper *w = instance->as<QmlListWrapper>();
743 QQmlListProperty<QObject> *property = w->d()->property();
745 if (!property->count)
746 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
747 if (property->count(property) == 0)
748 return thisObject->asReturnedValue();
750 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
751 if (!property->replace)
752 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
754 ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
755 if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
758 const ArrayElementLessThan lessThan(scope.engine, comparefn);
759 sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
760 Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
761 Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
762 return lessThan(o1, o2);
765 return thisObject->asReturnedValue();
790ReturnedValue
PropertyListPrototype::method_set_length(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
793 ScopedObject instance(scope, thisObject->toObject(scope.engine));
797 const QmlListWrapper *w = instance->as<QmlListWrapper>();
801 QQmlListProperty<QObject> *property = w->d()->property();
804 const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
806 return scope.engine->throwRangeError(QString::fromLatin1(
"Invalid list length."));
808 if (newLength == 0 && property->clear) {
809 property->clear(property);
813 if (!property->count)
814 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
816 qsizetype count = property->count(property);
817 if (!qIsAtMostUintLimit(count))
818 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
820 if (newLength < uint(count)) {
821 if (!property->removeLast)
822 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
824 for (uint i = count; i > newLength; --i)
825 property->removeLast(property);
830 if (!property->append)
831 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
833 for (uint i = count; i < newLength; ++i)
834 property->append(property,
nullptr);
836 count = property->count(property);
837 if (!qIsAtMostUintLimit(count))
838 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
840 if (uint(count) != newLength)
841 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);