jsarray.c
来自「java script test programing source code」· C语言 代码 · 共 1,865 行 · 第 1/4 页
C
1,865 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set sw=4 ts=8 et tw=80: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * 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 Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS array class. */#include "jsstddef.h"#include <stdlib.h>#include <string.h>#include "jstypes.h"#include "jsutil.h" /* Added by JSIFY */#include "jsapi.h"#include "jsarray.h"#include "jsatom.h"#include "jsbool.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsfun.h"#include "jsgc.h"#include "jsinterp.h"#include "jslock.h"#include "jsnum.h"#include "jsobj.h"#include "jsstr.h"/* 2^32 - 1 as a number and a string */#define MAXINDEX 4294967295u#define MAXSTR "4294967295"/* * Determine if the id represents an array index or an XML property index. * * An id is an array index according to ECMA by (15.4): * * "Array objects give special treatment to a certain class of property names. * A property name P (in the form of a string value) is an array index if and * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal * to 2^32-1." * * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) * except that by using signed 32-bit integers we miss the top half of the * valid range. This function checks the string representation itself; note * that calling a standard conversion routine might allow strings such as * "08" or "4.0" as array indices, which they are not. */JSBooljs_IdIsIndex(jsval id, jsuint *indexp){ JSString *str; jschar *cp; if (JSVAL_IS_INT(id)) { jsint i; i = JSVAL_TO_INT(id); if (i < 0) return JS_FALSE; *indexp = (jsuint)i; return JS_TRUE; } /* NB: id should be a string, but jsxml.c may call us with an object id. */ if (!JSVAL_IS_STRING(id)) return JS_FALSE; str = JSVAL_TO_STRING(id); cp = JSSTRING_CHARS(str); if (JS7_ISDEC(*cp) && JSSTRING_LENGTH(str) < sizeof(MAXSTR)) { jsuint index = JS7_UNDEC(*cp++); jsuint oldIndex = 0; jsuint c = 0; if (index != 0) { while (JS7_ISDEC(*cp)) { oldIndex = index; c = JS7_UNDEC(*cp); index = 10*index + c; cp++; } } /* Ensure that all characters were consumed and we didn't overflow. */ if (*cp == 0 && (oldIndex < (MAXINDEX / 10) || (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10)))) { *indexp = index; return JS_TRUE; } } return JS_FALSE;}static JSBoolValueIsLength(JSContext *cx, jsval v, jsuint *lengthp){ jsint i; jsdouble d; if (JSVAL_IS_INT(v)) { i = JSVAL_TO_INT(v); if (i < 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return JS_FALSE; } *lengthp = (jsuint) i; return JS_TRUE; } if (!js_ValueToNumber(cx, v, &d)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return JS_FALSE; } if (!js_DoubleToECMAUint32(cx, d, (uint32 *)lengthp)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return JS_FALSE; } if (JSDOUBLE_IS_NaN(d) || d != *lengthp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); return JS_FALSE; } return JS_TRUE;}JSBooljs_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp){ JSTempValueRooter tvr; jsid id; JSBool ok; jsint i; JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); if (ok) { /* * Short-circuit, because js_ValueToECMAUint32 fails when called * during init time. */ if (JSVAL_IS_INT(tvr.u.value)) { i = JSVAL_TO_INT(tvr.u.value); *lengthp = (jsuint)i; /* jsuint cast does ToUint32 */ } else { ok = js_ValueToECMAUint32(cx, tvr.u.value, (uint32 *)lengthp); } } JS_POP_TEMP_ROOT(cx, &tvr); return ok;}static JSBoolIndexToValue(JSContext *cx, jsuint index, jsval *vp){ if (index <= JSVAL_INT_MAX) { *vp = INT_TO_JSVAL(index); return JS_TRUE; } return js_NewDoubleValue(cx, (jsdouble)index, vp);}static JSBoolBigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, jsid *idp){ jschar buf[10], *start; JSClass *clasp; JSAtom *atom;
// JS_STATIC_ASSERT((jsuint)-1 == 4294967295U); JS_ASSERT(index > JSVAL_INT_MAX); start = JS_ARRAY_END(buf); do { --start; *start = (jschar)('0' + index % 10); index /= 10; } while (index != 0); /* * Skip the atomization if the class is known to store atoms corresponding * to big indexes together with elements. In such case we know that the * array does not have an element at the given index if its atom does not * exist. */ if (!createAtom && ((clasp = OBJ_GET_CLASS(cx, obj)) == &js_ArrayClass || clasp == &js_ArgumentsClass || clasp == &js_ObjectClass)) { atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start); if (!atom) { *idp = JSVAL_VOID; return JS_TRUE; } } else { atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0); if (!atom) return JS_FALSE; } *idp = ATOM_TO_JSID(atom); return JS_TRUE;}/* * If the property at the given index exists, get its value into location * pointed by vp and set *hole to false. Otherwise set *hole to true and *vp * to JSVAL_VOID. This function assumes that the location pointed by vp is * properly rooted and can be used as GC-protected storage for temporaries. */static JSBoolGetArrayElement(JSContext *cx, JSObject *obj, jsuint index, JSBool *hole, jsval *vp){ jsid id; JSObject *obj2; JSProperty *prop; if (index <= JSVAL_INT_MAX) { id = INT_TO_JSID(index); } else { if (!BigIndexToId(cx, obj, index, JS_FALSE, &id)) return JS_FALSE; if (id == JSVAL_VOID) { *hole = JS_TRUE; *vp = JSVAL_VOID; return JS_TRUE; } } if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) return JS_FALSE; if (!prop) { *hole = JS_TRUE; *vp = JSVAL_VOID; } else { OBJ_DROP_PROPERTY(cx, obj2, prop); if (!OBJ_GET_PROPERTY(cx, obj, id, vp)) return JS_FALSE; *hole = JS_FALSE; } return JS_TRUE;}/* * Set the value of the property at the given index to v assuming v is rooted. */static JSBoolSetArrayElement(JSContext *cx, JSObject *obj, jsuint index, jsval v){ jsid id; if (index <= JSVAL_INT_MAX) { id = INT_TO_JSID(index); } else { if (!BigIndexToId(cx, obj, index, JS_TRUE, &id)) return JS_FALSE; JS_ASSERT(id != JSVAL_VOID); } return OBJ_SET_PROPERTY(cx, obj, id, &v);}static JSBoolDeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index){ jsid id; jsval junk; if (index <= JSVAL_INT_MAX) { id = INT_TO_JSID(index); } else { if (!BigIndexToId(cx, obj, index, JS_FALSE, &id)) return JS_FALSE; if (id == JSVAL_VOID) return JS_TRUE; } return OBJ_DELETE_PROPERTY(cx, obj, id, &junk);}/* * When hole is true, delete the property at the given index. Otherwise set * its value to v assuming v is rooted. */static JSBoolSetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index, JSBool hole, jsval v){ if (hole) { JS_ASSERT(v == JSVAL_VOID); return DeleteArrayElement(cx, obj, index); } else { return SetArrayElement(cx, obj, index, v); }}JSBooljs_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length){ jsval v; jsid id; if (!IndexToValue(cx, length, &v)) return JS_FALSE; id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); return OBJ_SET_PROPERTY(cx, obj, id, &v);}JSBooljs_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp){ JSErrorReporter older; JSTempValueRooter tvr; jsid id; JSBool ok; older = JS_SetErrorReporter(cx, NULL); JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr); id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); ok = OBJ_GET_PROPERTY(cx, obj, id, &tvr.u.value); JS_SetErrorReporter(cx, older); if (ok) ok = ValueIsLength(cx, tvr.u.value, lengthp); JS_POP_TEMP_ROOT(cx, &tvr); return ok;}JSBooljs_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp){ JSClass *clasp; clasp = OBJ_GET_CLASS(cx, obj); *answerp = (clasp == &js_ArgumentsClass || clasp == &js_ArrayClass); if (!*answerp) { *lengthp = 0; return JS_TRUE; } return js_GetLengthProperty(cx, obj, lengthp);}/* * This get function is specific to Array.prototype.length and other array * instance length properties. It calls back through the class get function * in case some magic happens there (see call_getProperty in jsfun.c). */static JSBoolarray_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ return OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, id, vp);}static JSBoolarray_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ jsuint newlen, oldlen, gap, index; jsid id2; jsval junk; JSObject *iter; JSTempValueRooter tvr; JSBool ok; if (!ValueIsLength(cx, *vp, &newlen)) return JS_FALSE; if (!js_GetLengthProperty(cx, obj, &oldlen)) return JS_FALSE; if (oldlen > newlen) { if (oldlen - newlen < (1 << 24)) { do { --oldlen; if (!DeleteArrayElement(cx, obj, oldlen)) return JS_FALSE; } while (oldlen != newlen); } else { /* * We are going to remove a lot of indexes in a presumably sparse * array. So instead of looping through indexes between newlen and * oldlen, we iterate through all properties and remove those that * correspond to indexes from the [newlen, oldlen) range. * See bug 322135. */ iter = JS_NewPropertyIterator(cx, obj); if (!iter) return JS_FALSE; /* Protect iter against GC in OBJ_DELETE_PROPERTY. */ JS_PUSH_TEMP_ROOT_OBJECT(cx, iter, &tvr); gap = oldlen - newlen; for (;;) { ok = JS_NextProperty(cx, iter, &id2); if (!ok) break; if (id2 == JSVAL_VOID) break; if (js_IdIsIndex(id2, &index) && index - newlen < gap) { ok = OBJ_DELETE_PROPERTY(cx, obj, id2, &junk); if (!ok) break; } } JS_POP_TEMP_ROOT(cx, &tvr); if (!ok) return JS_FALSE; } } return IndexToValue(cx, newlen, vp);}static JSBoolarray_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ jsuint index, length; if (!js_IdIsIndex(id, &index)) return JS_TRUE; if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (index >= length) { length = index + 1; return js_SetLengthProperty(cx, obj, length); } return JS_TRUE;}static JSBoolarray_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp){ return js_TryValueOf(cx, obj, type, vp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?