56 Heap::ArrayData *arrayData = object.arrayData();
58 const uint length = arrayData->length();
59 if (Q_UNLIKELY(length == std::numeric_limits<uint>::max())) {
60 object.scope.engine->throwRangeError(QLatin1String(
"Too many elements."));
64 ArrayData::realloc(object.object, Heap::ArrayData::Simple, length + 1,
false);
65 QV4::Scope scope(object.scope.engine);
66 QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(object.scope.engine, o));
67 arrayData->vtable()->put(
68 object.object, length, wrappedObject);
179ReturnedValue QmlListWrapper::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
181 Q_ASSERT(m->as<QmlListWrapper>());
182 const QmlListWrapper *w =
static_cast<
const QmlListWrapper *>(m);
183 QV4::ExecutionEngine *v4 = w->engine();
185 if (id.isArrayIndex()) {
186 const uint index = id.asArrayIndex();
187 const quint32 count = w->d()->property()->count
188 ? w->d()->property()->count(w->d()->property())
190 if (index < count && w->d()->property()->at) {
193 return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
197 *hasProperty =
false;
198 return Value::undefinedValue().asReturnedValue();
201 return Object::virtualGet(m, id, receiver, hasProperty);
212bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
214 Q_ASSERT(m->as<QmlListWrapper>());
216 const auto *w =
static_cast<
const QmlListWrapper *>(m);
217 QV4::ExecutionEngine *v4 = w->engine();
219 QQmlListProperty<QObject> *prop = w->d()->property();
221 if (id.isArrayIndex()) {
222 if (!prop->count || !prop->replace)
225 const uint index = id.asArrayIndex();
226 const int count = prop->count(prop);
227 if (count < 0 || index >= uint(count))
230 if (value.isNull()) {
231 prop->replace(prop, index,
nullptr);
235 QV4::Scope scope(v4);
236 QV4::ScopedObject so(scope, value.toObject(scope.engine));
237 if (
auto *wrapper = so->as<QV4::QObjectWrapper>()) {
238 QObject *object = wrapper->object();
240 prop->replace(prop, index, object);
244 const QMetaType elementType = w->d()->elementType();
245 const QMetaObject *elementMeta = elementType.metaObject();
246 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
247 qCWarning(lcIncompatibleElement)
248 <<
"Cannot insert" << object <<
"into a QML list of" << elementType.name();
249 prop->replace(prop, index,
nullptr);
253 prop->replace(prop, index, object);
260 return Object::virtualPut(m, id, value, receiver);
302 defineDefaultProperty(QStringLiteral(
"pop"), method_pop, 0);
303 defineDefaultProperty(QStringLiteral(
"push"), method_push, 1);
304 defineDefaultProperty(QStringLiteral(
"shift"), method_shift, 0);
305 defineDefaultProperty(QStringLiteral(
"splice"), method_splice, 2);
306 defineDefaultProperty(QStringLiteral(
"unshift"), method_unshift, 1);
307 defineDefaultProperty(QStringLiteral(
"indexOf"), method_indexOf, 1);
308 defineDefaultProperty(QStringLiteral(
"lastIndexOf"), method_lastIndexOf, 1);
309 defineDefaultProperty(QStringLiteral(
"sort"), method_sort, 1);
310 defineAccessorProperty(QStringLiteral(
"length"), method_get_length, method_set_length);
313ReturnedValue
PropertyListPrototype::method_pop(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
316 ScopedObject instance(scope, thisObject->toObject(scope.engine));
320 QmlListWrapper *w = instance->as<QmlListWrapper>();
324 QQmlListProperty<QObject> *property = w->d()->property();
326 if (!property->count)
327 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
328 const qsizetype len = property->count(property);
333 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
335 scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
337 if (!property->removeLast)
338 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
339 property->removeLast(property);
341 return result->asReturnedValue();
344ReturnedValue
PropertyListPrototype::method_push(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
347 ScopedObject instance(scope, thisObject->toObject(scope.engine));
350 QmlListWrapper *w = instance->as<QmlListWrapper>();
354 QQmlListProperty<QObject> *property = w->d()->property();
355 if (!property->append)
356 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
357 if (!property->count)
358 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
360 for (
int i = 0; i < argc; ++i) {
361 const Value &arg = argv[i];
362 if (!arg.isNull() && !arg.as<QObjectWrapper>())
366 const qsizetype length = property->count(property);
367 if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
368 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
370 const QMetaType elementType = w->d()->elementType();
371 const QMetaObject *elementMeta = elementType.metaObject();
372 for (
int i = 0; i < argc; ++i) {
373 if (argv[i].isNull()) {
374 property->append(property,
nullptr);
378 QObject *object = argv[i].as<QV4::QObjectWrapper>()->object();
380 property->append(property,
nullptr);
384 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
385 qCWarning(lcIncompatibleElement)
386 <<
"Cannot append" << object <<
"to a QML list of" << elementType.name();
387 property->append(property,
nullptr);
391 property->append(property, object);
394 const auto actualLength = property->count(property);
395 if (actualLength != length + argc)
396 qmlWarning(property->object) <<
"List didn't append all objects";
398 return Encode(uint(actualLength));
401ReturnedValue
PropertyListPrototype::method_shift(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
404 ScopedObject instance(scope, thisObject->toObject(scope.engine));
407 QmlListWrapper *w = instance->as<QmlListWrapper>();
411 QQmlListProperty<QObject> *property = w->d()->property();
413 if (!property->count)
414 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
415 const qsizetype len = property->count(property);
420 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
421 ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
423 if (!property->replace)
424 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
425 if (!property->removeLast)
426 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
428 for (qsizetype i = 1; i < len; ++i)
429 property->replace(property, i - 1, property->at(property, i));
430 property->removeLast(property);
432 return result->asReturnedValue();
435ReturnedValue
PropertyListPrototype::method_splice(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
438 ScopedObject instance(scope, thisObject->toObject(scope.engine));
441 QmlListWrapper *w = instance->as<QmlListWrapper>();
445 QQmlListProperty<QObject> *property = w->d()->property();
447 if (!property->count)
448 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
449 const qsizetype len = property->count(property);
451 const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
454 start =
static_cast<qsizetype>(qMax(0., len + rs));
456 start =
static_cast<qsizetype>(qMin(rs,
static_cast<
double>(len)));
458 qsizetype deleteCount = 0;
459 qsizetype itemCount = 0;
461 deleteCount = len - start;
462 }
else if (argc > 1){
463 itemCount = argc - 2;
464 double dc = argv[1].toInteger();
465 deleteCount =
static_cast<qsizetype>(qMin(qMax(dc, 0.),
double(len - start)));
468 if (itemCount > deleteCount
469 && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
470 return scope.engine->throwTypeError();
473 if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
474 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
477 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
479 for (qsizetype i = 0; i < itemCount; ++i) {
480 const auto arg = argv[i + 2];
481 if (!arg.isNull() && !arg.as<QObjectWrapper>())
485 ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
486 newArray->arrayReserve(deleteCount);
487 ScopedValue v(scope);
488 QV4::ScopedValue wrappedObject(scope);
489 for (qsizetype i = 0; i < deleteCount; ++i) {
490 wrappedObject = QObjectWrapper::wrap(scope.engine, property->at(property, start + i));
494 newArray->setArrayLengthUnchecked(deleteCount);
496 if (!property->replace)
497 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
498 if (!property->removeLast)
499 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
500 if (!property->append)
501 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
503 if (itemCount < deleteCount) {
504 for (qsizetype k = start; k < len - deleteCount; ++k)
505 property->replace(property, k + itemCount, property->at(property, k + deleteCount));
506 for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
507 property->removeLast(property);
508 }
else if (itemCount > deleteCount) {
509 for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
510 property->append(property,
nullptr);
511 for (qsizetype k = len - deleteCount; k > start; --k) {
513 property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
517 const QMetaType elementType = w->d()->elementType();
518 const QMetaObject *elementMeta = elementType.metaObject();
519 for (qsizetype i = 0; i < itemCount; ++i) {
520 const auto arg = argv[i + 2];
522 property->replace(property, start + i,
nullptr);
526 QObject *object = arg.as<QObjectWrapper>()->object();
528 property->replace(property, start + i,
nullptr);
532 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
533 qCWarning(lcIncompatibleElement)
534 <<
"Cannot splice" << object <<
"into a QML list of" << elementType.name();
535 property->replace(property, start + i,
nullptr);
539 property->replace(property, start + i, object);
542 return newArray->asReturnedValue();
545ReturnedValue
PropertyListPrototype::method_unshift(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
548 ScopedObject instance(scope, thisObject->toObject(scope.engine));
552 QmlListWrapper *w = instance->as<QmlListWrapper>();
556 QQmlListProperty<QObject> *property = w->d()->property();
558 if (!property->count)
559 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
560 const qsizetype len = property->count(property);
562 if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
563 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
565 if (!property->append)
566 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
567 if (!property->replace)
568 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
570 for (
int i = 0; i < argc; ++i) {
571 const auto arg = argv[i];
572 if (!arg.isNull() && !arg.as<QObjectWrapper>())
576 for (
int i = 0; i < argc; ++i)
577 property->append(property,
nullptr);
578 if (property->count(property) != argc + len)
579 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
581 for (qsizetype k = len; k > 0; --k)
582 property->replace(property, k + argc - 1, property->at(property, k - 1));
584 const QMetaType elementType = w->d()->elementType();
585 const QMetaObject *elementMeta = elementType.metaObject();
586 for (
int i = 0; i < argc; ++i) {
587 const auto *wrapper = argv[i].as<QObjectWrapper>();
588 QObject *object = wrapper ? wrapper->object() :
nullptr;
590 property->replace(property, i, object);
594 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
595 qCWarning(lcIncompatibleElement)
596 <<
"Cannot unshift" << object <<
"into a QML list of" << elementType.name();
597 property->replace(property, i,
nullptr);
601 property->replace(property, i, object);
604 return Encode(uint(len + argc));
616 QObject *searchValue;
617 if (argv[0].isNull()) {
618 searchValue =
nullptr;
620 Scoped<QObjectWrapper> wrapper(scope, argv[0]);
622 searchValue = wrapper->object();
627 ScopedObject instance(scope, thisObject->toObject(scope.engine));
631 QmlListWrapper *w = instance->as<QmlListWrapper>();
635 QQmlListProperty<QObject> *property = w->d()->property();
637 if (!property->count)
638 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
639 const qsizetype len = property->count(property);
644 return iterate(scope.engine, property, len, searchValue);
647ReturnedValue
PropertyListPrototype::method_indexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
649 return firstOrLastIndexOf(
650 b, thisObject, argv, argc,
651 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
652 qsizetype len, QObject *searchValue) -> ReturnedValue {
653 qsizetype fromIndex = 0;
655 double f = argv[1].toInteger();
656 if (hasExceptionOrIsInterrupted(engine))
657 return Encode::undefined();
661 f = qMax(len + f, 0.);
662 fromIndex = qsizetype(f);
665 for (qsizetype i = fromIndex; i < len; ++i) {
666 if (property->at(property, i) == searchValue) {
667 if (qIsAtMostUintLimit(i))
668 return Encode(uint(i));
669 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
677ReturnedValue
PropertyListPrototype::method_lastIndexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
679 return firstOrLastIndexOf(
680 b, thisObject, argv, argc,
681 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
682 qsizetype len, QObject *searchValue) -> ReturnedValue {
683 qsizetype fromIndex = len - 1;
685 double f = argv[1].toInteger();
686 if (hasExceptionOrIsInterrupted(engine))
687 return Encode::undefined();
689 f = qMin(f, (
double)(len - 1));
695 fromIndex = qsizetype(f);
698 for (qsizetype i = fromIndex; i >= 0; --i) {
699 if (property->at(property, i) == searchValue) {
700 if (qIsAtMostUintLimit(i))
701 return Encode(uint(i));
702 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
710ReturnedValue
PropertyListPrototype::method_sort(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
713 ScopedObject instance(scope, thisObject->toObject(scope.engine));
717 QmlListWrapper *w = instance->as<QmlListWrapper>();
721 QQmlListProperty<QObject> *property = w->d()->property();
723 if (!property->count)
724 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
725 if (property->count(property) == 0)
726 return thisObject->asReturnedValue();
728 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
729 if (!property->replace)
730 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
732 ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
733 if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
736 const ArrayElementLessThan lessThan(scope.engine, comparefn);
737 sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
738 Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
739 Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
740 return lessThan(o1, o2);
743 return thisObject->asReturnedValue();
768ReturnedValue
PropertyListPrototype::method_set_length(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
771 ScopedObject instance(scope, thisObject->toObject(scope.engine));
775 const QmlListWrapper *w = instance->as<QmlListWrapper>();
779 QQmlListProperty<QObject> *property = w->d()->property();
782 const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
784 return scope.engine->throwRangeError(QString::fromLatin1(
"Invalid list length."));
786 if (newLength == 0 && property->clear) {
787 property->clear(property);
791 if (!property->count)
792 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
794 qsizetype count = property->count(property);
795 if (!qIsAtMostUintLimit(count))
796 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
798 if (newLength < uint(count)) {
799 if (!property->removeLast)
800 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
802 for (uint i = count; i > newLength; --i)
803 property->removeLast(property);
808 if (!property->append)
809 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
811 for (uint i = count; i < newLength; ++i)
812 property->append(property,
nullptr);
814 count = property->count(property);
815 if (!qIsAtMostUintLimit(count))
816 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
818 if (uint(count) != newLength)
819 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);