📄 nativearray.java
字号:
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Norris Boyd * Mike McCabe * Igor Bukanov * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */package org.mozilla.javascript;/** * This class implements the Array native object. * @author Norris Boyd * @author Mike McCabe */public class NativeArray extends IdScriptableObject{ static final long serialVersionUID = 7331366857676127338L; /* * Optimization possibilities and open issues: * - Long vs. double schizophrenia. I suspect it might be better * to use double throughout. * - Most array operations go through getElem or setElem (defined * in this file) to handle the full 2^32 range; it might be faster * to have versions of most of the loops in this file for the * (infinitely more common) case of indices < 2^31. * - Functions that need a new Array call "new Array" in the * current scope rather than using a hardwired constructor; * "Array" could be redefined. It turns out that js calls the * equivalent of "new Array" in the current scope, except that it * always gets at least an object back, even when Array == null. */ private static final Object ARRAY_TAG = new Object(); private static final Integer NEGATIVE_ONE = new Integer(-1); static void init(Scriptable scope, boolean sealed) { NativeArray obj = new NativeArray(); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } /** * Zero-parameter constructor: just used to create Array.prototype */ private NativeArray() { dense = null; this.length = 0; } public NativeArray(long length) { int intLength = (int) length; if (intLength == length && intLength > 0) { if (intLength > maximumDenseLength) intLength = maximumDenseLength; dense = new Object[intLength]; for (int i=0; i < intLength; i++) dense[i] = NOT_FOUND; } this.length = length; } public NativeArray(Object[] array) { dense = array; this.length = array.length; } public String getClassName() { return "Array"; } private static final int Id_length = 1, MAX_INSTANCE_ID = 1; protected int getMaxInstanceId() { return MAX_INSTANCE_ID; } protected int findInstanceIdInfo(String s) { if (s.equals("length")) { return instanceIdInfo(DONTENUM | PERMANENT, Id_length); } return super.findInstanceIdInfo(s); } protected String getInstanceIdName(int id) { if (id == Id_length) { return "length"; } return super.getInstanceIdName(id); } protected Object getInstanceIdValue(int id) { if (id == Id_length) { return ScriptRuntime.wrapNumber(length); } return super.getInstanceIdValue(id); } protected void setInstanceIdValue(int id, Object value) { if (id == Id_length) { setLength(value); return; } super.setInstanceIdValue(id, value); } protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toLocaleString: arity=1; s="toLocaleString"; break; case Id_toSource: arity=0; s="toSource"; break; case Id_join: arity=1; s="join"; break; case Id_reverse: arity=0; s="reverse"; break; case Id_sort: arity=1; s="sort"; break; case Id_push: arity=1; s="push"; break; case Id_pop: arity=1; s="pop"; break; case Id_shift: arity=1; s="shift"; break; case Id_unshift: arity=1; s="unshift"; break; case Id_splice: arity=1; s="splice"; break; case Id_concat: arity=1; s="concat"; break; case Id_slice: arity=1; s="slice"; break; case Id_indexOf: arity=1; s="indexOf"; break; case Id_lastIndexOf: arity=1; s="lastIndexOf"; break; case Id_every: arity=1; s="every"; break; case Id_filter: arity=1; s="filter"; break; case Id_forEach: arity=1; s="forEach"; break; case Id_map: arity=1; s="map"; break; case Id_some: arity=1; s="some"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(ARRAY_TAG, id, s, arity); } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(ARRAY_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: { boolean inNewExpr = (thisObj == null); if (!inNewExpr) { // IdFunctionObject.construct will set up parent, proto return f.construct(cx, scope, args); } return jsConstructor(cx, scope, args); } case Id_toString: return toStringHelper(cx, scope, thisObj, cx.hasFeature(Context.FEATURE_TO_STRING_AS_SOURCE), false); case Id_toLocaleString: return toStringHelper(cx, scope, thisObj, false, true); case Id_toSource: return toStringHelper(cx, scope, thisObj, true, false); case Id_join: return js_join(cx, thisObj, args); case Id_reverse: return js_reverse(cx, thisObj, args); case Id_sort: return js_sort(cx, scope, thisObj, args); case Id_push: return js_push(cx, thisObj, args); case Id_pop: return js_pop(cx, thisObj, args); case Id_shift: return js_shift(cx, thisObj, args); case Id_unshift: return js_unshift(cx, thisObj, args); case Id_splice: return js_splice(cx, scope, thisObj, args); case Id_concat: return js_concat(cx, scope, thisObj, args); case Id_slice: return js_slice(cx, thisObj, args); case Id_indexOf: return indexOfHelper(cx, thisObj, args, false); case Id_lastIndexOf: return indexOfHelper(cx, thisObj, args, true); case Id_every: case Id_filter: case Id_forEach: case Id_map: case Id_some: return iterativeMethod(cx, id, scope, thisObj, args); } throw new IllegalArgumentException(String.valueOf(id)); } public Object get(int index, Scriptable start) { if (dense != null && 0 <= index && index < dense.length) return dense[index]; return super.get(index, start); } public boolean has(int index, Scriptable start) { if (dense != null && 0 <= index && index < dense.length) return dense[index] != NOT_FOUND; return super.has(index, start); } // if id is an array index (ECMA 15.4.0), return the number, // otherwise return -1L private static long toArrayIndex(String id) { double d = ScriptRuntime.toNumber(id); if (d == d) { long index = ScriptRuntime.toUint32(d); if (index == d && index != 4294967295L) { // Assume that ScriptRuntime.toString(index) is the same // as java.lang.Long.toString(index) for long if (Long.toString(index).equals(id)) { return index; } } } return -1; } public void put(String id, Scriptable start, Object value) { super.put(id, start, value); if (start == this) { // If the object is sealed, super will throw exception long index = toArrayIndex(id); if (index >= length) { length = index + 1; } } } public void put(int index, Scriptable start, Object value) { if (start == this && !isSealed() && dense != null && 0 <= index && index < dense.length) { // If start == this && sealed, super will throw exception dense[index] = value; } else { super.put(index, start, value); } if (start == this) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } } } public void delete(int index) { if (!isSealed() && dense != null && 0 <= index && index < dense.length) { dense[index] = NOT_FOUND; } else { super.delete(index); } } public Object[] getIds() { Object[] superIds = super.getIds(); if (dense == null) { return superIds; } int N = dense.length; long currentLength = length; if (N > currentLength) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -