From: Fabrice Bellard Date: Tue, 13 Oct 2026 15:39:02 +0000 (+0200) Subject: added Iterator.prototype.includes (saghul) X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D/1?a=commitdiff_plain;h=7bb3e9ea01ebb64cc1456fdf5cbba2fe87ef04ad;p=quickjs.git added Iterator.prototype.includes (saghul) --- diff --git a/quickjs.c b/quickjs.c index 5323bdf..01876e2 100644 --- a/quickjs.c +++ b/quickjs.c @@ -45736,6 +45736,71 @@ static JSValue js_iterator_proto_func(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +static JSValue js_iterator_proto_includes(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue item, method; + int64_t to_skip, skipped; + double d; + int done; + + if (!JS_IsObject(this_val)) + return JS_ThrowTypeErrorNotAnObject(ctx); + + // skippedElements is deliberately not coerced: anything that isn't an + // integral Number (or +/-Infinity) is a TypeError, and the underlying + // iterator is closed before the error propagates. + to_skip = 0; + if (argc > 1 && !JS_IsUndefined(argv[1])) { + if (!JS_IsNumber(argv[1])) { + JS_ThrowTypeError(ctx, "not a number"); + goto fail; + } + JS_ToFloat64(ctx, &d, argv[1]); // cannot fail + if (isnan(d) || (isfinite(d) && trunc(d) != d)) { + JS_ThrowTypeError(ctx, "not an integral number"); + goto fail; + } + if (d < 0 || (isfinite(d) && d > MAX_SAFE_INTEGER)) { + JS_ThrowRangeError(ctx, "must be positive"); + goto fail; + } + // +Infinity means "skip everything"; use MAX_SAFE_INTEGER + to_skip = isfinite(d) ? (int64_t)d : MAX_SAFE_INTEGER; + } + + // Note: a failure here propagates without closing the iterator. + method = JS_GetProperty(ctx, this_val, JS_ATOM_next); + if (JS_IsException(method)) + return JS_EXCEPTION; + + for (skipped = 0; /*empty*/; /*empty*/) { + item = JS_IteratorNext(ctx, this_val, method, &done); + if (JS_IsException(item)) { + // IteratorStepValue marks the iterator done, it does not close it. + JS_FreeValue(ctx, method); + return JS_EXCEPTION; + } + if (done) { + JS_FreeValue(ctx, method); + return JS_FALSE; + } + if (skipped < to_skip) { + skipped++; + } else if (js_same_value_zero(ctx, item, argv[0])) { + JS_FreeValue(ctx, item); + JS_FreeValue(ctx, method); + if (JS_IteratorClose(ctx, this_val, false) < 0) + return JS_EXCEPTION; + return JS_TRUE; + } + JS_FreeValue(ctx, item); + } +fail: + JS_IteratorClose(ctx, this_val, true); + return JS_EXCEPTION; +} + static JSValue js_iterator_proto_reduce(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -46182,6 +46247,7 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("find", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND), JS_CFUNC_MAGIC_DEF("forEach", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ), JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ), + JS_CFUNC_DEF("includes", 1, js_iterator_proto_includes ), JS_CFUNC_DEF("join", 1, js_iterator_proto_join ), JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ), JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ), diff --git a/test262.conf b/test262.conf index 1c65c94..fa2954f 100644 --- a/test262.conf +++ b/test262.conf @@ -151,7 +151,7 @@ IsHTMLDDA Iterator.prototype.join iterator-chunking=skip iterator-helpers -iterator-includes=skip +iterator-includes iterator-sequencing json-modules json-parse-with-source