From a0570086c698f78ec829cafd7d8d7ac3906abbc1 Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Sat, 9 Dec 2023 12:33:05 +0100 Subject: [PATCH] added Array.prototype.findLast{Index} and TypeArray.prototype.findLast{index} (initial patch by bnoordhuis) --- quickjs.c | 77 +++++++++++++++++++++++++++++++++++++++++----------- test262.conf | 2 +- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/quickjs.c b/quickjs.c index d80d601..4c4d273 100644 --- a/quickjs.c +++ b/quickjs.c @@ -38496,13 +38496,21 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +enum { + special_find, + special_findIndex, + special_findLast, + special_findLastIndex, +}; + static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue obj, val, index_val, res; - int64_t len, k; + int64_t len, k, end; + int dir; index_val = JS_UNDEFINED; val = JS_UNDEFINED; @@ -38518,7 +38526,18 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + // TODO(bnoordhuis) add fast path for fast arrays + for(; k != end; k += dir) { index_val = JS_NewInt64(ctx, k); if (JS_IsException(index_val)) goto exception; @@ -38532,7 +38551,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); JS_FreeValue(ctx, obj); return index_val; @@ -38546,7 +38565,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, index_val); } JS_FreeValue(ctx, obj); - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -39369,8 +39388,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, special_findLastIndex ), JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), JS_CFUNC_DEF("includes", 1, js_array_includes ), @@ -50725,8 +50746,19 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* XXX: create auto_initializer */ { /* initialize Array.prototype[Symbol.unscopables] */ - char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0" - "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0"; + char const unscopables[] = + "copyWithin" "\0" + "entries" "\0" + "fill" "\0" + "find" "\0" + "findIndex" "\0" + "findLast" "\0" + "findLastIndex" "\0" + "flat" "\0" + "flatMap" "\0" + "includes" "\0" + "keys" "\0" + "values" "\0"; const char *p = unscopables; obj1 = JS_NewObjectProto(ctx, JS_NULL); for(p = unscopables; *p; p += strlen(p) + 1) { @@ -51791,12 +51823,13 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, } static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue val, index_val, res; - int len, k; + int len, k, end; + int dir; val = JS_UNDEFINED; len = js_typed_array_get_length_internal(ctx, this_val); @@ -51811,7 +51844,17 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + for(; k != end; k += dir) { index_val = JS_NewInt32(ctx, k); val = JS_GetPropertyValue(ctx, this_val, index_val); if (JS_IsException(val)) @@ -51823,7 +51866,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); return index_val; } else { @@ -51832,7 +51875,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, val); } - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -52630,8 +52673,10 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ), JS_CFUNC_DEF("fill", 1, js_typed_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, special_findLastIndex ), JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ), JS_CFUNC_DEF("slice", 2, js_typed_array_slice ), JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ), diff --git a/test262.conf b/test262.conf index 49fdca6..c4349f1 100644 --- a/test262.conf +++ b/test262.conf @@ -55,7 +55,7 @@ __setter__ AggregateError align-detached-buffer-semantics-with-web-reality arbitrary-module-namespace-names=skip -array-find-from-last=skip +array-find-from-last array-grouping=skip Array.fromAsync=skip Array.prototype.at