Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/mujs/jsarray.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/mujs/jsarray.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,751 @@ +#include "jsi.h" + +int js_getlength(js_State *J, int idx) +{ + int len; + js_getproperty(J, idx, "length"); + len = js_tointeger(J, -1); + js_pop(J, 1); + return len; +} + +void js_setlength(js_State *J, int idx, int len) +{ + js_pushnumber(J, len); + js_setproperty(J, idx < 0 ? idx - 1 : idx, "length"); +} + +static void jsB_new_Array(js_State *J) +{ + int i, top = js_gettop(J); + + js_newarray(J); + + if (top == 2) { + if (js_isnumber(J, 1)) { + js_copy(J, 1); + js_setproperty(J, -2, "length"); + } else { + js_copy(J, 1); + js_setindex(J, -2, 0); + } + } else { + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, -2, i - 1); + } + } +} + +static void Ap_concat(js_State *J) +{ + int i, top = js_gettop(J); + int n, k, len; + + js_newarray(J); + n = 0; + + for (i = 0; i < top; ++i) { + js_copy(J, i); + if (js_isarray(J, -1)) { + len = js_getlength(J, -1); + for (k = 0; k < len; ++k) + if (js_hasindex(J, -1, k)) + js_setindex(J, -3, n++); + js_pop(J, 1); + } else { + js_setindex(J, -2, n++); + } + } +} + +static void Ap_join(js_State *J) +{ + char * volatile out = NULL; + const char * volatile r = NULL; + const char *sep; + int seplen; + int k, n, len, rlen; + + len = js_getlength(J, 0); + + if (js_isdefined(J, 1)) { + sep = js_tostring(J, 1); + seplen = strlen(sep); + } else { + sep = ","; + seplen = 1; + } + + if (len <= 0) { + js_pushliteral(J, ""); + return; + } + + if (js_try(J)) { + js_free(J, out); + js_throw(J); + } + + n = 0; + for (k = 0; k < len; ++k) { + js_getindex(J, 0, k); + if (js_iscoercible(J, -1)) { + r = js_tostring(J, -1); + rlen = strlen(r); + } else { + rlen = 0; + } + + if (k == 0) { + out = js_malloc(J, rlen + 1); + if (rlen > 0) { + memcpy(out, r, rlen); + n += rlen; + } + } else { + if (n + seplen + rlen > JS_STRLIMIT) + js_rangeerror(J, "invalid string length"); + out = js_realloc(J, out, n + seplen + rlen + 1); + if (seplen > 0) { + memcpy(out + n, sep, seplen); + n += seplen; + } + if (rlen > 0) { + memcpy(out + n, r, rlen); + n += rlen; + } + } + + js_pop(J, 1); + } + + js_pushlstring(J, out, n); + js_endtry(J); + js_free(J, out); +} + +static void Ap_pop(js_State *J) +{ + int n; + + n = js_getlength(J, 0); + + if (n > 0) { + js_getindex(J, 0, n - 1); + js_delindex(J, 0, n - 1); + js_setlength(J, 0, n - 1); + } else { + js_setlength(J, 0, 0); + js_pushundefined(J); + } +} + +static void Ap_push(js_State *J) +{ + int i, top = js_gettop(J); + int n; + + n = js_getlength(J, 0); + + for (i = 1; i < top; ++i, ++n) { + js_copy(J, i); + js_setindex(J, 0, n); + } + + js_setlength(J, 0, n); + + js_pushnumber(J, n); +} + +static void Ap_reverse(js_State *J) +{ + int len, middle, lower; + + len = js_getlength(J, 0); + middle = len / 2; + lower = 0; + + while (lower != middle) { + int upper = len - lower - 1; + int haslower = js_hasindex(J, 0, lower); + int hasupper = js_hasindex(J, 0, upper); + if (haslower && hasupper) { + js_setindex(J, 0, lower); + js_setindex(J, 0, upper); + } else if (hasupper) { + js_setindex(J, 0, lower); + js_delindex(J, 0, upper); + } else if (haslower) { + js_setindex(J, 0, upper); + js_delindex(J, 0, lower); + } + ++lower; + } + + js_copy(J, 0); +} + +static void Ap_shift(js_State *J) +{ + int k, len; + + len = js_getlength(J, 0); + + if (len == 0) { + js_setlength(J, 0, 0); + js_pushundefined(J); + return; + } + + js_getindex(J, 0, 0); + + for (k = 1; k < len; ++k) { + if (js_hasindex(J, 0, k)) + js_setindex(J, 0, k - 1); + else + js_delindex(J, 0, k - 1); + } + + js_delindex(J, 0, len - 1); + js_setlength(J, 0, len - 1); +} + +static void Ap_slice(js_State *J) +{ + int len, s, e, n; + double sv, ev; + + js_newarray(J); + + len = js_getlength(J, 0); + sv = js_tointeger(J, 1); + ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; + + if (sv < 0) sv = sv + len; + if (ev < 0) ev = ev + len; + + s = sv < 0 ? 0 : sv > len ? len : sv; + e = ev < 0 ? 0 : ev > len ? len : ev; + + for (n = 0; s < e; ++s, ++n) + if (js_hasindex(J, 0, s)) + js_setindex(J, -2, n); +} + +struct sortslot { + js_Value v; + js_State *J; +}; + +static int sortcmp(const void *avoid, const void *bvoid) +{ + const struct sortslot *aslot = avoid, *bslot = bvoid; + const js_Value *a = &aslot->v, *b = &bslot->v; + js_State *J = aslot->J; + const char *sx, *sy; + double v; + int c; + + int unx = (a->t.type == JS_TUNDEFINED); + int uny = (b->t.type == JS_TUNDEFINED); + if (unx) return !uny; + if (uny) return -1; + + if (js_iscallable(J, 1)) { + js_copy(J, 1); /* copy function */ + js_pushundefined(J); + js_pushvalue(J, *a); + js_pushvalue(J, *b); + js_call(J, 2); + v = js_tonumber(J, -1); + c = (v == 0) ? 0 : (v < 0) ? -1 : 1; + js_pop(J, 1); + } else { + js_pushvalue(J, *a); + js_pushvalue(J, *b); + sx = js_tostring(J, -2); + sy = js_tostring(J, -1); + c = strcmp(sx, sy); + js_pop(J, 2); + } + return c; +} + +static void Ap_sort(js_State *J) +{ + struct sortslot * volatile array = NULL; + int i, n, len; + + len = js_getlength(J, 0); + if (len <= 0) { + js_copy(J, 0); + return; + } + + if (len >= INT_MAX / (int)sizeof(*array)) + js_rangeerror(J, "array is too large to sort"); + + /* Holding objects where the GC cannot see them is illegal, but if we + * don't allow the GC to run we can use qsort() on a temporary array of + * js_Values for fast sorting. + */ + ++J->gcpause; + + if (js_try(J)) { + --J->gcpause; + js_free(J, array); + js_throw(J); + } + + array = js_malloc(J, len * sizeof *array); + + n = 0; + for (i = 0; i < len; ++i) { + if (js_hasindex(J, 0, i)) { + array[n].v = *js_tovalue(J, -1); + array[n].J = J; + js_pop(J, 1); + ++n; + } + } + + qsort(array, n, sizeof *array, sortcmp); + + for (i = 0; i < n; ++i) { + js_pushvalue(J, array[i].v); + js_setindex(J, 0, i); + } + for (i = len-i; i >= n; --i) { + js_delindex(J, 0, i); + } + + --J->gcpause; + + js_endtry(J); + js_free(J, array); + + js_copy(J, 0); +} + +static void Ap_splice(js_State *J) +{ + int top = js_gettop(J); + int len, start, del, add, k; + + len = js_getlength(J, 0); + start = js_tointeger(J, 1); + if (start < 0) + start = (len + start) > 0 ? len + start : 0; + else if (start > len) + start = len; + + if (js_isdefined(J, 2)) + del = js_tointeger(J, 2); + else + del = len - start; + if (del > len - start) + del = len - start; + if (del < 0) + del = 0; + + js_newarray(J); + + /* copy deleted items to return array */ + for (k = 0; k < del; ++k) + if (js_hasindex(J, 0, start + k)) + js_setindex(J, -2, k); + js_setlength(J, -1, del); + + /* shift the tail to resize the hole left by deleted items */ + add = top - 3; + if (add < del) { + for (k = start; k < len - del; ++k) { + if (js_hasindex(J, 0, k + del)) + js_setindex(J, 0, k + add); + else + js_delindex(J, 0, k + add); + } + for (k = len; k > len - del + add; --k) + js_delindex(J, 0, k - 1); + } else if (add > del) { + for (k = len - del; k > start; --k) { + if (js_hasindex(J, 0, k + del - 1)) + js_setindex(J, 0, k + add - 1); + else + js_delindex(J, 0, k + add - 1); + } + } + + /* copy new items into the hole */ + for (k = 0; k < add; ++k) { + js_copy(J, 3 + k); + js_setindex(J, 0, start + k); + } + + js_setlength(J, 0, len - del + add); +} + +static void Ap_unshift(js_State *J) +{ + int i, top = js_gettop(J); + int k, len; + + len = js_getlength(J, 0); + + for (k = len; k > 0; --k) { + int from = k - 1; + int to = k + top - 2; + if (js_hasindex(J, 0, from)) + js_setindex(J, 0, to); + else + js_delindex(J, 0, to); + } + + for (i = 1; i < top; ++i) { + js_copy(J, i); + js_setindex(J, 0, i - 1); + } + + js_setlength(J, 0, len + top - 1); + + js_pushnumber(J, len + top - 1); +} + +static void Ap_toString(js_State *J) +{ + if (!js_iscoercible(J, 0)) + js_typeerror(J, "'this' is not an object"); + js_getproperty(J, 0, "join"); + if (!js_iscallable(J, -1)) { + js_pop(J, 1); + // TODO: call Object.prototype.toString implementation directly + js_getglobal(J, "Object"); + js_getproperty(J, -1, "prototype"); + js_rot2pop1(J); + js_getproperty(J, -1, "toString"); + js_rot2pop1(J); + } + js_copy(J, 0); + js_call(J, 0); +} + +static void Ap_indexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0; + if (from < 0) from = len + from; + if (from < 0) from = 0; + + js_copy(J, 1); + for (k = from; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_lastIndexOf(js_State *J) +{ + int k, len, from; + + len = js_getlength(J, 0); + from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1; + if (from > len - 1) from = len - 1; + if (from < 0) from = len + from; + + js_copy(J, 1); + for (k = from; k >= 0; --k) { + if (js_hasindex(J, 0, k)) { + if (js_strictequal(J)) { + js_pushnumber(J, k); + return; + } + js_pop(J, 1); + } + } + + js_pushnumber(J, -1); +} + +static void Ap_every(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (!js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 1); +} + +static void Ap_some(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) + return; + js_pop(J, 2); + } + } + + js_pushboolean(J, 0); +} + +static void Ap_forEach(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_pop(J, 2); + } + } + + js_pushundefined(J); +} + +static void Ap_map(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + js_setindex(J, -3, k); + js_pop(J, 1); + } + } + js_setlength(J, -1, len); +} + +static void Ap_filter(js_State *J) +{ + int hasthis = js_gettop(J) >= 3; + int k, to, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + js_newarray(J); + to = 0; + + len = js_getlength(J, 0); + for (k = 0; k < len; ++k) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + if (hasthis) + js_copy(J, 2); + else + js_pushundefined(J); + js_copy(J, -3); + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 3); + if (js_toboolean(J, -1)) { + js_pop(J, 1); + js_setindex(J, -2, to++); + } else { + js_pop(J, 2); + } + } + } +} + +static void Ap_reduce(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = 0; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k < len) + if (js_hasindex(J, 0, k++)) + break; + if (k == len) + js_typeerror(J, "no initial value"); + } + + while (k < len) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + ++k; + } + + /* return accumulator */ +} + +static void Ap_reduceRight(js_State *J) +{ + int hasinitial = js_gettop(J) >= 3; + int k, len; + + if (!js_iscallable(J, 1)) + js_typeerror(J, "callback is not a function"); + + len = js_getlength(J, 0); + k = len - 1; + + if (len == 0 && !hasinitial) + js_typeerror(J, "no initial value"); + + /* initial value of accumulator */ + if (hasinitial) + js_copy(J, 2); + else { + while (k >= 0) + if (js_hasindex(J, 0, k--)) + break; + if (k < 0) + js_typeerror(J, "no initial value"); + } + + while (k >= 0) { + if (js_hasindex(J, 0, k)) { + js_copy(J, 1); + js_pushundefined(J); + js_rot(J, 4); /* accumulator on top */ + js_rot(J, 4); /* property on top */ + js_pushnumber(J, k); + js_copy(J, 0); + js_call(J, 4); /* calculate new accumulator */ + } + --k; + } + + /* return accumulator */ +} + +static void A_isArray(js_State *J) +{ + if (js_isobject(J, 1)) { + js_Object *T = js_toobject(J, 1); + js_pushboolean(J, T->type == JS_CARRAY); + } else { + js_pushboolean(J, 0); + } +} + +void jsB_initarray(js_State *J) +{ + js_pushobject(J, J->Array_prototype); + { + jsB_propf(J, "Array.prototype.toString", Ap_toString, 0); + jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */ + jsB_propf(J, "Array.prototype.join", Ap_join, 1); + jsB_propf(J, "Array.prototype.pop", Ap_pop, 0); + jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */ + jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0); + jsB_propf(J, "Array.prototype.shift", Ap_shift, 0); + jsB_propf(J, "Array.prototype.slice", Ap_slice, 2); + jsB_propf(J, "Array.prototype.sort", Ap_sort, 1); + jsB_propf(J, "Array.prototype.splice", Ap_splice, 2); + jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */ + + /* ES5 */ + jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1); + jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1); + jsB_propf(J, "Array.prototype.every", Ap_every, 1); + jsB_propf(J, "Array.prototype.some", Ap_some, 1); + jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1); + jsB_propf(J, "Array.prototype.map", Ap_map, 1); + jsB_propf(J, "Array.prototype.filter", Ap_filter, 1); + jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1); + jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1); + } + js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */ + { + /* ES5 */ + jsB_propf(J, "Array.isArray", A_isArray, 1); + } + js_defglobal(J, "Array", JS_DONTENUM); +}
