55void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
58 ScopedObject o(scope);
59 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1));
60 ctor->defineReadonlyProperty(engine->id_prototype(), (o =
this));
61 ctor->defineDefaultProperty(QStringLiteral(
"isArray"), method_isArray, 1);
62 ctor->defineDefaultProperty(QStringLiteral(
"of"), method_of, 0);
63 ctor->defineDefaultProperty(QStringLiteral(
"from"), method_from, 1);
64 ctor->addSymbolSpecies();
66 Scoped<InternalClass> ic(scope, engine->classes[EngineBase::Class_Empty]
67 ->changeVTable(QV4::Object::staticVTable()));
68 ScopedObject unscopables(scope, engine->newObject(ic->d()));
69 ScopedString name(scope);
70 defineDefaultProperty(QStringLiteral(
"constructor"), (o = ctor));
71 defineDefaultProperty(engine->id_toString(), method_toString, 0);
72 defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0);
73 defineDefaultProperty(QStringLiteral(
"concat"), method_concat, 1);
74 name = engine->newIdentifier(QStringLiteral(
"copyWithin"));
75 unscopables->put(name, Value::fromBoolean(
true));
76 defineDefaultProperty(name, method_copyWithin, 2);
77 name = engine->newIdentifier(QStringLiteral(
"entries"));
78 unscopables->put(name, Value::fromBoolean(
true));
79 defineDefaultProperty(name, method_entries, 0);
80 name = engine->newIdentifier(QStringLiteral(
"fill"));
81 unscopables->put(name, Value::fromBoolean(
true));
82 defineDefaultProperty(name, method_fill, 1);
83 name = engine->newIdentifier(QStringLiteral(
"find"));
84 unscopables->put(name, Value::fromBoolean(
true));
85 defineDefaultProperty(name, method_find, 1);
86 name = engine->newIdentifier(QStringLiteral(
"findIndex"));
87 unscopables->put(name, Value::fromBoolean(
true));
88 defineDefaultProperty(name, method_findIndex, 1);
89 name = engine->newIdentifier(QStringLiteral(
"includes"));
90 unscopables->put(name, Value::fromBoolean(
true));
91 defineDefaultProperty(name, method_includes, 1);
92 defineDefaultProperty(QStringLiteral(
"join"), method_join, 1);
93 name = engine->newIdentifier(QStringLiteral(
"keys"));
94 unscopables->put(name, Value::fromBoolean(
true));
95 defineDefaultProperty(name, method_keys, 0);
96 defineDefaultProperty(QStringLiteral(
"pop"), method_pop, 0);
97 defineDefaultProperty(QStringLiteral(
"push"), method_push, 1);
98 defineDefaultProperty(QStringLiteral(
"reverse"), method_reverse, 0);
99 defineDefaultProperty(QStringLiteral(
"shift"), method_shift, 0);
100 defineDefaultProperty(QStringLiteral(
"slice"), method_slice, 2);
101 defineDefaultProperty(QStringLiteral(
"sort"), method_sort, 1);
102 defineDefaultProperty(QStringLiteral(
"splice"), method_splice, 2);
103 defineDefaultProperty(QStringLiteral(
"unshift"), method_unshift, 1);
104 defineDefaultProperty(QStringLiteral(
"indexOf"), method_indexOf, 1);
105 defineDefaultProperty(QStringLiteral(
"lastIndexOf"), method_lastIndexOf, 1);
106 defineDefaultProperty(QStringLiteral(
"every"), method_every, 1);
107 defineDefaultProperty(QStringLiteral(
"some"), method_some, 1);
108 defineDefaultProperty(QStringLiteral(
"forEach"), method_forEach, 1);
109 defineDefaultProperty(QStringLiteral(
"map"), method_map, 1);
110 defineDefaultProperty(QStringLiteral(
"filter"), method_filter, 1);
111 defineDefaultProperty(QStringLiteral(
"reduce"), method_reduce, 1);
112 defineDefaultProperty(QStringLiteral(
"reduceRight"), method_reduceRight, 1);
113 ScopedString valuesString(scope, engine->newIdentifier(QStringLiteral(
"values")));
114 ScopedObject values(scope, FunctionObject::createBuiltinFunction(engine, valuesString, method_values, 0));
115 engine->jsObjects[ExecutionEngine::ArrayProtoValues] = values;
116 unscopables->put(valuesString, Value::fromBoolean(
true));
117 defineDefaultProperty(valuesString, values);
118 defineDefaultProperty(engine->symbol_iterator(), values);
120 defineReadonlyConfigurableProperty(engine->symbol_unscopables(), unscopables);
148ReturnedValue ArrayPrototype::method_from(
const FunctionObject *builtin,
const Value *thisObject,
const Value *argv,
int argc)
150 Scope scope(builtin);
151 ScopedFunctionObject thatCtor(scope, thisObject);
152 ScopedObject itemsObject(scope, argv[0]);
153 bool usingIterator =
false;
157 ScopedValue it(scope, itemsObject->get(scope.engine->symbol_iterator()));
158 if (!it->isNullOrUndefined()) {
159 ScopedFunctionObject itfunc(scope, it);
161 return scope.engine->throwTypeError();
162 usingIterator =
true;
166 ScopedFunctionObject mapfn(scope, Value::undefinedValue());
167 Value *mapArguments =
nullptr;
169 mapfn = ScopedFunctionObject(scope, argv[1]);
171 return scope.engine->throwTypeError(QString::fromLatin1(
"%1 is not a function").arg(argv[1].toQStringNoThrow()));
172 mapArguments = scope.constructUndefined(2);
175 ScopedValue thisArg(scope);
181 ScopedObject a(createObjectFromCtorOrArray(scope, thatCtor,
false, 0));
183 ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject,
true));
186 return scope.engine->throwTypeError();
190 ScopedValue mappedValue(scope);
191 Value *nextValue = scope.constructUndefined(1);
192 ScopedValue done(scope);
197 if (k > (
static_cast<qint64>(1) << 53) - 1) {
198 ScopedValue error(scope, scope.engine->throwTypeError());
199 return Runtime::IteratorClose::call(scope.engine, iterator);
203 done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue));
205 if (done->toBoolean()) {
206 if (ArrayObject *ao = a->as<ArrayObject>()) {
207 ao->setArrayLengthUnchecked(k);
209 a->set(scope.engine->id_length(), Value::fromDouble(k), QV4::Object::DoThrowOnRejection);
212 return a.asReturnedValue();
216 Q_ASSERT(mapArguments);
217 mapArguments[0] = *nextValue;
218 mapArguments[1] = Value::fromDouble(k);
219 mappedValue = mapfn->call(thisArg, mapArguments, 2);
220 if (scope.hasException())
221 return Runtime::IteratorClose::call(scope.engine, iterator);
223 mappedValue = *nextValue;
226 if (a->getOwnProperty(PropertyKey::fromArrayIndex(k)) == Attr_Invalid) {
227 a->arraySet(k, mappedValue);
230 scope.engine->throwTypeError(QString::fromLatin1(
"Cannot redefine property: %1").arg(k));
233 if (scope.hasException())
234 return Runtime::IteratorClose::call(scope.engine, iterator);
243 ScopedObject arrayLike(scope, argv[0].toObject(scope.engine));
245 return scope.engine->throwTypeError(QString::fromLatin1(
"Cannot convert %1 to object").arg(argv[0].toQStringNoThrow()));
246 qint64 len = arrayLike->getLength();
247 ScopedObject a(createObjectFromCtorOrArray(scope, thatCtor,
true, len));
251 ScopedValue mappedValue(scope, Value::undefinedValue());
252 ScopedValue kValue(scope);
254 kValue = arrayLike->get(k);
258 Q_ASSERT(mapArguments);
259 mapArguments[0] = kValue;
260 mapArguments[1] = Value::fromDouble(k);
261 mappedValue = mapfn->call(thisArg, mapArguments, 2);
264 mappedValue = kValue;
267 if (a->getOwnProperty(PropertyKey::fromArrayIndex(k)) != Attr_Invalid)
268 return scope.engine->throwTypeError(QString::fromLatin1(
"Cannot redefine property: %1").arg(k));
270 a->arraySet(k, mappedValue);
276 if (ArrayObject *ao = a->as<ArrayObject>()) {
277 ao->setArrayLengthUnchecked(k);
279 a->set(scope.engine->id_length(), Value::fromDouble(k), QV4::Object::DoThrowOnRejection);
282 return a.asReturnedValue();
328ReturnedValue ArrayPrototype::method_toLocaleString(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
331 ScopedObject instance(scope, thisObject);
333 return scope.engine->throwTypeError();
335 qint64 len = instance->getLength();
336 const QString separator = QStringLiteral(
",");
340 ScopedValue v(scope);
341 ScopedString s(scope);
343 ScopedPropertyKey tolocaleString(scope, scope.engine->id_toLocaleString()->toPropertyKey());
344 Q_ASSERT(!scope.engine->hasException);
346 ScopedObject valueAsObject(scope);
347 ScopedFunctionObject function(scope);
349 for (qint64 k = 0; k < len; ++k) {
353 v = instance->get(k);
354 if (v->isNullOrUndefined())
357 valueAsObject = v->toObject(scope.engine);
358 Q_ASSERT(valueAsObject);
360 function = valueAsObject->get(tolocaleString);
362 return scope.engine->throwTypeError();
364 v = function->call(valueAsObject,
nullptr, 0);
365 if (scope.hasException())
366 return Encode::undefined();
368 s = v->toString(scope.engine);
369 if (scope.hasException())
370 return Encode::undefined();
374 return scope.engine->newString(R)->asReturnedValue();
377ReturnedValue ArrayPrototype::method_concat(
const FunctionObject *b,
const Value *that,
const Value *argv,
int argc)
380 ScopedObject thisObject(scope, that->toObject(scope.engine));
384 ScopedArrayObject result(scope, scope.engine->newArrayObject());
386 ScopedArrayObject elt(scope);
387 ScopedObject eltAsObj(scope);
388 ScopedValue entry(scope);
389 for (
int i = -1; i < argc; ++i) {
390 const Value *v = i == -1 ? thisObject.getPointer() : argv + i;
394 uint n = elt->getLength();
395 uint newLen = ArrayData::append(result, elt, n);
396 result->setArrayLengthUnchecked(newLen);
397 }
else if (eltAsObj && eltAsObj->isConcatSpreadable()) {
398 const uint startIndex = result->getLength();
399 const qint64 len = eltAsObj->getLength();
400 if (scope.hasException())
401 return Encode::undefined();
403 for (qint64 i = 0; i < len; ++i) {
404 bool hasProperty =
false;
405 entry = eltAsObj->get(i, &hasProperty);
407 if (!result->put(startIndex + i, entry))
408 return scope.engine->throwTypeError();
411 }
else if (eltAsObj && eltAsObj->isArrayLike()) {
412 const uint startIndex = result->getLength();
413 for (qint64 i = 0, len = eltAsObj->getLength(); i < len; ++i) {
414 entry = eltAsObj->get(i);
416 result->put(startIndex + i, entry);
419 result->arraySet(result->getLength(), *v);
423 return result.asReturnedValue();
426ReturnedValue ArrayPrototype::method_copyWithin(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
429 ScopedObject instance(scope, thisObject->toObject(scope.engine));
433 double len = instance->getLength();
434 double target = argv[0].toInteger();
435 double start = argc > 1 ? argv[1].toInteger() : 0;
438 if (argc > 2 && !argv[2].isUndefined()) {
439 end = argv[2].toInteger();
442 double relativeTarget = target;
443 double relativeStart = start;
444 double relativeEnd = end;
448 if (relativeTarget < 0) {
449 to = std::max(len+relativeTarget, 0.0);
451 to = std::min(relativeTarget, len);
453 if (relativeStart < 0) {
454 from = std::max(len+relativeStart, 0.0);
456 from = std::min(relativeStart, len);
460 if (relativeEnd < 0) {
461 fin = std::max(len+relativeEnd, 0.0);
463 fin = std::min(relativeEnd, len);
465 double count = std::min(fin-from, len-to);
466 double direction = 1;
467 if (from < to && to < from+count) {
469 from = from + count - 1;
473 ScopedValue fromVal(scope);
475 bool fromPresent =
false;
476 fromVal = instance->get(from, &fromPresent);
479 instance->setIndexed(to, fromVal, QV4::Object::DoThrowOnRejection);
482 bool didDelete = instance->deleteProperty(PropertyKey::fromArrayIndex(to));
485 return scope.engine->throwTypeError();
489 from = from + direction;
494 return instance.asReturnedValue();
577ReturnedValue ArrayPrototype::method_join(
const FunctionObject *functionObject,
578 const Value *thisObject,
const Value *argv,
int argc)
580 Scope scope(functionObject);
582 ScopedObject instance(scope, thisObject->toObject(scope.engine));
585 return Encode(scope.engine->newString());
589 ScopedValue argument(scope, argc ? argv[0] : Value::undefinedValue());
590 const QString separator = argument->isUndefined()
591 ? QStringLiteral(
",")
592 : argument->toQString();
594 ScopedValue scopedLength(scope, instance->get(scope.engine->id_length()));
595 const quint32 genericLength = scopedLength->isUndefined() ? 0 : scopedLength->toUInt32();
597 return Encode(scope.engine->newString());
600 if (
auto *arrayObject = instance->as<ArrayObject>()) {
601 ScopedValue entry(scope);
602 const qint64 arrayLength = arrayObject->getLength();
603 Q_ASSERT(arrayLength >= 0);
604 Q_ASSERT(arrayLength <= std::numeric_limits<quint32>::max());
605 for (quint32 i = 0; i < quint32(arrayLength); ++i) {
609 entry = arrayObject->get(i);
611 if (!entry->isNullOrUndefined())
612 result += entry->toQString();
615 ScopedString name(scope, scope.engine->newString(QStringLiteral(
"0")));
616 ScopedValue value(scope, instance->get(name));
619 if (!value->isNullOrUndefined())
620 result = value->toQString();
622 for (quint32 i = 1; i < genericLength; ++i) {
625 name = Value::fromDouble(i).toString(scope.engine);
626 value = instance->get(name);
629 if (!value->isNullOrUndefined())
630 result += value->toQString();
634 return Encode(scope.engine->newString(result));
637ReturnedValue ArrayPrototype::method_pop(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
640 ScopedObject instance(scope, thisObject->toObject(scope.engine));
644 qint64 len = instance->getLength();
647 if (!instance->isArrayObject())
648 instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromInt32(0)));
652 ScopedValue result(scope, instance->get(len - 1));
655 if (!instance->deleteProperty(PropertyKey::fromArrayIndex(len - 1)))
656 return scope.engine->throwTypeError();
658 if (instance->isArrayObject())
659 instance->setArrayLength(len - 1);
661 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(len - 1))))
662 return scope.engine->throwTypeError();
664 return result->asReturnedValue();
667ReturnedValue ArrayPrototype::method_push(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
670 ScopedObject instance(scope, thisObject->toObject(scope.engine));
674 instance->arrayCreate();
675 Q_ASSERT(instance->arrayData());
677 qint64 len = instance->getLength();
679 if (len + quint64(argc) >= UINT_MAX) {
682 ScopedString s(scope);
683 for (
int i = 0, ei = argc; i < ei; ++i) {
684 s = Value::fromDouble(l + i).toString(scope.engine);
685 if (!instance->put(s, argv[i]))
686 return scope.engine->throwTypeError();
688 double newLen = l + argc;
689 if (!instance->isArrayObject()) {
690 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(newLen))))
691 return scope.engine->throwTypeError();
693 ScopedString str(scope, scope.engine->newString(QStringLiteral(
"Array.prototype.push: Overflow")));
694 return scope.engine->throwRangeError(str);
696 return Encode(newLen);
701 else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) {
702 instance->arrayData()->vtable()->putArray(instance, len, argv, argc);
703 len = instance->arrayData()->length();
705 for (
int i = 0, ei = argc; i < ei; ++i) {
706 if (!instance->put(len + i, argv[i]))
707 return scope.engine->throwTypeError();
711 if (instance->isArrayObject())
712 instance->setArrayLengthUnchecked(len);
714 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(len))))
715 return scope.engine->throwTypeError();
718 return Encode(uint(len));
721ReturnedValue ArrayPrototype::method_reverse(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
724 ScopedObject instance(scope, thisObject->toObject(scope.engine));
728 qint64 length = instance->getLength();
730 if (length >= UINT_MAX)
731 return scope.engine->throwRangeError(QLatin1String(
"Array.prototype.reverse: Length out of range."));
733 int lo = 0, hi = length - 1;
735 ScopedValue lval(scope);
736 ScopedValue hval(scope);
737 for (; lo < hi; ++lo, --hi) {
738 bool loExists, hiExists;
739 lval = instance->get(lo, &loExists);
740 hval = instance->get(hi, &hiExists);
744 ok = instance->put(lo, hval);
746 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(lo));
749 ok = instance->put(hi, lval);
751 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(hi));
754 return scope.engine->throwTypeError();
756 return instance->asReturnedValue();
759ReturnedValue ArrayPrototype::method_shift(
const FunctionObject *b,
const Value *thisObject,
const Value *,
int)
762 ScopedObject instance(scope, thisObject->toObject(scope.engine));
766 instance->arrayCreate();
767 Q_ASSERT(instance->arrayData());
769 qint64 len = instance->getLength();
772 if (!instance->isArrayObject())
773 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromInt32(0))))
774 return scope.engine->throwTypeError();
778 ScopedValue result(scope);
779 if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) {
780 result = instance->arrayData()->vtable()->pop_front(instance);
782 result = instance->get(uint(0));
784 ScopedValue v(scope);
786 for (qint64 k = 1; k < len; ++k) {
788 v = instance->get(k, &exists);
792 ok = instance->put(k - 1, v);
794 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(k - 1));
796 return scope.engine->throwTypeError();
798 bool ok = instance->deleteProperty(PropertyKey::fromArrayIndex(len - 1));
800 return scope.engine->throwTypeError();
803 if (instance->isArrayObject())
804 instance->setArrayLengthUnchecked(len - 1);
806 bool ok = instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(len - 1)));
808 return scope.engine->throwTypeError();
811 return result->asReturnedValue();
858ReturnedValue ArrayPrototype::method_sort(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
864 ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
867 if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
868 return scope.engine->throwTypeError(QStringLiteral(
"The provided comparison function is not callable."));
871 ScopedObject instance(scope, thisObject->toObject(scope.engine));
876 qint64 len = instance->getLength();
878 if (instance->arrayData() && instance->arrayData()->length()) {
879 ArrayData::sort(scope.engine, instance, comparefn, len);
886 Value* sorted = scope.constructUndefined(scope.engine->safeForAllocLength(len));
890 for (uint index = 0; index < len; ++index) {
891 bool hasProperty =
false;
892 auto element = instance->get(index, &hasProperty);
895 sorted[written] = element;
900 std::stable_sort(sorted, sorted + written, ArrayElementLessThan(scope.engine, comparefn));
906 for (uint index = 0; index < written; ++index) {
907 instance->setIndexed(index, sorted[index], QV4::Object::DoThrowOnRejection);
915 while (written < len) {
916 if (!instance->deleteProperty(PropertyKey::fromArrayIndex(written)))
917 return scope.engine->throwTypeError();
923 return thisObject->asReturnedValue();
926ReturnedValue ArrayPrototype::method_splice(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
929 ScopedObject instance(scope, thisObject->toObject(scope.engine));
933 qint64 len = instance->getLength();
935 double rs = (argc ? argv[0] : Value::undefinedValue()).toInteger();
938 start =
static_cast<qint64>(qMax(0., len + rs));
940 start =
static_cast<qint64>(qMin(rs,
static_cast<
double>(len)));
942 qint64 deleteCount = 0;
943 qint64 itemCount = 0;
945 deleteCount = len - start;
946 }
else if (argc > 1){
947 itemCount = argc - 2;
948 double dc = argv[1].toInteger();
949 deleteCount =
static_cast<qint64>(qMin(qMax(dc, 0.),
double(len - start)));
952 if (len + itemCount - deleteCount > UINT_MAX - 1)
953 return scope.engine->throwTypeError();
954 if (deleteCount > UINT_MAX - 1)
955 return scope.engine->throwRangeError(QString::fromLatin1(
"Array length out of range."));
957 ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
958 newArray->arrayReserve(deleteCount);
959 ScopedValue v(scope);
960 for (uint i = 0; i < deleteCount; ++i) {
962 v = instance->get(start + i, &exists);
965 newArray->arrayPut(i, v);
967 newArray->setArrayLengthUnchecked(deleteCount);
970 if (itemCount < deleteCount) {
971 for (uint k = start; k < len - deleteCount; ++k) {
973 v = instance->get(k + deleteCount, &exists);
977 ok = instance->put(k + itemCount, v);
979 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(k + itemCount));
981 return scope.engine->throwTypeError();
983 for (uint k = len; k > len - deleteCount + itemCount; --k) {
984 if (!instance->deleteProperty(PropertyKey::fromArrayIndex(k - 1)))
985 return scope.engine->throwTypeError();
987 }
else if (itemCount > deleteCount) {
988 uint k = len - deleteCount;
991 v = instance->get(k + deleteCount - 1, &exists);
995 ok = instance->put(k + itemCount - 1, v);
997 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(k + itemCount - 1));
999 return scope.engine->throwTypeError();
1004 for (uint i = 0; i < itemCount; ++i)
1005 instance->put(start + i, argv[i + 2]);
1007 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(len - deleteCount + itemCount))))
1008 return scope.engine->throwTypeError();
1010 return newArray->asReturnedValue();
1013ReturnedValue ArrayPrototype::method_unshift(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1016 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1020 instance->arrayCreate();
1021 Q_ASSERT(instance->arrayData());
1023 qint64 len = instance->getLength();
1025 if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len &&
1026 instance->arrayData()->type != Heap::ArrayData::Custom) {
1027 instance->arrayData()->vtable()->push_front(instance, argv, argc);
1029 ScopedValue v(scope);
1030 for (qint64 k = len; k > 0; --k) {
1032 v = instance->get(k - 1, &exists);
1035 ok = instance->put(k + argc - 1, v);
1037 ok = instance->deleteProperty(PropertyKey::fromArrayIndex(k + argc - 1));
1039 return scope.engine->throwTypeError();
1041 for (
int i = 0, ei = argc; i < ei; ++i) {
1042 bool ok = instance->put(i, argv[i]);
1044 return scope.engine->throwTypeError();
1048 qint64 newLen = len + argc;
1049 if (instance->isArrayObject())
1050 instance->setArrayLengthUnchecked(newLen);
1052 if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Value::fromDouble(newLen))))
1053 return scope.engine->throwTypeError();
1056 return Encode(
double(newLen));
1098ReturnedValue ArrayPrototype::method_indexOf(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1101 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1105 qint64 len = instance->getLength();
1109 ScopedValue searchValue(scope, argc ? argv[0] : Value::undefinedValue());
1110 qint64 fromIndex = 0;
1113 double f = argv[1].toInteger();
1118 f = qMax(
double(len) + f, 0.);
1119 fromIndex = qint64(f);
1122 if (instance->isStringObject()) {
1123 ScopedValue v(scope);
1124 for (qint64 k = fromIndex; k < len; ++k) {
1126 v = instance->get(k, &exists);
1127 if (exists && RuntimeHelpers::strictEqual(v, searchValue))
1128 return Encode(
double(k));
1133 ScopedValue value(scope);
1135 if (ArgumentsObject::isNonStrictArgumentsObject(instance) ||
1136 (instance->arrayType() >= Heap::ArrayData::Sparse) || instance->protoHasArray()) {
1138 for (qint64 i = fromIndex; i < len; ++i) {
1140 value = instance->get(i, &exists);
1142 if (exists && RuntimeHelpers::strictEqual(value, searchValue))
1143 return Encode(
double(i));
1145 }
else if (!instance->arrayData()) {
1148 Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple);
1149 Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
1150 if (len > sa->values.size)
1151 len = sa->values.size;
1152 uint idx = fromIndex;
1154 value = sa->data(idx);
1156 if (RuntimeHelpers::strictEqual(value, searchValue))
1253ReturnedValue ArrayPrototype::method_fill(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1256 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1260 const qsizetype len = instance->getLength();
1263 const qsizetype relativeStart = argc > 1 ? argv[1].toInteger() : 0;
1264 qsizetype relativeEnd = len;
1265 if (argc > 2 && !argv[2].isUndefined())
1266 relativeEnd = argv[2].toInteger();
1271 if (relativeStart < 0) {
1272 if (relativeStart > -len)
1273 k = std::max(len + relativeStart, qsizetype(0));
1275 k = std::min(relativeStart, len);
1279 if (relativeEnd < 0) {
1280 if (relativeEnd > -len)
1281 fin = std::max(len + relativeEnd, qsizetype(0));
1283 fin = std::min(relativeEnd, len);
1287 if (
sizeof(qsizetype) >
sizeof(uint) && fin > qsizetype(std::numeric_limits<uint>::max()))
1288 return scope.engine->throwRangeError(QString::fromLatin1(
"Array length out of range."));
1290 for (; k < fin; ++k)
1291 instance->setIndexed(uint(k), argv[0], QV4::Object::DoThrowOnRejection);
1293 return instance.asReturnedValue();
1296ReturnedValue ArrayPrototype::method_some(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1299 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1303 qint64 len = instance->getLength();
1305 if (!argc || !argv->isFunctionObject())
1307 const FunctionObject *callback =
static_cast<
const FunctionObject *>(argv);
1309 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
1310 ScopedValue result(scope);
1311 Value *arguments = scope.constructUndefined(3);
1313 for (qint64 k = 0; k < len; ++k) {
1315 arguments[0] = instance->get(k, &exists);
1319 arguments[1] = Value::fromDouble(k);
1320 arguments[2] = instance;
1321 result = callback->call(that, arguments, 3);
1323 if (result->toBoolean())
1324 return Encode(
true);
1326 return Encode(
false);
1358ReturnedValue ArrayPrototype::method_map(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1361 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1365 qint64 len = instance->getLength();
1367 if (!argc || !argv->isFunctionObject())
1369 const FunctionObject *callback =
static_cast<
const FunctionObject *>(argv);
1371 if (len > UINT_MAX - 1)
1372 return scope.engine->throwRangeError(QString::fromLatin1(
"Array length out of range."));
1374 ScopedArrayObject a(scope, scope.engine->newArrayObject());
1375 a->arrayReserve(len);
1376 a->setArrayLengthUnchecked(len);
1378 ScopedValue v(scope);
1379 ScopedValue mapped(scope);
1380 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
1381 Value *arguments = scope.constructUndefined(3);
1383 for (uint k = 0; k < len; ++k) {
1385 arguments[0] = instance->get(k, &exists);
1389 arguments[1] = Value::fromDouble(k);
1390 arguments[2] = instance;
1391 mapped = callback->call(that, arguments, 3);
1393 a->arraySet(k, mapped);
1395 return a.asReturnedValue();
1398ReturnedValue ArrayPrototype::method_filter(
const FunctionObject *b,
const Value *thisObject,
const Value *argv,
int argc)
1401 ScopedObject instance(scope, thisObject->toObject(scope.engine));
1405 qint64 len = instance->getLength();
1407 if (!argc || !argv->isFunctionObject())
1409 const FunctionObject *callback =
static_cast<
const FunctionObject *>(argv);
1411 ScopedArrayObject a(scope, scope.engine->newArrayObject());
1412 a->arrayReserve(len);
1414 ScopedValue selected(scope);
1415 ScopedValue that(scope, argc > 1 ? argv[1] : Value::undefinedValue());
1416 Value *arguments = scope.constructUndefined(3);
1419 for (qint64 k = 0; k < len; ++k) {
1421 arguments[0] = instance->get(k, &exists);
1425 arguments[1] = Value::fromDouble(k);
1426 arguments[2] = instance;
1427 selected = callback->call(that, arguments, 3);
1429 if (selected->toBoolean()) {
1430 a->arraySet(to, arguments[0]);
1434 return a.asReturnedValue();