📄 jsarray.c
字号:
chars[nchars] = 0; str = js_NewString(cx, chars, nchars, 0); if (!str) { free(chars); return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE;}static jschar comma_space_ucstr[] = {',', ' ', 0};static jschar comma_ucstr[] = {',', 0};static JSString comma_space = {2, comma_space_ucstr};static JSString comma = {1, comma_ucstr};#if JS_HAS_TOSOURCEstatic JSBoolarray_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ return array_join_sub(cx, obj, &comma_space, JS_TRUE, rval, JS_FALSE);}#endifstatic JSBoolarray_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ JSBool literalize; /* * JS1.2 arrays convert to array literals, with a comma followed by a space * between each element. */ literalize = (cx->version == JSVERSION_1_2); return array_join_sub(cx, obj, literalize ? &comma_space : &comma, literalize, rval, JS_FALSE);}static JSBoolarray_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ /* * Passing comma here as the separator. Need a way to get a * locale-specific version. */ return array_join_sub(cx, obj, &comma, JS_FALSE, rval, JS_TRUE);}static JSBoolInitArrayElements(JSContext *cx, JSObject *obj, jsuint length, jsval *vector){ jsuint index; jsid id; for (index = 0; index < length; index++) { if (!IndexToId(cx, index, &id)) return JS_FALSE; if (!OBJ_SET_PROPERTY(cx, obj, id, &vector[index])) return JS_FALSE; } return JS_TRUE;}static JSBoolInitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector){ jsval v; jsid id; if (!IndexToValue(cx, length, &v)) return JS_FALSE; id = (jsid) cx->runtime->atomState.lengthAtom; if (!OBJ_DEFINE_PROPERTY(cx, obj, id, v, array_length_getter, array_length_setter, JSPROP_PERMANENT, NULL)) { return JS_FALSE; } if (!vector) return JS_TRUE; return InitArrayElements(cx, obj, length, vector);}#if JS_HAS_SOME_PERL_FUN/* * Perl-inspired join, reverse, and sort. */static JSBoolarray_join(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ JSString *str; if (JSVAL_IS_VOID(argv[0])) return array_join_sub(cx, obj, &comma, JS_FALSE, rval, JS_FALSE); str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; argv[0] = STRING_TO_JSVAL(str); return array_join_sub(cx, obj, str, JS_FALSE, rval, JS_FALSE);}static JSBoolarray_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsuint len, half, i; jsid id, id2; jsval v, v2; if (!js_GetLengthProperty(cx, obj, &len)) return JS_FALSE; half = len / 2; for (i = 0; i < half; i++) { if (!IndexToId(cx, i, &id)) return JS_FALSE; if (!IndexToId(cx, len - i - 1, &id2)) return JS_FALSE; if (!OBJ_GET_PROPERTY(cx, obj, id, &v)) return JS_FALSE; if (!OBJ_GET_PROPERTY(cx, obj, id2, &v2)) return JS_FALSE;#if JS_HAS_SPARSE_ARRAYS /* This part isn't done yet. */ if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) return JS_FALSE; if (!prop) { OBJ_DELETE_PROPERTY(cx, obj, id2, &v); /* v is junk. */ continue; } OBJ_DROP_PROPERTY(cx, obj2, prop);#endif if (!OBJ_SET_PROPERTY(cx, obj, id, &v2)) return JS_FALSE; if (!OBJ_SET_PROPERTY(cx, obj, id2, &v)) return JS_FALSE; } *rval = OBJECT_TO_JSVAL(obj); return JS_TRUE;}typedef struct HSortArgs { void *vec; size_t elsize; void *pivot; JSComparator cmp; void *arg; JSBool fastcopy;} HSortArgs;static intsort_compare(const void *a, const void *b, void *arg);static intsort_compare_strings(const void *a, const void *b, void *arg);static voidHeapSortHelper(JSBool building, HSortArgs *hsa, size_t lo, size_t hi){ void *pivot, *vec, *vec2, *arg, *a, *b; size_t elsize; JSComparator cmp; JSBool fastcopy; size_t j, hiDiv2; pivot = hsa->pivot; vec = hsa->vec; elsize = hsa->elsize; vec2 = (char *)vec - 2 * elsize; cmp = hsa->cmp; arg = hsa->arg; fastcopy = hsa->fastcopy;#define MEMCPY(p,q,n) \ (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n)) if (lo == 1) { j = 2; b = (char *)vec + elsize; if (j < hi && cmp(vec, b, arg) < 0) j++; a = (char *)vec + (hi - 1) * elsize; b = (char *)vec2 + j * elsize; /* * During sorting phase b points to a member of heap that cannot be * bigger then biggest of vec[0] and vec[1], and cmp(a, b, arg) <= 0 * always holds. */ if ((building || hi == 2) && cmp(a, b, arg) >= 0) return; MEMCPY(pivot, a, elsize); MEMCPY(a, b, elsize); lo = j; } else { a = (char *)vec2 + lo * elsize; MEMCPY(pivot, a, elsize); } hiDiv2 = hi/2; while (lo <= hiDiv2) { j = lo + lo; a = (char *)vec2 + j * elsize; b = (char *)vec + (j - 1) * elsize; if (j < hi && cmp(a, b, arg) < 0) j++; b = (char *)vec2 + j * elsize; if (cmp(pivot, b, arg) >= 0) break; a = (char *)vec2 + lo * elsize; MEMCPY(a, b, elsize); lo = j; } a = (char *)vec2 + lo * elsize; MEMCPY(a, pivot, elsize);#undef MEMCPY}JSBooljs_HeapSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, void *arg) { void *pivot; HSortArgs hsa; size_t i; pivot = malloc(elsize); if (!pivot) return JS_FALSE; hsa.vec = vec; hsa.elsize = elsize; hsa.pivot = pivot; hsa.cmp = cmp; hsa.arg = arg; hsa.fastcopy = (cmp == sort_compare || cmp == sort_compare_strings); for (i = nel/2; i != 0; i--) HeapSortHelper(JS_TRUE, &hsa, i, nel); while (nel > 2) HeapSortHelper(JS_FALSE, &hsa, 1, --nel); free(pivot); return JS_TRUE;}typedef struct CompareArgs { JSContext *context; jsval fval; JSBool status;} CompareArgs;static intsort_compare(const void *a, const void *b, void *arg){ jsval av = *(const jsval *)a, bv = *(const jsval *)b; CompareArgs *ca = (CompareArgs *) arg; JSContext *cx = ca->context; jsdouble cmp = -1; jsval fval, argv[2], rval; JSBool ok; fval = ca->fval; if (fval == JSVAL_NULL) { JSString *astr, *bstr; if (av == bv) { cmp = 0; } else if (av == JSVAL_VOID || bv == JSVAL_VOID) { /* Put undefined properties at the end. */ cmp = (av == JSVAL_VOID) ? 1 : -1; } else if ((astr = js_ValueToString(cx, av)) != NULL && (bstr = js_ValueToString(cx, bv)) != NULL) { cmp = js_CompareStrings(astr, bstr); } else { ca->status = JS_FALSE; } } else { argv[0] = av; argv[1] = bv; ok = js_InternalCall(cx, OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fval)), fval, 2, argv, &rval); if (ok) { ok = js_ValueToNumber(cx, rval, &cmp); /* Clamp cmp to -1, 0, 1. */ if (JSDOUBLE_IS_NaN(cmp)) { /* XXX report some kind of error here? ECMA talks about * 'consistent compare functions' that don't return NaN, but is * silent about what the result should be. So we currently * ignore it. */ cmp = 0; } else if (cmp > 0) { cmp = 1; } else if (cmp < 0) { cmp = -1; } else { cmp = 0; } } else { ca->status = ok; } } return (int)cmp;}static intsort_compare_strings(const void *a, const void *b, void *arg){ jsval av = *(const jsval *)a, bv = *(const jsval *)b; return (int) js_CompareStrings(JSVAL_TO_STRING(av), JSVAL_TO_STRING(bv));}/* XXXmccabe do the sort helper functions need to take int? (Or can we claim * that 2^32 * 32 is too large to worry about?) Something dumps when I change * to unsigned int; is qsort using -1 as a fencepost? */static JSBoolarray_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsval fval; CompareArgs ca; jsuint len, newlen, i; jsval *vec; jsid id; size_t nbytes; /* * Optimize the default compare function case if all of obj's elements * have values of type string. */ JSBool all_strings; if (argc > 0) { if (JSVAL_IS_PRIMITIVE(argv[0])) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); return JS_FALSE; } fval = argv[0]; all_strings = JS_FALSE; /* non-default compare function */ } else { fval = JSVAL_NULL; all_strings = JS_TRUE; /* check for all string values */ } if (!js_GetLengthProperty(cx, obj, &len)) return JS_FALSE; if (len == 0) { *rval = OBJECT_TO_JSVAL(obj); return JS_TRUE; } /* * Test for size_t overflow, which could lead to indexing beyond the end * of the malloc'd vector. */ nbytes = len * sizeof(jsval); if ((double) nbytes < (double) len * sizeof(jsval)) { JS_ReportOutOfMemory(cx); return JS_FALSE; } vec = (jsval *) JS_malloc(cx, nbytes); if (!vec) return JS_FALSE;#if JS_HAS_SPARSE_ARRAYS newlen = 0;#else newlen = len;#endif for (i = 0; i < len; i++) { ca.status = IndexToId(cx, i, &id); if (!ca.status) goto out;#if JS_HAS_SPARSE_ARRAYS { JSObject *obj2; JSProperty *prop; ca.status = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); if (!ca.status) goto out; if (!prop) { vec[i] = JSVAL_VOID; continue; } OBJ_DROP_PROPERTY(cx, obj2, prop); newlen++; }#endif ca.status = OBJ_GET_PROPERTY(cx, obj, id, &vec[i]); if (!ca.status) goto out; /* We know JSVAL_IS_STRING yields 0 or 1, so avoid a branch via &=. */ all_strings &= JSVAL_IS_STRING(vec[i]); } ca.context = cx; ca.fval = fval; ca.status = JS_TRUE; if (!js_HeapSort(vec, (size_t) len, sizeof(jsval), all_strings ? sort_compare_strings : sort_compare, &ca)) { JS_ReportOutOfMemory(cx); ca.status = JS_FALSE; } if (ca.status) { ca.status = InitArrayElements(cx, obj, newlen, vec); if (ca.status) *rval = OBJECT_TO_JSVAL(obj);#if JS_HAS_SPARSE_ARRAYS /* set length of newly-created array object to old length. */ if (ca.status && newlen < len) { ca.status = js_SetLengthProperty(cx, obj, len); /* Delete any leftover properties greater than newlen. */ while (ca.status && newlen < len) { jsval junk; ca.status = !IndexToId(cx, newlen, &id) || !OBJ_DELETE_PROPERTY(cx, obj, id, &junk); newlen++; } }#endif }out: if (vec) JS_free(cx, vec); return ca.status;}#endif /* JS_HAS_SOME_PERL_FUN */#if JS_HAS_MORE_PERL_FUN/* * Perl-inspired push, pop, shift, unshift, and splice methods. */static JSBoolarray_push(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ jsuint length; uintN i; jsid id; if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; for (i = 0; i < argc; i++) { if (!IndexToId(cx, length + i, &id)) return JS_FALSE; if (!OBJ_SET_PROPERTY(cx, obj, id, &argv[i])) return JS_FALSE; } /* * If JS1.2, follow Perl4 by returning the last thing pushed. Otherwise, * return the new array length. */ length += argc; if (cx->version == JSVERSION_1_2) { *rval = argc ? argv[argc-1] : JSVAL_VOID; } else { if (!IndexToValue(cx, length, rval)) return JS_FALSE; } return js_SetLengthProperty(cx, obj, length);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -