57 ListWrapperObject object(p);
58 Heap::ArrayData *arrayData = object.arrayData();
60 const uint length = arrayData->length();
61 if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
62 object.scope.engine->throwRangeError(QLatin1String(
"Too many elements."));
66 ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1,
false);
67 QV4::Scope scope(object.scope.engine);
68 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(object.scope.engine, o));
69 arrayData->vtable()->put(
70 object.object, length, wrappedObject);
167ReturnedValue QmlListWrapper::createOwned(ExecutionEngine *engine,
const QQmlProperty &prop)
169 Q_ASSERT(prop.propertyMetaType().flags() & QMetaType::IsQmlList);
170 QQmlPropertyPrivate *privProp = QQmlPropertyPrivate::get(prop);
171 QQmlListProperty<QObject> listProp;
172 privProp->core.readProperty(privProp->object, &listProp);
173 const qsizetype listSize = listProp.count(&listProp);
175 Scoped<QV4::QmlListWrapper> listWrapper(scope, QV4::QmlListWrapper::create(engine, privProp->propertyType()));
178 Heap::ArrayData *arrayData = listWrapper->arrayData();
179 ArrayData::realloc(listWrapper, Heap::ArrayData::Simple, listSize,
false);
180 for (qsizetype i = 0; i != listSize; ++i) {
181 QObject *o = listProp.at(&listProp, i);
182 ScopedObject scopedO(scope, QV4::QObjectWrapper::wrap(engine, o));
183 arrayData->vtable()->put(listWrapper, i, scopedO);
185 return listWrapper.asReturnedValue();
206ReturnedValue QmlListWrapper::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
208 Q_ASSERT(m->as<QmlListWrapper>());
209 const QmlListWrapper *w =
static_cast<
const QmlListWrapper *>(m);
210 QV4::ExecutionEngine *v4 = w->engine();
212 if (id.isArrayIndex()) {
213 if (w->d()->hasDeadOwner()) {
215 *hasProperty =
false;
216 return Value::undefinedValue().asReturnedValue();
219 const uint index = id.asArrayIndex();
220 const quint32 count = w->d()->property()->count
221 ? w->d()->property()->count(w->d()->property())
223 if (index < count && w->d()->property()->at) {
226 return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
230 *hasProperty =
false;
231 return Value::undefinedValue().asReturnedValue();
234 return Object::virtualGet(m, id, receiver, hasProperty);
248bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
250 Q_ASSERT(m->as<QmlListWrapper>());
252 const auto *w =
static_cast<
const QmlListWrapper *>(m);
253 QV4::ExecutionEngine *v4 = w->engine();
255 QQmlListProperty<QObject> *prop = w->d()->property();
257 if (id.isArrayIndex()) {
258 if (w->d()->hasDeadOwner())
261 if (!prop->count || !prop->replace)
264 const uint index = id.asArrayIndex();
265 const int count = prop->count(prop);
274 if (index >= uint(count)) {
278 for (uint times = uint(count); times < index; ++times)
279 prop->append(prop,
nullptr);
282 if (value.isNull()) {
283 prop->replace(prop, index,
nullptr);
287 QV4::Scope scope(v4);
288 QV4::ScopedObject so(scope, value.toObject(scope.engine));
289 if (
auto *wrapper = so->as<QV4::QObjectWrapper>()) {
290 QObject *object = wrapper->object();
292 prop->replace(prop, index, object);
296 const QMetaType elementType = w->d()->elementType();
297 const QMetaObject *elementMeta = elementType.metaObject();
298 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
299 qCWarning(lcIncompatibleElement)
300 <<
"Cannot insert" << object <<
"into a QML list of" << elementType.name();
301 prop->replace(prop, index,
nullptr);
305 prop->replace(prop, index, object);
312 return Object::virtualPut(m, id, value, receiver);
358 defineDefaultProperty(QStringLiteral(
"pop"), method_pop, 0);
359 defineDefaultProperty(QStringLiteral(
"push"), method_push, 1);
360 defineDefaultProperty(QStringLiteral(
"shift"), method_shift, 0);
361 defineDefaultProperty(QStringLiteral(
"splice"), method_splice, 2);
362 defineDefaultProperty(QStringLiteral(
"unshift"), method_unshift, 1);
363 defineDefaultProperty(QStringLiteral(
"indexOf"), method_indexOf, 1);
364 defineDefaultProperty(QStringLiteral(
"lastIndexOf"), method_lastIndexOf, 1);
365 defineDefaultProperty(QStringLiteral(
"sort"), method_sort, 1);
366 defineAccessorProperty(QStringLiteral(
"length"), method_get_length, method_set_length);
369ReturnedValue
PropertyListPrototype::method_pop(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
372 ScopedObject instance(scope, thisObject->toObject(scope.engine));
376 QmlListWrapper *w = instance->as<QmlListWrapper>();
380 if (w->d()->hasDeadOwner())
383 QQmlListProperty<QObject> *property = w->d()->property();
385 if (!property->count)
386 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
387 const qsizetype len = property->count(property);
392 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
394 scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
396 if (!property->removeLast)
397 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
398 property->removeLast(property);
400 return result->asReturnedValue();
403ReturnedValue
PropertyListPrototype::method_push(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
406 ScopedObject instance(scope, thisObject->toObject(scope.engine));
409 QmlListWrapper *w = instance->as<QmlListWrapper>();
413 if (w->d()->hasDeadOwner())
416 QQmlListProperty<QObject> *property = w->d()->property();
417 if (!property->append)
418 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
419 if (!property->count)
420 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
422 for (
int i = 0; i < argc; ++i) {
423 const Value &arg = argv[i];
424 if (!arg.isNull() && !arg.as<QObjectWrapper>())
428 const qsizetype length = property->count(property);
429 if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
430 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
432 const QMetaType elementType = w->d()->elementType();
433 const QMetaObject *elementMeta = elementType.metaObject();
434 for (
int i = 0; i < argc; ++i) {
435 if (argv[i].isNull()) {
436 property->append(property,
nullptr);
440 QObject *object = argv[i].as<QV4::QObjectWrapper>()->object();
442 property->append(property,
nullptr);
446 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
447 qCWarning(lcIncompatibleElement)
448 <<
"Cannot append" << object <<
"to a QML list of" << elementType.name();
449 property->append(property,
nullptr);
453 property->append(property, object);
456 const auto actualLength = property->count(property);
457 if (actualLength != length + argc)
458 qmlWarning(property->object) <<
"List didn't append all objects";
460 return Encode(uint(actualLength));
463ReturnedValue
PropertyListPrototype::method_shift(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
466 ScopedObject instance(scope, thisObject->toObject(scope.engine));
469 QmlListWrapper *w = instance->as<QmlListWrapper>();
473 if (w->d()->hasDeadOwner())
476 QQmlListProperty<QObject> *property = w->d()->property();
478 if (!property->count)
479 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
480 const qsizetype len = property->count(property);
485 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
486 ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
488 if (!property->replace)
489 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
490 if (!property->removeLast)
491 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
493 for (qsizetype i = 1; i < len; ++i)
494 property->replace(property, i - 1, property->at(property, i));
495 property->removeLast(property);
497 return result->asReturnedValue();
500ReturnedValue
PropertyListPrototype::method_splice(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
503 ScopedObject instance(scope, thisObject->toObject(scope.engine));
506 QmlListWrapper *w = instance->as<QmlListWrapper>();
510 if (w->d()->hasDeadOwner())
513 QQmlListProperty<QObject> *property = w->d()->property();
515 if (!property->count)
516 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
517 const qsizetype len = property->count(property);
519 const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
522 start =
static_cast<qsizetype>(qMax(0., len + rs));
524 start =
static_cast<qsizetype>(qMin(rs,
static_cast<
double>(len)));
526 qsizetype deleteCount = 0;
527 qsizetype itemCount = 0;
529 deleteCount = len - start;
530 }
else if (argc > 1){
531 itemCount = argc - 2;
532 double dc = argv[1].toInteger();
533 deleteCount =
static_cast<qsizetype>(qMin(qMax(dc, 0.),
double(len - start)));
536 if (itemCount > deleteCount
537 && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
538 return scope.engine->throwTypeError();
541 if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
542 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
545 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
547 for (qsizetype i = 0; i < itemCount; ++i) {
548 const auto arg = argv[i + 2];
549 if (!arg.isNull() && !arg.as<QObjectWrapper>())
553 ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
554 newArray->arrayReserve(deleteCount);
555 ScopedValue v(scope);
556 QV4::ScopedValue wrappedObject(scope);
557 for (qsizetype i = 0; i < deleteCount; ++i) {
558 wrappedObject = QObjectWrapper::wrap(scope.engine, property->at(property, start + i));
562 newArray->setArrayLengthUnchecked(deleteCount);
564 if (!property->replace)
565 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
566 if (!property->removeLast)
567 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
568 if (!property->append)
569 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
571 if (itemCount < deleteCount) {
572 for (qsizetype k = start; k < len - deleteCount; ++k)
573 property->replace(property, k + itemCount, property->at(property, k + deleteCount));
574 for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
575 property->removeLast(property);
576 }
else if (itemCount > deleteCount) {
577 for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
578 property->append(property,
nullptr);
579 for (qsizetype k = len - deleteCount; k > start; --k) {
581 property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
585 const QMetaType elementType = w->d()->elementType();
586 const QMetaObject *elementMeta = elementType.metaObject();
587 for (qsizetype i = 0; i < itemCount; ++i) {
588 const auto arg = argv[i + 2];
590 property->replace(property, start + i,
nullptr);
594 QObject *object = arg.as<QObjectWrapper>()->object();
596 property->replace(property, start + i,
nullptr);
600 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
601 qCWarning(lcIncompatibleElement)
602 <<
"Cannot splice" << object <<
"into a QML list of" << elementType.name();
603 property->replace(property, start + i,
nullptr);
607 property->replace(property, start + i, object);
610 return newArray->asReturnedValue();
613ReturnedValue
PropertyListPrototype::method_unshift(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
616 ScopedObject instance(scope, thisObject->toObject(scope.engine));
620 QmlListWrapper *w = instance->as<QmlListWrapper>();
624 if (w->d()->hasDeadOwner())
627 QQmlListProperty<QObject> *property = w->d()->property();
629 if (!property->count)
630 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
631 const qsizetype len = property->count(property);
633 if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
634 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
636 if (!property->append)
637 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
638 if (!property->replace)
639 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
641 for (
int i = 0; i < argc; ++i) {
642 const auto arg = argv[i];
643 if (!arg.isNull() && !arg.as<QObjectWrapper>())
647 for (
int i = 0; i < argc; ++i)
648 property->append(property,
nullptr);
649 if (property->count(property) != argc + len)
650 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
652 for (qsizetype k = len; k > 0; --k)
653 property->replace(property, k + argc - 1, property->at(property, k - 1));
655 const QMetaType elementType = w->d()->elementType();
656 const QMetaObject *elementMeta = elementType.metaObject();
657 for (
int i = 0; i < argc; ++i) {
658 const auto *wrapper = argv[i].as<QObjectWrapper>();
659 QObject *object = wrapper ? wrapper->object() :
nullptr;
661 property->replace(property, i, object);
665 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
666 qCWarning(lcIncompatibleElement)
667 <<
"Cannot unshift" << object <<
"into a QML list of" << elementType.name();
668 property->replace(property, i,
nullptr);
672 property->replace(property, i, object);
675 return Encode(uint(len + argc));
687 QObject *searchValue;
688 if (argv[0].isNull()) {
689 searchValue =
nullptr;
691 Scoped<QObjectWrapper> wrapper(scope, argv[0]);
693 searchValue = wrapper->object();
698 ScopedObject instance(scope, thisObject->toObject(scope.engine));
702 QmlListWrapper *w = instance->as<QmlListWrapper>();
706 if (w->d()->hasDeadOwner())
709 QQmlListProperty<QObject> *property = w->d()->property();
711 if (!property->count)
712 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
713 const qsizetype len = property->count(property);
718 return iterate(scope.engine, property, len, searchValue);
721ReturnedValue
PropertyListPrototype::method_indexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
723 return firstOrLastIndexOf(
724 b, thisObject, argv, argc,
725 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
726 qsizetype len, QObject *searchValue) -> ReturnedValue {
727 qsizetype fromIndex = 0;
729 double f = argv[1].toInteger();
730 if (hasExceptionOrIsInterrupted(engine))
731 return Encode::undefined();
735 f = qMax(len + f, 0.);
736 fromIndex = qsizetype(f);
739 for (qsizetype i = fromIndex; i < len; ++i) {
740 if (property->at(property, i) == searchValue) {
741 if (qIsAtMostUintLimit(i))
742 return Encode(uint(i));
743 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
751ReturnedValue
PropertyListPrototype::method_lastIndexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
753 return firstOrLastIndexOf(
754 b, thisObject, argv, argc,
755 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
756 qsizetype len, QObject *searchValue) -> ReturnedValue {
757 qsizetype fromIndex = len - 1;
759 double f = argv[1].toInteger();
760 if (hasExceptionOrIsInterrupted(engine))
761 return Encode::undefined();
763 f = qMin(f, (
double)(len - 1));
769 fromIndex = qsizetype(f);
772 for (qsizetype i = fromIndex; i >= 0; --i) {
773 if (property->at(property, i) == searchValue) {
774 if (qIsAtMostUintLimit(i))
775 return Encode(uint(i));
776 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
784ReturnedValue
PropertyListPrototype::method_sort(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
787 ScopedObject instance(scope, thisObject->toObject(scope.engine));
791 QmlListWrapper *w = instance->as<QmlListWrapper>();
795 if (w->d()->hasDeadOwner())
798 QQmlListProperty<QObject> *property = w->d()->property();
800 if (!property->count)
801 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
802 if (property->count(property) == 0)
803 return thisObject->asReturnedValue();
805 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
806 if (!property->replace)
807 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
809 ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
810 if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
813 const ArrayElementLessThan lessThan(scope.engine, comparefn);
814 sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
815 Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
816 Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
817 return lessThan(o1, o2);
820 return thisObject->asReturnedValue();
848ReturnedValue
PropertyListPrototype::method_set_length(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
851 ScopedObject instance(scope, thisObject->toObject(scope.engine));
855 const QmlListWrapper *w = instance->as<QmlListWrapper>();
859 if (w->d()->hasDeadOwner())
862 QQmlListProperty<QObject> *property = w->d()->property();
865 const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
867 return scope.engine->throwRangeError(QString::fromLatin1(
"Invalid list length."));
869 if (newLength == 0 && property->clear) {
870 property->clear(property);
874 if (!property->count)
875 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
877 qsizetype count = property->count(property);
878 if (!qIsAtMostUintLimit(count))
879 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
881 if (newLength < uint(count)) {
882 if (!property->removeLast)
883 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
885 for (uint i = count; i > newLength; --i)
886 property->removeLast(property);
891 if (!property->append)
892 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
894 for (uint i = count; i < newLength; ++i)
895 property->append(property,
nullptr);
897 count = property->count(property);
898 if (!qIsAtMostUintLimit(count))
899 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
901 if (uint(count) != newLength)
902 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);