📄 array_object.cpp
字号:
// -*- c-basic-offset: 2 -*-/* * This file is part of the KDE libraries * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2003 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "value.h"#include "object.h"#include "types.h"#include "interpreter.h"#include "operations.h"#include "array_object.h"#include "internal.h"#include "error_object.h"#include "array_object.lut.h"#include <stdio.h>#include <assert.h>using namespace KJS;// ------------------------------ ArrayInstanceImp -----------------------------const unsigned sparseArrayCutoff = 10000;const ClassInfo ArrayInstanceImp::info = {"Array", 0, 0, 0};ArrayInstanceImp::ArrayInstanceImp(ObjectImp *proto, unsigned initialLength) : ObjectImp(proto) , length(initialLength) , storageLength(initialLength < sparseArrayCutoff ? initialLength : 0) , capacity(storageLength) , storage(capacity ? (ValueImp **)calloc(capacity, sizeof(ValueImp *)) : 0){}ArrayInstanceImp::ArrayInstanceImp(ObjectImp *proto, const List &list) : ObjectImp(proto) , length(list.size()) , storageLength(length) , capacity(storageLength) , storage(capacity ? (ValueImp **)malloc(sizeof(ValueImp *) * capacity) : 0){ ListIterator it = list.begin(); unsigned l = length; for (unsigned i = 0; i < l; ++i) { storage[i] = (it++).imp(); }}ArrayInstanceImp::~ArrayInstanceImp(){ free(storage);}Value ArrayInstanceImp::get(ExecState *exec, const Identifier &propertyName) const{ if (propertyName == lengthPropertyName) return Number(length); bool ok; unsigned index = propertyName.toArrayIndex(&ok); if (ok) { if (index >= length) return Undefined(); if (index < storageLength) { ValueImp *v = storage[index]; return v ? Value(v) : Undefined(); } } return ObjectImp::get(exec, propertyName);}Value ArrayInstanceImp::get(ExecState *exec, unsigned index) const{ if (index >= length) return Undefined(); if (index < storageLength) { ValueImp *v = storage[index]; return v ? Value(v) : Undefined(); } return ObjectImp::get(exec, Identifier::from(index));}// Special implementation of [[Put]] - see ECMA 15.4.5.1void ArrayInstanceImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr){ if (propertyName == lengthPropertyName) { setLength(value.toUInt32(exec), exec); return; } bool ok; unsigned index = propertyName.toArrayIndex(&ok); if (ok) { put(exec, index, value, attr); return; } ObjectImp::put(exec, propertyName, value, attr);}void ArrayInstanceImp::put(ExecState *exec, unsigned index, const Value &value, int attr){ if (index < sparseArrayCutoff && index >= storageLength) { resizeStorage(index + 1); } if (index >= length) { length = index + 1; } if (index < storageLength) { storage[index] = value.imp(); return; } assert(index >= sparseArrayCutoff); ObjectImp::put(exec, Identifier::from(index), value, attr);}bool ArrayInstanceImp::hasProperty(ExecState *exec, const Identifier &propertyName) const{ if (propertyName == lengthPropertyName) return true; bool ok; unsigned index = propertyName.toArrayIndex(&ok); if (ok) { if (index >= length) return false; if (index < storageLength) { ValueImp *v = storage[index]; return v && v != UndefinedImp::staticUndefined; } } return ObjectImp::hasProperty(exec, propertyName);}bool ArrayInstanceImp::hasProperty(ExecState *exec, unsigned index) const{ if (index >= length) return false; if (index < storageLength) { ValueImp *v = storage[index]; return v && v != UndefinedImp::staticUndefined; } return ObjectImp::hasProperty(exec, Identifier::from(index));}bool ArrayInstanceImp::deleteProperty(ExecState *exec, const Identifier &propertyName){ if (propertyName == lengthPropertyName) return false; bool ok; uint32_t index = propertyName.toUInt32(&ok); if (ok) { if (index >= length) return true; if (index < storageLength) { storage[index] = 0; return true; } } return ObjectImp::deleteProperty(exec, propertyName);}bool ArrayInstanceImp::deleteProperty(ExecState *exec, unsigned index){ if (index >= length) return true; if (index < storageLength) { storage[index] = 0; return true; } return ObjectImp::deleteProperty(exec, Identifier::from(index));}ReferenceList ArrayInstanceImp::propList(ExecState *exec, bool recursive){ ReferenceList properties = ObjectImp::propList(exec,recursive); // avoid fetching this every time through the loop ValueImp *undefined = UndefinedImp::staticUndefined; for (unsigned i = 0; i < storageLength; ++i) { ValueImp *imp = storage[i]; if (imp && imp != undefined) { properties.append(Reference(this, i)); } } return properties;}void ArrayInstanceImp::resizeStorage(unsigned newLength){ if (newLength < storageLength) { memset(storage + newLength, 0, sizeof(ValueImp *) * (storageLength - newLength)); } if (newLength > capacity) { unsigned newCapacity; if (newLength > sparseArrayCutoff) { newCapacity = newLength; } else { newCapacity = (newLength * 3 + 1) / 2; if (newCapacity > sparseArrayCutoff) { newCapacity = sparseArrayCutoff; } } storage = (ValueImp **)realloc(storage, newCapacity * sizeof (ValueImp *)); memset(storage + capacity, 0, sizeof(ValueImp *) * (newCapacity - capacity)); capacity = newCapacity; } storageLength = newLength;}void ArrayInstanceImp::setLength(unsigned newLength, ExecState *exec){ if (newLength <= storageLength) { resizeStorage(newLength); } if (newLength < length) { ReferenceList sparseProperties; _prop.addSparseArrayPropertiesToReferenceList(sparseProperties, Object(this)); ReferenceListIterator it = sparseProperties.begin(); while (it != sparseProperties.end()) { Reference ref = it++; bool ok; unsigned index = ref.getPropertyName(exec).toArrayIndex(&ok); if (ok && index > newLength) { ref.deleteValue(exec); } } } length = newLength;}void ArrayInstanceImp::mark(){ ObjectImp::mark(); unsigned l = storageLength; for (unsigned i = 0; i < l; ++i) { ValueImp *imp = storage[i]; if (imp && !imp->marked()) imp->mark(); }}static ExecState *execForCompareByStringForQSort;static int compareByStringForQSort(const void *a, const void *b){ ExecState *exec = execForCompareByStringForQSort; ValueImp *va = *(ValueImp **)a; ValueImp *vb = *(ValueImp **)b; if (va->dispatchType() == UndefinedType) { return vb->dispatchType() == UndefinedType ? 0 : 1; } if (vb->dispatchType() == UndefinedType) { return -1; } return compare(va->dispatchToString(exec), vb->dispatchToString(exec));}void ArrayInstanceImp::sort(ExecState *exec){ int lengthNotIncludingUndefined = pushUndefinedObjectsToEnd(exec); execForCompareByStringForQSort = exec; qsort(storage, lengthNotIncludingUndefined, sizeof(ValueImp *), compareByStringForQSort); execForCompareByStringForQSort = 0;}struct CompareWithCompareFunctionArguments { CompareWithCompareFunctionArguments(ExecState *e, ObjectImp *cf) : exec(e) , compareFunction(cf) , globalObject(e->dynamicInterpreter()->globalObject()) { arguments.append(Undefined()); arguments.append(Undefined()); } ExecState *exec; ObjectImp *compareFunction; List arguments; Object globalObject;};static CompareWithCompareFunctionArguments *compareWithCompareFunctionArguments;static int compareWithCompareFunctionForQSort(const void *a, const void *b){ CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments; ValueImp *va = *(ValueImp **)a; ValueImp *vb = *(ValueImp **)b; if (va->dispatchType() == UndefinedType) { return vb->dispatchType() == UndefinedType ? 0 : 1; } if (vb->dispatchType() == UndefinedType) { return -1; } args->arguments.clear(); args->arguments.append(va); args->arguments.append(vb); double compareResult = args->compareFunction->call (args->exec, args->globalObject, args->arguments).toNumber(args->exec); return compareResult < 0 ? -1 : compareResult > 0 ? 1 : 0;}void ArrayInstanceImp::sort(ExecState *exec, Object &compareFunction){ int lengthNotIncludingUndefined = pushUndefinedObjectsToEnd(exec); CompareWithCompareFunctionArguments args(exec, compareFunction.imp()); compareWithCompareFunctionArguments = &args; qsort(storage, lengthNotIncludingUndefined, sizeof(ValueImp *), compareWithCompareFunctionForQSort); compareWithCompareFunctionArguments = 0;}unsigned ArrayInstanceImp::pushUndefinedObjectsToEnd(ExecState *exec){ ValueImp *undefined = UndefinedImp::staticUndefined; unsigned o = 0; for (unsigned i = 0; i != storageLength; ++i) { ValueImp *v = storage[i]; if (v && v != undefined) { if (o != i) storage[o] = v; o++; } } ReferenceList sparseProperties; _prop.addSparseArrayPropertiesToReferenceList(sparseProperties, Object(this)); unsigned newLength = o + sparseProperties.length(); if (newLength > storageLength) { resizeStorage(newLength); } ReferenceListIterator it = sparseProperties.begin(); while (it != sparseProperties.end()) { Reference ref = it++; storage[o] = ref.getValue(exec).imp(); ObjectImp::deleteProperty(exec, ref.getPropertyName(exec)); o++; } if (newLength != storageLength) memset(storage + o, 0, sizeof(ValueImp *) * (storageLength - o)); return o;}// ------------------------------ ArrayPrototypeImp ----------------------------const ClassInfo ArrayPrototypeImp::info = {"Array", &ArrayInstanceImp::info, &arrayTable, 0};/* Source for array_object.lut.h@begin arrayTable 13 toString ArrayProtoFuncImp::ToString DontEnum|Function 0 toLocaleString ArrayProtoFuncImp::ToLocaleString DontEnum|Function 0 concat ArrayProtoFuncImp::Concat DontEnum|Function 1 join ArrayProtoFuncImp::Join DontEnum|Function 1 pop ArrayProtoFuncImp::Pop DontEnum|Function 0 push ArrayProtoFuncImp::Push DontEnum|Function 1 reverse ArrayProtoFuncImp::Reverse DontEnum|Function 0 shift ArrayProtoFuncImp::Shift DontEnum|Function 0 slice ArrayProtoFuncImp::Slice DontEnum|Function 2 sort ArrayProtoFuncImp::Sort DontEnum|Function 1 splice ArrayProtoFuncImp::Splice DontEnum|Function 2 unshift ArrayProtoFuncImp::UnShift DontEnum|Function 1@end*/// ECMA 15.4.4ArrayPrototypeImp::ArrayPrototypeImp(ExecState *exec, ObjectPrototypeImp *objProto) : ArrayInstanceImp(objProto, 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -