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();
202ReturnedValue QmlListWrapper::virtualGet(
const Managed *m, PropertyKey id,
const Value *receiver,
bool *hasProperty)
204 Q_ASSERT(m->as<QmlListWrapper>());
205 const QmlListWrapper *w =
static_cast<
const QmlListWrapper *>(m);
206 QV4::ExecutionEngine *v4 = w->engine();
208 if (id.isArrayIndex()) {
209 const uint index = id.asArrayIndex();
210 const quint32 count = w->d()->property()->count
211 ? w->d()->property()->count(w->d()->property())
213 if (index < count && w->d()->property()->at) {
216 return QV4::QObjectWrapper::wrap(v4, w->d()->property()->at(w->d()->property(), index));
220 *hasProperty =
false;
221 return Value::undefinedValue().asReturnedValue();
224 return Object::virtualGet(m, id, receiver, hasProperty);
235bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id,
const Value &value, Value *receiver)
237 Q_ASSERT(m->as<QmlListWrapper>());
239 const auto *w =
static_cast<
const QmlListWrapper *>(m);
240 QV4::ExecutionEngine *v4 = w->engine();
242 QQmlListProperty<QObject> *prop = w->d()->property();
244 if (id.isArrayIndex()) {
245 if (!prop->count || !prop->replace)
248 const uint index = id.asArrayIndex();
249 const int count = prop->count(prop);
258 if (index >= uint(count)) {
262 for (uint times = uint(count); times < index; ++times)
263 prop->append(prop,
nullptr);
266 if (value.isNull()) {
267 prop->replace(prop, index,
nullptr);
271 QV4::Scope scope(v4);
272 QV4::ScopedObject so(scope, value.toObject(scope.engine));
273 if (
auto *wrapper = so->as<QV4::QObjectWrapper>()) {
274 QObject *object = wrapper->object();
276 prop->replace(prop, index, object);
280 const QMetaType elementType = w->d()->elementType();
281 const QMetaObject *elementMeta = elementType.metaObject();
282 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
283 qCWarning(lcIncompatibleElement)
284 <<
"Cannot insert" << object <<
"into a QML list of" << elementType.name();
285 prop->replace(prop, index,
nullptr);
289 prop->replace(prop, index, object);
296 return Object::virtualPut(m, id, value, receiver);
338 defineDefaultProperty(QStringLiteral(
"pop"), method_pop, 0);
339 defineDefaultProperty(QStringLiteral(
"push"), method_push, 1);
340 defineDefaultProperty(QStringLiteral(
"shift"), method_shift, 0);
341 defineDefaultProperty(QStringLiteral(
"splice"), method_splice, 2);
342 defineDefaultProperty(QStringLiteral(
"unshift"), method_unshift, 1);
343 defineDefaultProperty(QStringLiteral(
"indexOf"), method_indexOf, 1);
344 defineDefaultProperty(QStringLiteral(
"lastIndexOf"), method_lastIndexOf, 1);
345 defineDefaultProperty(QStringLiteral(
"sort"), method_sort, 1);
346 defineAccessorProperty(QStringLiteral(
"length"), method_get_length, method_set_length);
349ReturnedValue
PropertyListPrototype::method_pop(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
352 ScopedObject instance(scope, thisObject->toObject(scope.engine));
356 QmlListWrapper *w = instance->as<QmlListWrapper>();
360 QQmlListProperty<QObject> *property = w->d()->property();
362 if (!property->count)
363 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
364 const qsizetype len = property->count(property);
369 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
371 scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, len - 1)));
373 if (!property->removeLast)
374 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
375 property->removeLast(property);
377 return result->asReturnedValue();
380ReturnedValue
PropertyListPrototype::method_push(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
383 ScopedObject instance(scope, thisObject->toObject(scope.engine));
386 QmlListWrapper *w = instance->as<QmlListWrapper>();
390 QQmlListProperty<QObject> *property = w->d()->property();
391 if (!property->append)
392 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
393 if (!property->count)
394 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
396 for (
int i = 0; i < argc; ++i) {
397 const Value &arg = argv[i];
398 if (!arg.isNull() && !arg.as<QObjectWrapper>())
402 const qsizetype length = property->count(property);
403 if (!qIsAtMostUintLimit(length, std::numeric_limits<uint>::max() - argc))
404 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
406 const QMetaType elementType = w->d()->elementType();
407 const QMetaObject *elementMeta = elementType.metaObject();
408 for (
int i = 0; i < argc; ++i) {
409 if (argv[i].isNull()) {
410 property->append(property,
nullptr);
414 QObject *object = argv[i].as<QV4::QObjectWrapper>()->object();
416 property->append(property,
nullptr);
420 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
421 qCWarning(lcIncompatibleElement)
422 <<
"Cannot append" << object <<
"to a QML list of" << elementType.name();
423 property->append(property,
nullptr);
427 property->append(property, object);
430 const auto actualLength = property->count(property);
431 if (actualLength != length + argc)
432 qmlWarning(property->object) <<
"List didn't append all objects";
434 return Encode(uint(actualLength));
437ReturnedValue
PropertyListPrototype::method_shift(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
440 ScopedObject instance(scope, thisObject->toObject(scope.engine));
443 QmlListWrapper *w = instance->as<QmlListWrapper>();
447 QQmlListProperty<QObject> *property = w->d()->property();
449 if (!property->count)
450 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
451 const qsizetype len = property->count(property);
456 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
457 ScopedValue result(scope, QV4::QObjectWrapper::wrap(scope.engine, property->at(property, 0)));
459 if (!property->replace)
460 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
461 if (!property->removeLast)
462 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
464 for (qsizetype i = 1; i < len; ++i)
465 property->replace(property, i - 1, property->at(property, i));
466 property->removeLast(property);
468 return result->asReturnedValue();
471ReturnedValue
PropertyListPrototype::method_splice(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
474 ScopedObject instance(scope, thisObject->toObject(scope.engine));
477 QmlListWrapper *w = instance->as<QmlListWrapper>();
481 QQmlListProperty<QObject> *property = w->d()->property();
483 if (!property->count)
484 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
485 const qsizetype len = property->count(property);
487 const double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
490 start =
static_cast<qsizetype>(qMax(0., len + rs));
492 start =
static_cast<qsizetype>(qMin(rs,
static_cast<
double>(len)));
494 qsizetype deleteCount = 0;
495 qsizetype itemCount = 0;
497 deleteCount = len - start;
498 }
else if (argc > 1){
499 itemCount = argc - 2;
500 double dc = argv[1].toInteger();
501 deleteCount =
static_cast<qsizetype>(qMin(qMax(dc, 0.),
double(len - start)));
504 if (itemCount > deleteCount
505 && len > std::numeric_limits<qsizetype>::max() - itemCount + deleteCount) {
506 return scope.engine->throwTypeError();
509 if (!qIsAtMostUintLimit(deleteCount, std::numeric_limits<uint>::max() - 1))
510 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
513 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
515 for (qsizetype i = 0; i < itemCount; ++i) {
516 const auto arg = argv[i + 2];
517 if (!arg.isNull() && !arg.as<QObjectWrapper>())
521 ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
522 newArray->arrayReserve(deleteCount);
523 ScopedValue v(scope);
524 QV4::ScopedValue wrappedObject(scope);
525 for (qsizetype i = 0; i < deleteCount; ++i) {
526 wrappedObject = QObjectWrapper::wrap(scope.engine, property->at(property, start + i));
530 newArray->setArrayLengthUnchecked(deleteCount);
532 if (!property->replace)
533 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
534 if (!property->removeLast)
535 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
536 if (!property->append)
537 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
539 if (itemCount < deleteCount) {
540 for (qsizetype k = start; k < len - deleteCount; ++k)
541 property->replace(property, k + itemCount, property->at(property, k + deleteCount));
542 for (qsizetype k = len; k > len - deleteCount + itemCount; --k)
543 property->removeLast(property);
544 }
else if (itemCount > deleteCount) {
545 for (qsizetype k = 0; k < itemCount - deleteCount; ++k)
546 property->append(property,
nullptr);
547 for (qsizetype k = len - deleteCount; k > start; --k) {
549 property, k + itemCount - 1, property->at(property, k + deleteCount - 1));
553 const QMetaType elementType = w->d()->elementType();
554 const QMetaObject *elementMeta = elementType.metaObject();
555 for (qsizetype i = 0; i < itemCount; ++i) {
556 const auto arg = argv[i + 2];
558 property->replace(property, start + i,
nullptr);
562 QObject *object = arg.as<QObjectWrapper>()->object();
564 property->replace(property, start + i,
nullptr);
568 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
569 qCWarning(lcIncompatibleElement)
570 <<
"Cannot splice" << object <<
"into a QML list of" << elementType.name();
571 property->replace(property, start + i,
nullptr);
575 property->replace(property, start + i, object);
578 return newArray->asReturnedValue();
581ReturnedValue
PropertyListPrototype::method_unshift(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
584 ScopedObject instance(scope, thisObject->toObject(scope.engine));
588 QmlListWrapper *w = instance->as<QmlListWrapper>();
592 QQmlListProperty<QObject> *property = w->d()->property();
594 if (!property->count)
595 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
596 const qsizetype len = property->count(property);
598 if (std::numeric_limits<qsizetype>::max() - len < argc || !qIsAtMostUintLimit(len + argc))
599 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
601 if (!property->append)
602 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
603 if (!property->replace)
604 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
606 for (
int i = 0; i < argc; ++i) {
607 const auto arg = argv[i];
608 if (!arg.isNull() && !arg.as<QObjectWrapper>())
612 for (
int i = 0; i < argc; ++i)
613 property->append(property,
nullptr);
614 if (property->count(property) != argc + len)
615 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);
617 for (qsizetype k = len; k > 0; --k)
618 property->replace(property, k + argc - 1, property->at(property, k - 1));
620 const QMetaType elementType = w->d()->elementType();
621 const QMetaObject *elementMeta = elementType.metaObject();
622 for (
int i = 0; i < argc; ++i) {
623 const auto *wrapper = argv[i].as<QObjectWrapper>();
624 QObject *object = wrapper ? wrapper->object() :
nullptr;
626 property->replace(property, i, object);
630 if (Q_UNLIKELY(!elementMeta || !QQmlMetaObject::canConvert(object, elementMeta))) {
631 qCWarning(lcIncompatibleElement)
632 <<
"Cannot unshift" << object <<
"into a QML list of" << elementType.name();
633 property->replace(property, i,
nullptr);
637 property->replace(property, i, object);
640 return Encode(uint(len + argc));
652 QObject *searchValue;
653 if (argv[0].isNull()) {
654 searchValue =
nullptr;
656 Scoped<QObjectWrapper> wrapper(scope, argv[0]);
658 searchValue = wrapper->object();
663 ScopedObject instance(scope, thisObject->toObject(scope.engine));
667 QmlListWrapper *w = instance->as<QmlListWrapper>();
671 QQmlListProperty<QObject> *property = w->d()->property();
673 if (!property->count)
674 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
675 const qsizetype len = property->count(property);
680 return iterate(scope.engine, property, len, searchValue);
683ReturnedValue
PropertyListPrototype::method_indexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
685 return firstOrLastIndexOf(
686 b, thisObject, argv, argc,
687 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
688 qsizetype len, QObject *searchValue) -> ReturnedValue {
689 qsizetype fromIndex = 0;
691 double f = argv[1].toInteger();
692 if (hasExceptionOrIsInterrupted(engine))
693 return Encode::undefined();
697 f = qMax(len + f, 0.);
698 fromIndex = qsizetype(f);
701 for (qsizetype i = fromIndex; i < len; ++i) {
702 if (property->at(property, i) == searchValue) {
703 if (qIsAtMostUintLimit(i))
704 return Encode(uint(i));
705 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
713ReturnedValue
PropertyListPrototype::method_lastIndexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
715 return firstOrLastIndexOf(
716 b, thisObject, argv, argc,
717 [argc, argv](ExecutionEngine *engine, QQmlListProperty<QObject> *property,
718 qsizetype len, QObject *searchValue) -> ReturnedValue {
719 qsizetype fromIndex = len - 1;
721 double f = argv[1].toInteger();
722 if (hasExceptionOrIsInterrupted(engine))
723 return Encode::undefined();
725 f = qMin(f, (
double)(len - 1));
731 fromIndex = qsizetype(f);
734 for (qsizetype i = fromIndex; i >= 0; --i) {
735 if (property->at(property, i) == searchValue) {
736 if (qIsAtMostUintLimit(i))
737 return Encode(uint(i));
738 return engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
746ReturnedValue
PropertyListPrototype::method_sort(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
749 ScopedObject instance(scope, thisObject->toObject(scope.engine));
753 QmlListWrapper *w = instance->as<QmlListWrapper>();
757 QQmlListProperty<QObject> *property = w->d()->property();
759 if (!property->count)
760 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
761 if (property->count(property) == 0)
762 return thisObject->asReturnedValue();
764 return scope.engine->throwTypeError(u"List doesn't define an At function"_s);
765 if (!property->replace)
766 return scope.engine->throwTypeError(u"List doesn't define a Replace function"_s);
768 ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
769 if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
772 const ArrayElementLessThan lessThan(scope.engine, comparefn);
773 sortHelper(begin(*property), end(*property), [&](QObject *a, QObject *b) {
774 Scoped<QObjectWrapper> o1(scope, QObjectWrapper::wrap(scope.engine, a));
775 Scoped<QObjectWrapper> o2(scope, QObjectWrapper::wrap(scope.engine, b));
776 return lessThan(o1, o2);
779 return thisObject->asReturnedValue();
804ReturnedValue
PropertyListPrototype::method_set_length(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
807 ScopedObject instance(scope, thisObject->toObject(scope.engine));
811 const QmlListWrapper *w = instance->as<QmlListWrapper>();
815 QQmlListProperty<QObject> *property = w->d()->property();
818 const uint newLength = argc ? argv[0].asArrayLength(&ok) : 0;
820 return scope.engine->throwRangeError(QString::fromLatin1(
"Invalid list length."));
822 if (newLength == 0 && property->clear) {
823 property->clear(property);
827 if (!property->count)
828 return scope.engine->throwTypeError(u"List doesn't define a Count function"_s);
830 qsizetype count = property->count(property);
831 if (!qIsAtMostUintLimit(count))
832 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
834 if (newLength < uint(count)) {
835 if (!property->removeLast)
836 return scope.engine->throwTypeError(u"List doesn't define a RemoveLast function"_s);
838 for (uint i = count; i > newLength; --i)
839 property->removeLast(property);
844 if (!property->append)
845 return scope.engine->throwTypeError(u"List doesn't define an Append function"_s);
847 for (uint i = count; i < newLength; ++i)
848 property->append(property,
nullptr);
850 count = property->count(property);
851 if (!qIsAtMostUintLimit(count))
852 return scope.engine->throwRangeError(QString::fromLatin1(
"List length out of range."));
854 if (uint(count) != newLength)
855 return scope.engine->throwTypeError(u"List doesn't append null objects"_s);