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 + -
显示快捷键?