This allows simplifications of the code moving forward.
Change-Id: If65809fd3646e6dc2da6bc62190d6465b1b1ec12
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
return object;
}
-ArrayObject *ExecutionEngine::newArrayObject(ExecutionContext *ctx, const Array &value)
-{
- ArrayObject *object = new (memoryManager) ArrayObject(ctx, value);
- object->prototype = arrayPrototype;
- return object;
-}
-
Object *ExecutionEngine::newDateObject(const Value &value)
{
Object *object = new (memoryManager) DateObject(value);
Object *newFunctionObject(ExecutionContext *ctx);
ArrayObject *newArrayObject(ExecutionContext *ctx);
- ArrayObject *newArrayObject(ExecutionContext *ctx, const Array &value);
+// ArrayObject *newArrayObject(ExecutionContext *ctx, const Array &value);
Object *newDateObject(const Value &value);
Object *o = object.objectValue();
if (idx < UINT_MAX) {
- const PropertyDescriptor *p = o->array.nonSparseArrayAt(idx);
+ const PropertyDescriptor *p = o->nonSparseArrayAt(idx);
if (p && p->type == PropertyDescriptor::Data)
return p->value;
uint idx = index.asArrayIndex();
if (idx < UINT_MAX) {
- PropertyDescriptor *p = o->array.nonSparseArrayAtRef(idx);
+ PropertyDescriptor *p = o->nonSparseArrayAtRef(idx);
if (p && p->type == PropertyDescriptor::Data && p->isWritable()) {
p->value = value;
return;
bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc)
{
- PropertyDescriptor *pd = array.arrayAt(index);
+ PropertyDescriptor *pd = arrayAt(index);
PropertyDescriptor map;
bool isMapped = false;
if (pd && index < (uint)mappedArguments.size())
return createNode(s, y, left);
}
-Array::Array(const Array &other)
- : arrayLen(other.arrayLen)
- , arrayObject(0)
- , arrayData(other.arrayData)
- , sparseArray(0)
-{
- arrayFreeList = other.arrayFreeList;
- if (other.sparseArray)
- sparseArray = new SparseArray(*other.sparseArray);
-}
-
-
-Value Array::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
-{
- bool protoHasArray = false;
- Object *p = o;
- while ((p = p->prototype))
- if (p->array.arrayLength())
- protoHasArray = true;
-
- if (protoHasArray) {
- // lets be safe and slow
- for (uint i = fromIndex; i < endIndex; ++i) {
- bool exists;
- Value value = o->__get__(ctx, i, &exists);
- if (exists && __qmljs_strict_equal(value, v))
- return Value::fromDouble(i);
- }
- } else if (sparseArray) {
- for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n && n->key() < endIndex; n = n->nextNode()) {
- bool exists;
- Value value = o->getValueChecked(ctx, arrayDecriptor(n->value), &exists);
- if (exists && __qmljs_strict_equal(value, v))
- return Value::fromDouble(n->key());
- }
- } else {
- if ((int) endIndex > arrayData.size())
- endIndex = arrayData.size();
- PropertyDescriptor *pd = arrayData.data() + arrayOffset;
- PropertyDescriptor *end = pd + endIndex;
- pd += fromIndex;
- while (pd < end) {
- bool exists;
- Value value = o->getValueChecked(ctx, pd, &exists);
- if (exists && __qmljs_strict_equal(value, v))
- return Value::fromDouble(pd - arrayOffset - arrayData.constData());
- ++pd;
- }
- }
- return Value::fromInt32(-1);
-}
-
-void Array::arrayConcat(const Array &other)
-{
- initSparse();
- int newLen = arrayLen + other.arrayLength();
- if (other.sparseArray)
- initSparse();
- if (sparseArray) {
- if (other.sparseArray) {
- for (const SparseArrayNode *it = other.sparseArray->begin(); it != other.sparseArray->end(); it = it->nextNode())
- arraySet(arrayLen + it->key(), other.arrayDecriptor(it->value));
- } else {
- int oldSize = arrayData.size();
- arrayData.resize(oldSize + other.arrayLength());
- memcpy(arrayData.data() + oldSize, other.arrayData.constData() + other.arrayOffset, other.arrayLength()*sizeof(PropertyDescriptor));
- for (uint i = 0; i < other.arrayLength(); ++i) {
- SparseArrayNode *n = sparseArray->insert(arrayLen + i);
- n->value = oldSize + i;
- }
- }
- } else {
- int oldSize = arrayData.size();
- arrayData.resize(oldSize + other.arrayLength());
- memcpy(arrayData.data() + oldSize, other.arrayData.constData() + other.arrayOffset, other.arrayLength()*sizeof(PropertyDescriptor));
- }
- setArrayLengthUnchecked(newLen);
-}
-
-void Array::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
-{
- if (sparseArray) {
- context->throwUnimplemented("Array::sort unimplemented for sparse arrays");
- return;
- delete sparseArray;
- }
-
- ArrayElementLessThan lessThan(context, thisObject, comparefn);
- if (len > arrayData.size() - arrayOffset)
- len = arrayData.size() - arrayOffset;
- PropertyDescriptor *begin = arrayData.begin() + arrayOffset;
- std::sort(begin, begin + len, lessThan);
-}
-
-
-void Array::initSparse()
-{
- if (!sparseArray) {
- sparseArray = new SparseArray;
- for (int i = arrayOffset; i < arrayData.size(); ++i) {
- SparseArrayNode *n = sparseArray->insert(i - arrayOffset);
- n->value = i;
- }
-
- if (arrayOffset) {
- int o = arrayOffset;
- for (int i = 0; i < o - 1; ++i) {
- arrayData[i].type = PropertyDescriptor::Generic;
- arrayData[i].value = Value::fromInt32(i + 1);
- }
- arrayData[o - 1].type = PropertyDescriptor::Generic;
- arrayData[o - 1].value = Value::fromInt32(arrayData.size());
- arrayFreeList = 0;
- } else {
- arrayFreeList = arrayData.size();
- }
- }
-}
-
-void Array::setArrayLengthUnchecked(uint l)
-{
- arrayLen = l;
- if (arrayObject) {
- // length is always the first property of an array
- PropertyDescriptor &lengthProperty = arrayObject->memberData[ArrayObject::LengthPropertyIndex];
- lengthProperty.value = Value::fromUInt32(l);
- }
-}
-
-bool Array::setArrayLength(uint newLen) {
- const PropertyDescriptor *lengthProperty = arrayObject->memberData.constData() + ArrayObject::LengthPropertyIndex;
- if (lengthProperty && !lengthProperty->isWritable())
- return false;
- uint oldLen = arrayLength();
- bool ok = true;
- if (newLen < oldLen) {
- if (sparseArray) {
- SparseArrayNode *begin = sparseArray->lowerBound(newLen);
- SparseArrayNode *it = sparseArray->end()->previousNode();
- while (1) {
- PropertyDescriptor &pd = arrayData[it->value];
- if (pd.type != PropertyDescriptor::Generic && !pd.isConfigurable()) {
- ok = false;
- newLen = it->key() + 1;
- break;
- }
- pd.type = PropertyDescriptor::Generic;
- pd.value.tag = Value::_Undefined_Type;
- pd.value.int_32 = arrayFreeList;
- arrayFreeList = it->value;
- bool brk = (it == begin);
- SparseArrayNode *prev = it->previousNode();
- sparseArray->erase(it);
- if (brk)
- break;
- it = prev;
- }
- } else {
- PropertyDescriptor *it = arrayData.data() + arrayData.size();
- const PropertyDescriptor *begin = arrayData.constData() + arrayOffset + newLen;
- while (--it >= begin) {
- if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
- ok = false;
- newLen = it - arrayData.data() + arrayOffset + 1;
- break;
- }
- }
- arrayData.resize(newLen + arrayOffset);
- }
- } else {
- if (newLen >= 0x100000)
- initSparse();
- }
- setArrayLengthUnchecked(newLen);
- return ok;
-}
-
-void Array::markArrayObjects() const
-{
- uint i = sparseArray ? 0 : arrayOffset;
- for (; i < (uint)arrayData.size(); ++i) {
- const PropertyDescriptor &pd = arrayData.at(i);
- if (pd.isData()) {
- if (Managed *m = pd.value.asManaged())
- m->mark();
- } else if (pd.isAccessor()) {
- if (pd.get)
- pd.get->mark();
- if (pd.set)
- pd.set->mark();
- }
- }
-}
}
}
return ub;
}
-
-class Array
-{
- friend struct ArrayPrototype;
-
- uint arrayLen;
- ArrayObject *arrayObject;
- union {
- uint arrayFreeList;
- uint arrayOffset;
- };
- QVector<PropertyDescriptor> arrayData;
- SparseArray *sparseArray;
-
- void fillDescriptor(PropertyDescriptor *pd, Value v)
- {
- pd->type = PropertyDescriptor::Data;
- pd->writable = PropertyDescriptor::Enabled;
- pd->enumberable = PropertyDescriptor::Enabled;
- pd->configurable = PropertyDescriptor::Enabled;
- pd->value = v;
- }
-
- uint allocArrayValue() {
- uint idx = arrayFreeList;
- if (arrayData.size() <= (int)arrayFreeList)
- arrayData.resize(++arrayFreeList);
- else
- arrayFreeList = arrayData.at(arrayFreeList).value.integerValue();
- return idx;
- }
-
- uint allocArrayValue(Value v) {
- uint idx = allocArrayValue();
- PropertyDescriptor *pd = &arrayData[idx];
- fillDescriptor(pd, v);
- return idx;
- }
- void freeArrayValue(int idx) {
- PropertyDescriptor &pd = arrayData[idx];
- pd.type = PropertyDescriptor::Generic;
- pd.value.tag = Value::_Undefined_Type;
- pd.value.int_32 = arrayFreeList;
- arrayFreeList = idx;
- }
-
- PropertyDescriptor *arrayDecriptor(uint index) {
- PropertyDescriptor *pd = arrayData.data() + index;
- if (!sparseArray)
- pd += arrayOffset;
- return pd;
- }
- const PropertyDescriptor *arrayDecriptor(uint index) const {
- const PropertyDescriptor *pd = arrayData.data() + index;
- if (!sparseArray)
- pd += arrayOffset;
- return pd;
- }
-
- void getArrayHeadRoom() {
- assert(!sparseArray && !arrayOffset);
- arrayOffset = qMax(arrayData.size() >> 2, 16);
- QVector<PropertyDescriptor> newValues(arrayData.size() + arrayOffset);
- memcpy(newValues.data() + arrayOffset, arrayData.constData(), arrayData.size()*sizeof(PropertyDescriptor));
- arrayData = newValues;
- }
-
-public:
- Array() : arrayLen(0), arrayObject(0), arrayOffset(0), sparseArray(0) {}
- Array(const Array &other);
- ~Array() { delete sparseArray; }
- void initSparse();
-
- uint arrayLength() const { return arrayLen; }
- bool setArrayLength(uint newLen);
-
- void setArrayObject(ArrayObject *a) { arrayObject = a; }
-
- void setArrayLengthUnchecked(uint l);
-
- PropertyDescriptor *arrayInsert(uint index) {
- PropertyDescriptor *pd;
- if (!sparseArray && (index < 0x1000 || index < arrayLen + (arrayLen >> 2))) {
- if (index + arrayOffset >= (uint)arrayData.size()) {
- arrayData.resize(arrayOffset + index + 1);
- for (uint i = arrayLen + 1; i < index; ++i) {
- arrayData[i].type = PropertyDescriptor::Generic;
- arrayData[i].value.tag = Value::_Undefined_Type;
- }
- }
- pd = arrayDecriptor(index);
- } else {
- initSparse();
- SparseArrayNode *n = sparseArray->insert(index);
- if (n->value == UINT_MAX)
- n->value = allocArrayValue();
- pd = arrayDecriptor(n->value);
- }
- if (index >= arrayLen)
- setArrayLengthUnchecked(index + 1);
- return pd;
- }
-
- void arraySet(uint index, const PropertyDescriptor *pd) {
- *arrayInsert(index) = *pd;
- }
-
- void arraySet(uint index, Value value) {
- PropertyDescriptor *pd = arrayInsert(index);
- fillDescriptor(pd, value);
- }
-
- bool deleteArrayIndex(uint index) {
- if (index >= arrayLen)
- return true;
- PropertyDescriptor *pd = 0;
- if (!sparseArray) {
- pd = arrayAt(index);
- } else {
- SparseArrayNode *n = sparseArray->findNode(index);
- if (n)
- pd = arrayDecriptor(n->value);
- }
- if (!pd || pd->type == PropertyDescriptor::Generic)
- return true;
- if (!pd->isConfigurable())
- return false;
- pd->type = PropertyDescriptor::Generic;
- pd->value.tag = Value::_Undefined_Type;
- if (sparseArray) {
- pd->value.int_32 = arrayFreeList;
- arrayFreeList = pd - arrayData.constData();
- }
- return true;
- }
-
- PropertyDescriptor *arrayAt(uint index) {
- if (!sparseArray) {
- if (index >= arrayData.size() - arrayOffset)
- return 0;
- return arrayData.data() + index + arrayOffset;
- } else {
- SparseArrayNode *n = sparseArray->findNode(index);
- if (!n)
- return 0;
- return arrayData.data() + n->value;
- }
- }
-
- const PropertyDescriptor *nonSparseArrayAt(uint index) const {
- if (sparseArray)
- return 0;
- index += arrayOffset;
- if (index >= (uint)arrayData.size())
- return 0;
- return arrayData.constData() + index;
- }
-
- PropertyDescriptor *nonSparseArrayAtRef(uint index) {
- if (sparseArray)
- return 0;
- index += arrayOffset;
- if (index >= (uint)arrayData.size())
- return 0;
- return arrayData.data() + index;
- }
-
- const PropertyDescriptor *arrayAt(uint index) const {
- if (!sparseArray) {
- if (index >= arrayData.size() - arrayOffset)
- return 0;
- return arrayData.constData() + index + arrayOffset;
- } else {
- SparseArrayNode *n = sparseArray->findNode(index);
- if (!n)
- return 0;
- return arrayData.constData() + n->value;
- }
- }
-
- void markArrayObjects() const;
-
- void push_front(Value v) {
- if (!sparseArray) {
- if (!arrayOffset)
- getArrayHeadRoom();
-
- --arrayOffset;
- PropertyDescriptor &pd = values[offset];
- fillDescriptor(&pd, v);
- } else {
- uint idx = allocArrayValue(v);
- sparseArray->push_front(idx);
- }
- setArrayLengthUnchecked(arrayLen + 1);
- }
- PropertyDescriptor *front() {
- PropertyDescriptor *pd = 0;
- if (!sparseArray) {
- if (arrayLen)
- pd = arrayData.data() + arrayOffset;
- } else {
- SparseArrayNode *n = sparseArray->findNode(0);
- if (n)
- pd = arrayDecriptor(n->value);
- }
- if (pd && pd->type == PropertyDescriptor::Generic)
- return 0;
- return pd;
- }
- void pop_front() {
- if (!arrayLen)
- return;
- if (!sparseArray) {
- ++arrayOffset;
- } else {
- uint idx = sparseArray->pop_front();
- freeArrayValue(idx);
- }
- setArrayLengthUnchecked(arrayLen - 1);
- }
- void push_back(Value v) {
- if (!sparseArray) {
- PropertyDescriptor pd;
- fillDescriptor(&pd, v);
- arrayData.append(pd);
- } else {
- uint idx = allocArrayValue(v);
- sparseArray->push_back(idx, arrayLen);
- }
- setArrayLengthUnchecked(arrayLen + 1);
- }
- PropertyDescriptor *back() {
- PropertyDescriptor *pd = 0;
- if (!sparseArray) {
- if (arrayLen)
- pd = arrayData.data() + arrayOffset + arrayLen;
- } else {
- SparseArrayNode *n = sparseArray->findNode(arrayLen - 1);
- if (n)
- pd = arrayDecriptor(n->value);
- }
- if (pd && pd->type == PropertyDescriptor::Generic)
- return 0;
- return pd;
- }
- void pop_back() {
- if (!arrayLen)
- return;
- if (!sparseArray) {
- arrayData.resize(arrayData.size() - 1);
- } else {
- uint idx = sparseArray->pop_back(arrayLen);
- if (idx != UINT_MAX)
- freeArrayValue(idx);
- }
- setArrayLengthUnchecked(arrayLen - 1);
- }
-
- SparseArrayNode *sparseArrayLowerBound(uint idx) { return sparseArray ? sparseArray->lowerBound(idx) : 0; }
- SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
- SparseArrayNode *sparseArrayEnd() { return sparseArray ? sparseArray->end() : 0; }
-
- void arrayConcat(const Array &other);
- void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayLen);
- Value arrayIndexOf(Value v, uint fromIndex, uint arrayLen, ExecutionContext *ctx, Object *o);
-};
-
}
}
Value ArrayCtor::call(ExecutionContext *ctx)
{
ArrayObject *a = ctx->engine->newArrayObject(ctx);
- Array &value = a->array;
+ uint len;
if (ctx->argumentCount == 1 && ctx->argument(0).isNumber()) {
bool ok;
- uint len = ctx->argument(0).asArrayLength(ctx, &ok);
+ len = ctx->argument(0).asArrayLength(ctx, &ok);
if (!ok) {
ctx->throwRangeError(ctx->argument(0));
return Value::undefinedValue();
}
- value.setArrayLengthUnchecked(len);
} else {
- for (unsigned int i = 0; i < ctx->argumentCount; ++i) {
- value.arraySet(i, ctx->argument(i));
+ len = ctx->argumentCount;
+ for (unsigned int i = 0; i < len; ++i) {
+ a->arraySet(i, ctx->argument(i));
}
}
+ a->setArrayLengthUnchecked(len);
return Value::fromObject(a);
}
uint ArrayPrototype::getLength(ExecutionContext *ctx, Object *o)
{
if (o->isArrayObject())
- return o->array.arrayLength();
+ return o->arrayLength();
return o->__get__(ctx, ctx->engine->id_length).toUInt32(ctx);
}
Value ArrayPrototype::method_concat(ExecutionContext *ctx)
{
- Array result;
+ ArrayObject *result = ctx->engine->newArrayObject(ctx);
- if (ArrayObject *instance = ctx->thisObject.asArrayObject())
- result = instance->array;
- else {
+ if (ArrayObject *instance = ctx->thisObject.asArrayObject()) {
+ result->copyArrayData(instance);
+ } else {
QString v = ctx->thisObject.toString(ctx)->toQString();
- result.arraySet(0, Value::fromString(ctx, v));
+ result->arraySet(0, Value::fromString(ctx, v));
}
for (uint i = 0; i < ctx->argumentCount; ++i) {
- quint32 k = result.arrayLength();
+ quint32 k = result->arrayLength();
Value arg = ctx->argument(i);
if (ArrayObject *elt = arg.asArrayObject())
- result.arrayConcat(elt->array);
+ result->arrayConcat(elt);
else
- result.arraySet(k, arg);
+ result->arraySet(k, arg);
}
- return Value::fromObject(ctx->engine->newArrayObject(ctx, result));
+ return Value::fromObject(result);
}
Value ArrayPrototype::method_join(ExecutionContext *ctx)
// ### FIXME
if (ArrayObject *a = self.asArrayObject()) {
- for (uint i = 0; i < a->array.arrayLength(); ++i) {
+ for (uint i = 0; i < a->arrayLength(); ++i) {
if (i)
R += r4;
instance->__delete__(ctx, len - 1);
if (instance->isArrayObject())
- instance->array.setArrayLengthUnchecked(len - 1);
+ instance->setArrayLengthUnchecked(len - 1);
else
instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len - 1));
return result;
bool protoHasArray = false;
Object *p = instance;
while ((p = p->prototype))
- if (p->array.arrayLength())
+ if (p->arrayLength())
protoHasArray = true;
- if (!protoHasArray && len == instance->array.arrayLength()) {
+ if (!protoHasArray && len == instance->arrayLength()) {
for (uint i = 0; i < ctx->argumentCount; ++i) {
Value v = ctx->argument(i);
- instance->array.push_back(v);
+ instance->push_back(v);
}
} else {
for (uint i = 0; i < ctx->argumentCount; ++i)
return Value::undefinedValue();
}
- Value result = instance->getValueChecked(ctx, instance->array.front());
+ Value result = instance->getValueChecked(ctx, instance->front());
bool protoHasArray = false;
Object *p = instance;
while ((p = p->prototype))
- if (p->array.arrayLength())
+ if (p->arrayLength())
protoHasArray = true;
- if (!protoHasArray && len >= instance->array.arrayLength()) {
- instance->array.pop_front();
+ if (!protoHasArray && len >= instance->arrayLength()) {
+ instance->pop_front();
} else {
// do it the slow way
for (uint k = 1; k < len; ++k) {
{
Object *o = ctx->thisObject.toObject(ctx).objectValue();
- Array result;
+ ArrayObject *result = ctx->engine->newArrayObject(ctx);
uint len = o->__get__(ctx, ctx->engine->id_length).toUInt32(ctx);
double s = ctx->argument(0).toInteger(ctx);
uint start;
bool exists;
Value v = o->__get__(ctx, i, &exists);
if (exists)
- result.arraySet(n, v);
+ result->arraySet(n, v);
++n;
}
- return Value::fromObject(ctx->engine->newArrayObject(ctx, result));
+ return Value::fromObject(result);
}
Value ArrayPrototype::method_sort(ExecutionContext *ctx)
uint len = getLength(ctx, instance);
Value comparefn = ctx->argument(0);
- instance->array.arraySort(ctx, instance, comparefn, len);
+ instance->arraySort(ctx, instance, comparefn, len);
return ctx->thisObject;
}
uint deleteCount = (uint)qMin(qMax(ctx->argument(1).toInteger(ctx), 0.), (double)(len - start));
- newArray->array.arrayData.resize(deleteCount);
- PropertyDescriptor *pd = newArray->array.arrayData.data();
+ newArray->arrayData.resize(deleteCount);
+ PropertyDescriptor *pd = newArray->arrayData.data();
for (uint i = 0; i < deleteCount; ++i) {
pd->type = PropertyDescriptor::Data;
pd->writable = PropertyDescriptor::Enabled;
pd->value = instance->__get__(ctx, start + i);
++pd;
}
- newArray->array.setArrayLengthUnchecked(deleteCount);
+ newArray->setArrayLengthUnchecked(deleteCount);
uint itemCount = ctx->argumentCount < 2 ? 0 : ctx->argumentCount - 2;
bool exists;
Value v = instance->__get__(ctx, k + deleteCount, &exists);
if (exists)
- instance->array.arraySet(k + itemCount, v);
+ instance->arraySet(k + itemCount, v);
else
instance->__delete__(ctx, k + itemCount);
}
bool exists;
Value v = instance->__get__(ctx, k + deleteCount - 1, &exists);
if (exists)
- instance->array.arraySet(k + itemCount - 1, v);
+ instance->arraySet(k + itemCount - 1, v);
else
instance->__delete__(ctx, k + itemCount - 1);
--k;
}
for (uint i = 0; i < itemCount; ++i)
- instance->array.arraySet(start + i, ctx->argument(i + 2));
+ instance->arraySet(start + i, ctx->argument(i + 2));
ctx->strictMode = true;
instance->__put__(ctx, ctx->engine->id_length, Value::fromDouble(len - deleteCount + itemCount));
bool protoHasArray = false;
Object *p = instance;
while ((p = p->prototype))
- if (p->array.arrayLength())
+ if (p->arrayLength())
protoHasArray = true;
- if (!protoHasArray && len >= instance->array.arrayLength()) {
+ if (!protoHasArray && len >= instance->arrayLength()) {
for (int i = ctx->argumentCount - 1; i >= 0; --i) {
Value v = ctx->argument(i);
- instance->array.push_front(v);
+ instance->push_front(v);
}
} else {
for (uint k = len; k > 0; --k) {
return Value::fromInt32(-1);
}
- return instance->array.arrayIndexOf(searchValue, fromIndex, len, ctx, instance);
+ return instance->arrayIndexOf(searchValue, fromIndex, len, ctx, instance);
}
Value ArrayPrototype::method_lastIndexOf(ExecutionContext *ctx)
Value thisArg = ctx->argument(1);
ArrayObject *a = ctx->engine->newArrayObject(ctx);
- a->array.setArrayLengthUnchecked(len);
+ a->setArrayLengthUnchecked(len);
for (uint k = 0; k < len; ++k) {
bool exists;
args[1] = Value::fromDouble(k);
args[2] = ctx->thisObject;
Value mapped = callback->call(ctx, thisArg, args, 3);
- a->array.arraySet(k, mapped);
+ a->arraySet(k, mapped);
}
return Value::fromObject(a);
}
args[2] = ctx->thisObject;
Value selected = callback->call(ctx, thisArg, args, 3);
if (__qmljs_to_boolean(selected, ctx)) {
- a->array.arraySet(to, v);
+ a->arraySet(to, v);
++to;
}
}
Value Parser::parseArray()
{
BEGIN << "parseArray";
- Array array;
+ ArrayObject *array = context->engine->newArrayObject(context);
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
Value val;
if (!parseValue(&val))
return Value::undefinedValue();
- array.arraySet(index, val);
+ array->arraySet(index, val);
QChar token = nextToken();
if (token == EndArray)
break;
}
}
- DEBUG << "size =" << array.arrayLength();
+ DEBUG << "size =" << array->arrayLength();
END;
--nestingLevel;
- return Value::fromObject(context->engine->newArrayObject(context, array));
+ return Value::fromObject(array);
}
/*
indent += gap;
QStringList partial;
- uint len = a->array.arrayLength();
+ uint len = a->arrayLength();
for (uint i = 0; i < len; ++i) {
bool exists;
Value v = a->__get__(ctx, i, &exists);
if (o) {
stringify.replacerFunction = o->asFunctionObject();
if (o->isArrayObject()) {
- for (uint i = 0; i < o->array.arrayLength(); ++i) {
+ for (uint i = 0; i < o->arrayLength(); ++i) {
Value v = o->__get__(ctx, i);
if (v.asNumberObject() || v.asStringObject() || v.isNumber())
v = __qmljs_to_string(v, ctx);
//
Object::~Object()
{
+ delete sparseArray;
}
void Object::__put__(ExecutionContext *ctx, const QString &name, const Value &value)
}
}
}
- array.markArrayObjects();
+ markArrayObjects();
}
PropertyDescriptor *Object::insertMember(String *s)
PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, uint index)
{
- PropertyDescriptor *p = array.arrayAt(index);
+ PropertyDescriptor *p = arrayAt(index);
if(p && p->type != PropertyDescriptor::Generic)
return p;
if (isStringObject())
{
Object *o = this;
while (o) {
- PropertyDescriptor *p = o->array.arrayAt(index);
+ PropertyDescriptor *p = o->arrayAt(index);
if(p && p->type != PropertyDescriptor::Generic)
return p;
if (o->isStringObject()) {
PropertyDescriptor *pd = 0;
Object *o = this;
while (o) {
- PropertyDescriptor *p = o->array.arrayAt(index);
+ PropertyDescriptor *p = o->arrayAt(index);
if (p && p->type != PropertyDescriptor::Generic) {
pd = p;
break;
uint l = value.asArrayLength(ctx, &ok);
if (!ok)
ctx->throwRangeError(value);
- ok = array.setArrayLength(l);
+ ok = setArrayLength(l);
if (!ok)
goto reject;
} else {
return;
}
- array.arraySet(index, value);
+ arraySet(index, value);
return;
reject:
bool Object::__hasProperty__(const ExecutionContext *ctx, uint index) const
{
- const PropertyDescriptor *p = array.arrayAt(index);
+ const PropertyDescriptor *p = arrayAt(index);
if (p && p->type != PropertyDescriptor::Generic)
return true;
bool Object::__delete__(ExecutionContext *ctx, uint index)
{
- if (array.deleteArrayIndex(index))
+ if (deleteArrayIndex(index))
return true;
if (ctx->strictMode)
__qmljs_throw_type_error(ctx);
uint l = desc->value.asArrayLength(ctx, &ok);
if (!ok)
ctx->throwRangeError(desc->value);
- succeeded = array.setArrayLength(l);
+ succeeded = setArrayLength(l);
}
if (desc->writable == PropertyDescriptor::Disabled)
lp->writable = PropertyDescriptor::Disabled;
PropertyDescriptor *current;
// 15.4.5.1, 4b
- if (isArrayObject() && index >= array.arrayLength() && !memberData.at(ArrayObject::LengthPropertyIndex).isWritable())
+ if (isArrayObject() && index >= arrayLength() && !memberData.at(ArrayObject::LengthPropertyIndex).isWritable())
goto reject;
if (isNonStrictArgumentsObject)
if (!extensible)
goto reject;
// clause 4
- PropertyDescriptor *pd = array.arrayInsert(index);
+ PropertyDescriptor *pd = arrayInsert(index);
*pd = *desc;
pd->fullyPopulated();
return true;
}
+void Object::copyArrayData(Object *other)
+{
+ arrayLen = other->arrayLen;
+ arrayData = other->arrayData;
+ arrayFreeList = other->arrayFreeList;
+ if (other->sparseArray)
+ sparseArray = new SparseArray(*other->sparseArray);
+ if (isArrayObject())
+ setArrayLengthUnchecked(arrayLen);
+}
+
+
+Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
+{
+ bool protoHasArray = false;
+ Object *p = o;
+ while ((p = p->prototype))
+ if (p->arrayLength())
+ protoHasArray = true;
+
+ if (protoHasArray) {
+ // lets be safe and slow
+ for (uint i = fromIndex; i < endIndex; ++i) {
+ bool exists;
+ Value value = o->__get__(ctx, i, &exists);
+ if (exists && __qmljs_strict_equal(value, v))
+ return Value::fromDouble(i);
+ }
+ } else if (sparseArray) {
+ for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n && n->key() < endIndex; n = n->nextNode()) {
+ bool exists;
+ Value value = o->getValueChecked(ctx, arrayDecriptor(n->value), &exists);
+ if (exists && __qmljs_strict_equal(value, v))
+ return Value::fromDouble(n->key());
+ }
+ } else {
+ if ((int) endIndex > arrayData.size())
+ endIndex = arrayData.size();
+ PropertyDescriptor *pd = arrayData.data() + arrayOffset;
+ PropertyDescriptor *end = pd + endIndex;
+ pd += fromIndex;
+ while (pd < end) {
+ bool exists;
+ Value value = o->getValueChecked(ctx, pd, &exists);
+ if (exists && __qmljs_strict_equal(value, v))
+ return Value::fromDouble(pd - arrayOffset - arrayData.constData());
+ ++pd;
+ }
+ }
+ return Value::fromInt32(-1);
+}
+
+void Object::arrayConcat(const ArrayObject *other)
+{
+ int newLen = arrayLen + other->arrayLength();
+ if (other->sparseArray)
+ initSparse();
+ if (sparseArray) {
+ if (other->sparseArray) {
+ for (const SparseArrayNode *it = other->sparseArray->begin(); it != other->sparseArray->end(); it = it->nextNode())
+ arraySet(arrayLen + it->key(), other->arrayDecriptor(it->value));
+ } else {
+ int oldSize = arrayData.size();
+ arrayData.resize(oldSize + other->arrayLength());
+ memcpy(arrayData.data() + oldSize, other->arrayData.constData() + other->arrayOffset, other->arrayLength()*sizeof(PropertyDescriptor));
+ for (uint i = 0; i < other->arrayLength(); ++i) {
+ SparseArrayNode *n = sparseArray->insert(arrayLen + i);
+ n->value = oldSize + i;
+ }
+ }
+ } else {
+ int oldSize = arrayData.size();
+ arrayData.resize(oldSize + other->arrayLength());
+ memcpy(arrayData.data() + oldSize, other->arrayData.constData() + other->arrayOffset, other->arrayLength()*sizeof(PropertyDescriptor));
+ }
+ setArrayLengthUnchecked(newLen);
+}
+
+void Object::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
+{
+ if (sparseArray) {
+ context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
+ return;
+ delete sparseArray;
+ }
+
+ ArrayElementLessThan lessThan(context, thisObject, comparefn);
+ if (len > arrayData.size() - arrayOffset)
+ len = arrayData.size() - arrayOffset;
+ PropertyDescriptor *begin = arrayData.begin() + arrayOffset;
+ std::sort(begin, begin + len, lessThan);
+}
+
+
+void Object::initSparse()
+{
+ if (!sparseArray) {
+ sparseArray = new SparseArray;
+ for (int i = arrayOffset; i < arrayData.size(); ++i) {
+ SparseArrayNode *n = sparseArray->insert(i - arrayOffset);
+ n->value = i;
+ }
+
+ if (arrayOffset) {
+ int o = arrayOffset;
+ for (int i = 0; i < o - 1; ++i) {
+ arrayData[i].type = PropertyDescriptor::Generic;
+ arrayData[i].value = Value::fromInt32(i + 1);
+ }
+ arrayData[o - 1].type = PropertyDescriptor::Generic;
+ arrayData[o - 1].value = Value::fromInt32(arrayData.size());
+ arrayFreeList = 0;
+ } else {
+ arrayFreeList = arrayData.size();
+ }
+ }
+}
+
+void Object::setArrayLengthUnchecked(uint l)
+{
+ arrayLen = l;
+ if (isArrayObject()) {
+ // length is always the first property of an array
+ PropertyDescriptor &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
+ lengthProperty.value = Value::fromUInt32(l);
+ }
+}
+
+bool Object::setArrayLength(uint newLen) {
+ assert(isArrayObject());
+ const PropertyDescriptor *lengthProperty = memberData.constData() + ArrayObject::LengthPropertyIndex;
+ if (lengthProperty && !lengthProperty->isWritable())
+ return false;
+ uint oldLen = arrayLength();
+ bool ok = true;
+ if (newLen < oldLen) {
+ if (sparseArray) {
+ SparseArrayNode *begin = sparseArray->lowerBound(newLen);
+ SparseArrayNode *it = sparseArray->end()->previousNode();
+ while (1) {
+ PropertyDescriptor &pd = arrayData[it->value];
+ if (pd.type != PropertyDescriptor::Generic && !pd.isConfigurable()) {
+ ok = false;
+ newLen = it->key() + 1;
+ break;
+ }
+ pd.type = PropertyDescriptor::Generic;
+ pd.value.tag = Value::_Undefined_Type;
+ pd.value.int_32 = arrayFreeList;
+ arrayFreeList = it->value;
+ bool brk = (it == begin);
+ SparseArrayNode *prev = it->previousNode();
+ sparseArray->erase(it);
+ if (brk)
+ break;
+ it = prev;
+ }
+ } else {
+ PropertyDescriptor *it = arrayData.data() + arrayData.size();
+ const PropertyDescriptor *begin = arrayData.constData() + arrayOffset + newLen;
+ while (--it >= begin) {
+ if (it->type != PropertyDescriptor::Generic && !it->isConfigurable()) {
+ ok = false;
+ newLen = it - arrayData.data() + arrayOffset + 1;
+ break;
+ }
+ }
+ arrayData.resize(newLen + arrayOffset);
+ }
+ } else {
+ if (newLen >= 0x100000)
+ initSparse();
+ }
+ setArrayLengthUnchecked(newLen);
+ return ok;
+}
+
+void Object::markArrayObjects() const
+{
+ uint i = sparseArray ? 0 : arrayOffset;
+ for (; i < (uint)arrayData.size(); ++i) {
+ const PropertyDescriptor &pd = arrayData.at(i);
+ if (pd.isData()) {
+ if (Managed *m = pd.value.asManaged())
+ m->mark();
+ } else if (pd.isAccessor()) {
+ if (pd.get)
+ pd.get->mark();
+ if (pd.set)
+ pd.set->mark();
+ }
+ }
+}
+
+
void ArrayObject::init(ExecutionContext *context)
{
type = Type_ArrayObject;
pd->enumberable = PropertyDescriptor::Disabled;
pd->configurable = PropertyDescriptor::Disabled;
pd->value = Value::fromInt32(0);
- array.setArrayObject(this);
}
Object *prototype;
QScopedPointer<PropertyTable> members;
QVector<PropertyDescriptor> memberData;
- Array array;
+
+ uint arrayLen;
+ union {
+ uint arrayFreeList;
+ uint arrayOffset;
+ };
+ QVector<PropertyDescriptor> arrayData;
+ SparseArray *sparseArray;
Object()
- : prototype(0) { type = Type_Object; }
- Object(const Array &a)
- : prototype(0), array(a) {}
+ : prototype(0)
+ , arrayLen(0), arrayOffset(0), sparseArray(0) { type = Type_Object; }
virtual ~Object();
PropertyDescriptor *insertMember(String *s);
+ // Array handling
+
+ void fillDescriptor(PropertyDescriptor *pd, Value v)
+ {
+ pd->type = PropertyDescriptor::Data;
+ pd->writable = PropertyDescriptor::Enabled;
+ pd->enumberable = PropertyDescriptor::Enabled;
+ pd->configurable = PropertyDescriptor::Enabled;
+ pd->value = v;
+ }
+
+ uint allocArrayValue() {
+ uint idx = arrayFreeList;
+ if (arrayData.size() <= (int)arrayFreeList)
+ arrayData.resize(++arrayFreeList);
+ else
+ arrayFreeList = arrayData.at(arrayFreeList).value.integerValue();
+ return idx;
+ }
+
+ uint allocArrayValue(Value v) {
+ uint idx = allocArrayValue();
+ PropertyDescriptor *pd = &arrayData[idx];
+ fillDescriptor(pd, v);
+ return idx;
+ }
+ void freeArrayValue(int idx) {
+ PropertyDescriptor &pd = arrayData[idx];
+ pd.type = PropertyDescriptor::Generic;
+ pd.value.tag = Value::_Undefined_Type;
+ pd.value.int_32 = arrayFreeList;
+ arrayFreeList = idx;
+ }
+
+ PropertyDescriptor *arrayDecriptor(uint index) {
+ PropertyDescriptor *pd = arrayData.data() + index;
+ if (!sparseArray)
+ pd += arrayOffset;
+ return pd;
+ }
+ const PropertyDescriptor *arrayDecriptor(uint index) const {
+ const PropertyDescriptor *pd = arrayData.data() + index;
+ if (!sparseArray)
+ pd += arrayOffset;
+ return pd;
+ }
+
+ void getArrayHeadRoom() {
+ assert(!sparseArray && !arrayOffset);
+ arrayOffset = qMax(arrayData.size() >> 2, 16);
+ QVector<PropertyDescriptor> newValues(arrayData.size() + arrayOffset);
+ memcpy(newValues.data() + arrayOffset, arrayData.constData(), arrayData.size()*sizeof(PropertyDescriptor));
+ arrayData = newValues;
+ }
+
+public:
+ void copyArrayData(Object *other);
+ void initSparse();
+
+ uint arrayLength() const { return arrayLen; }
+ bool setArrayLength(uint newLen);
+
+ void setArrayLengthUnchecked(uint l);
+
+ PropertyDescriptor *arrayInsert(uint index) {
+ PropertyDescriptor *pd;
+ if (!sparseArray && (index < 0x1000 || index < arrayLen + (arrayLen >> 2))) {
+ if (index + arrayOffset >= (uint)arrayData.size()) {
+ arrayData.resize(arrayOffset + index + 1);
+ for (uint i = arrayLen + 1; i < index; ++i) {
+ arrayData[i].type = PropertyDescriptor::Generic;
+ arrayData[i].value.tag = Value::_Undefined_Type;
+ }
+ }
+ pd = arrayDecriptor(index);
+ } else {
+ initSparse();
+ SparseArrayNode *n = sparseArray->insert(index);
+ if (n->value == UINT_MAX)
+ n->value = allocArrayValue();
+ pd = arrayDecriptor(n->value);
+ }
+ if (index >= arrayLen)
+ setArrayLengthUnchecked(index + 1);
+ return pd;
+ }
+
+ void arraySet(uint index, const PropertyDescriptor *pd) {
+ *arrayInsert(index) = *pd;
+ }
+
+ void arraySet(uint index, Value value) {
+ PropertyDescriptor *pd = arrayInsert(index);
+ fillDescriptor(pd, value);
+ }
+
+ bool deleteArrayIndex(uint index) {
+ if (index >= arrayLen)
+ return true;
+ PropertyDescriptor *pd = 0;
+ if (!sparseArray) {
+ pd = arrayAt(index);
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(index);
+ if (n)
+ pd = arrayDecriptor(n->value);
+ }
+ if (!pd || pd->type == PropertyDescriptor::Generic)
+ return true;
+ if (!pd->isConfigurable())
+ return false;
+ pd->type = PropertyDescriptor::Generic;
+ pd->value.tag = Value::_Undefined_Type;
+ if (sparseArray) {
+ pd->value.int_32 = arrayFreeList;
+ arrayFreeList = pd - arrayData.constData();
+ }
+ return true;
+ }
+
+ PropertyDescriptor *arrayAt(uint index) {
+ if (!sparseArray) {
+ if (index >= arrayData.size() - arrayOffset)
+ return 0;
+ return arrayData.data() + index + arrayOffset;
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(index);
+ if (!n)
+ return 0;
+ return arrayData.data() + n->value;
+ }
+ }
+
+ const PropertyDescriptor *nonSparseArrayAt(uint index) const {
+ if (sparseArray)
+ return 0;
+ index += arrayOffset;
+ if (index >= (uint)arrayData.size())
+ return 0;
+ return arrayData.constData() + index;
+ }
+
+ PropertyDescriptor *nonSparseArrayAtRef(uint index) {
+ if (sparseArray)
+ return 0;
+ index += arrayOffset;
+ if (index >= (uint)arrayData.size())
+ return 0;
+ return arrayData.data() + index;
+ }
+
+ const PropertyDescriptor *arrayAt(uint index) const {
+ if (!sparseArray) {
+ if (index >= arrayData.size() - arrayOffset)
+ return 0;
+ return arrayData.constData() + index + arrayOffset;
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(index);
+ if (!n)
+ return 0;
+ return arrayData.constData() + n->value;
+ }
+ }
+
+ void markArrayObjects() const;
+
+ void push_front(Value v) {
+ if (!sparseArray) {
+ if (!arrayOffset)
+ getArrayHeadRoom();
+
+ PropertyDescriptor pd;
+ fillDescriptor(&pd, v);
+ --arrayOffset;
+ arrayData[arrayOffset] = pd;
+ } else {
+ uint idx = allocArrayValue(v);
+ sparseArray->push_front(idx);
+ }
+ setArrayLengthUnchecked(arrayLen + 1);
+ }
+ PropertyDescriptor *front() {
+ PropertyDescriptor *pd = 0;
+ if (!sparseArray) {
+ if (arrayLen)
+ pd = arrayData.data() + arrayOffset;
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(0);
+ if (n)
+ pd = arrayDecriptor(n->value);
+ }
+ if (pd && pd->type == PropertyDescriptor::Generic)
+ return 0;
+ return pd;
+ }
+ void pop_front() {
+ if (!arrayLen)
+ return;
+ if (!sparseArray) {
+ ++arrayOffset;
+ } else {
+ uint idx = sparseArray->pop_front();
+ freeArrayValue(idx);
+ }
+ setArrayLengthUnchecked(arrayLen - 1);
+ }
+ void push_back(Value v) {
+ if (!sparseArray) {
+ PropertyDescriptor pd;
+ fillDescriptor(&pd, v);
+ arrayData.append(pd);
+ } else {
+ uint idx = allocArrayValue(v);
+ sparseArray->push_back(idx, arrayLen);
+ }
+ setArrayLengthUnchecked(arrayLen + 1);
+ }
+ PropertyDescriptor *back() {
+ PropertyDescriptor *pd = 0;
+ if (!sparseArray) {
+ if (arrayLen)
+ pd = arrayData.data() + arrayOffset + arrayLen;
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(arrayLen - 1);
+ if (n)
+ pd = arrayDecriptor(n->value);
+ }
+ if (pd && pd->type == PropertyDescriptor::Generic)
+ return 0;
+ return pd;
+ }
+ void pop_back() {
+ if (!arrayLen)
+ return;
+ if (!sparseArray) {
+ arrayData.resize(arrayData.size() - 1);
+ } else {
+ uint idx = sparseArray->pop_back(arrayLen);
+ if (idx != UINT_MAX)
+ freeArrayValue(idx);
+ }
+ setArrayLengthUnchecked(arrayLen - 1);
+ }
+
+ SparseArrayNode *sparseArrayLowerBound(uint idx) { return sparseArray ? sparseArray->lowerBound(idx) : 0; }
+ SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
+ SparseArrayNode *sparseArrayEnd() { return sparseArray ? sparseArray->end() : 0; }
+
+ void arrayConcat(const ArrayObject *other);
+ void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayLen);
+ Value arrayIndexOf(Value v, uint fromIndex, uint arrayLen, ExecutionContext *ctx, Object *o);
+
+
protected:
virtual void markObjects();
};
ArrayObject(ExecutionContext *ctx) { init(ctx); }
- ArrayObject(ExecutionContext *ctx, const Array &value): Object(value) { init(ctx); array.setArrayLengthUnchecked(array.arrayLength()); }
+ ArrayObject(ExecutionContext *ctx, const QVector<PropertyDescriptor> &value): Object() {
+ init(ctx);
+ arrayData = value;
+ setArrayLengthUnchecked(value.size());
+ }
void init(ExecutionContext *context);
};
return s->__getOwnProperty__(context, *index);
}
flags &= ~CurrentIsString;
- arrayNode = current->array.sparseArrayBegin();
+ arrayNode = current->sparseArrayBegin();
// iterate until we're past the end of the string
while (arrayNode && arrayNode->key() < slen)
arrayNode = arrayNode->nextNode();
}
if (!arrayIndex)
- arrayNode = current->array.sparseArrayBegin();
+ arrayNode = current->sparseArrayBegin();
// sparse arrays
if (arrayNode) {
- while (arrayNode != current->array.sparseArrayEnd()) {
+ while (arrayNode != current->sparseArrayEnd()) {
int k = arrayNode->key();
- p = current->array.arrayAt(k);
+ p = current->arrayAt(k);
arrayNode = arrayNode->nextNode();
if (p && (!(flags & EnumberableOnly) || p->isEnumerable())) {
arrayIndex = k + 1;
arrayIndex = UINT_MAX;
}
// dense arrays
- while (arrayIndex < current->array.arrayLength()) {
- p = current->array.arrayAt(arrayIndex);
+ while (arrayIndex < current->arrayLength()) {
+ p = current->arrayAt(arrayIndex);
++arrayIndex;
if (p && p->type != PropertyDescriptor::Generic && (!(flags & EnumberableOnly) || p->isEnumerable())) {
*index = arrayIndex - 1;
ctx->throwTypeError();
ArrayObject *array = ctx->engine->newArrayObject(ctx)->asArrayObject();
- Array &a = array->array;
ObjectIterator it(ctx, O, ObjectIterator::NoFlags);
while (1) {
Value v = it.nextPropertyNameAsString();
if (v.isNull())
break;
- a.push_back(v);
+ array->push_back(v);
}
return Value::fromObject(array);
}
key = Value::fromDouble(index);
key = __qmljs_to_string(key, ctx);
}
- a->array.push_back(key);
+ a->push_back(key);
}
return Value::fromObject(a);
Value entry = Value::undefinedValue();
if (start != -1 && end != -1)
entry = Value::fromString(ctx, s.mid(start, end - start));
- array->array.push_back(entry);
+ array->push_back(entry);
}
array->__put__(ctx, QLatin1String("index"), Value::fromInt32(result));
previousLastIndex = thisIndex;
}
Value matchStr = result.objectValue()->__get__(parentCtx, (uint)0, (bool *)0);
- a->array.arraySet(n, matchStr);
+ a->arraySet(n, matchStr);
++n;
}
if (!n)
if (separatorValue.isUndefined()) {
if (limitValue.isUndefined()) {
- array->array.push_back(Value::fromString(ctx, text));
+ array->push_back(Value::fromString(ctx, text));
return result;
}
return Value::fromString(ctx, text.left(limitValue.toInteger(ctx)));
if (result == JSC::Yarr::offsetNoMatch)
break;
- array->array.push_back(Value::fromString(ctx, text.mid(offset, matchOffsets[0] - offset)));
+ array->push_back(Value::fromString(ctx, text.mid(offset, matchOffsets[0] - offset)));
offset = qMax(offset + 1, matchOffsets[1]);
- if (array->array.arrayLength() >= limit)
+ if (array->arrayLength() >= limit)
break;
for (int i = 1; i < re->value->captureCount(); ++i) {
uint start = matchOffsets[i * 2];
uint end = matchOffsets[i * 2 + 1];
- array->array.push_back(Value::fromString(ctx, text.mid(start, end - start)));
- if (array->array.arrayLength() >= limit)
+ array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
+ if (array->arrayLength() >= limit)
break;
}
}
- if (array->array.arrayLength() < limit)
- array->array.push_back(Value::fromString(ctx, text.mid(offset)));
+ if (array->arrayLength() < limit)
+ array->push_back(Value::fromString(ctx, text.mid(offset)));
} else {
QString separator = separatorValue.toString(ctx)->toQString();
if (separator.isEmpty()) {
for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
- array->array.push_back(Value::fromString(ctx, text.mid(i, 1)));
+ array->push_back(Value::fromString(ctx, text.mid(i, 1)));
return result;
}
int start = 0;
int end;
while ((end = text.indexOf(separator, start)) != -1) {
- array->array.push_back(Value::fromString(ctx, text.mid(start, end - start)));
+ array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
start = end + separator.size();
- if (array->array.arrayLength() >= limit)
+ if (array->arrayLength() >= limit)
break;
}
- if (array->array.arrayLength() < limit && start != -1)
- array->array.push_back(Value::fromString(ctx, text.mid(start)));
+ if (array->arrayLength() < limit && start != -1)
+ array->push_back(Value::fromString(ctx, text.mid(start)));
}
return result;
}
S15.4.4.3_A1_T1 failing
S15.4.4.3_A3_T1 failing
15.4.4.4-5-c-i-1 failing
-S15.4.4.4_A1_T2 failing
S15.4.4.4_A2_T1 failing
S15.4.4.4_A2_T2 failing
S15.4.4.4_A3_T1 failing