diff --git a/quickjs.c b/quickjs.c index 1d2eaf5..33ea6a7 100644 --- a/quickjs.c +++ b/quickjs.c @@ -46241,6 +46241,105 @@ static int js_setlike_get_keys(JSContext *ctx, JSValue setlike, JSValue *pout) return 0; } +static JSValue js_set_intersection(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValue newset, item, iter, keys, has, next, rv; + JSMapState *s, *t; + JSMapRecord *mr; + int64_t size; + BOOL done; + int ok; + + has = JS_UNDEFINED; + iter = JS_UNDEFINED; + keys = JS_UNDEFINED; + next = JS_UNDEFINED; + newset = JS_UNDEFINED; + s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET); + if (!s) + goto exception; + // order matters! + if (js_setlike_get_size(ctx, argv[0], &size) < 0) + goto exception; + if (js_setlike_get_has(ctx, argv[0], &has) < 0) + goto exception; + if (js_setlike_get_keys(ctx, argv[0], &keys) < 0) + goto exception; + if (s->record_count > size) { + iter = JS_Call(ctx, keys, argv[0], 0, NULL); + if (JS_IsException(iter)) + goto exception; + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + item = map_normalize_key(ctx, item); + if (!map_find_record(ctx, s, item)) { + JS_FreeValue(ctx, item); + } else if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } + } else { + iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET); + if (JS_IsException(iter)) + goto exception; + newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); + if (JS_IsException(newset)) + goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); + for (;;) { + item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); + if (JS_IsException(item)) + goto exception; + if (done) // item is JS_UNDEFINED + break; + rv = JS_Call(ctx, has, argv[0], 1, &item); + ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION + if (ok > 0) { + item = map_normalize_key(ctx, item); + if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } else { + JS_FreeValue(ctx, item); + if (ok < 0) + goto exception; + } + } + } + goto fini; +exception: + JS_FreeValue(ctx, newset); + newset = JS_EXCEPTION; +fini: + JS_FreeValue(ctx, has); + JS_FreeValue(ctx, keys); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return newset; +} + static JSValue js_set_difference(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { @@ -46296,6 +46395,7 @@ static JSValue js_set_difference(JSContext *ctx, JSValue this_val, newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET); if (JS_IsException(newset)) goto exception; + t = JS_GetOpaque(newset, JS_CLASS_SET); for (;;) { item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET); if (JS_IsException(item)) @@ -46304,15 +46404,21 @@ static JSValue js_set_difference(JSContext *ctx, JSValue this_val, break; rv = JS_Call(ctx, has, argv[0], 1, &item); ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION - rv = JS_UNDEFINED; - if (ok == 0) - rv = js_map_set(ctx, newset, 1, &item, MAGIC_SET); - JS_FreeValue(ctx, item); - if (JS_IsException(rv)) - goto exception; - JS_FreeValue(ctx, rv); - if (ok < 0) - goto exception; + if (ok == 0) { + item = map_normalize_key(ctx, item); + if (map_find_record(ctx, t, item)) { + JS_FreeValue(ctx, item); // no duplicates + } else if ((mr = map_add_record(ctx, t, item))) { + mr->value = JS_UNDEFINED; + } else { + JS_FreeValue(ctx, item); + goto exception; + } + } else { + JS_FreeValue(ctx, item); + if (ok < 0) + goto exception; + } } } goto fini; @@ -46511,6 +46617,7 @@ static const JSCFunctionListEntry js_set_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ), JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ), JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ), + JS_CFUNC_DEF("intersection", 1, js_set_intersection ), JS_CFUNC_DEF("difference", 1, js_set_difference ), JS_CFUNC_DEF("symmetricDifference", 1, js_set_symmetricDifference ), JS_CFUNC_DEF("union", 1, js_set_union ), diff --git a/test262_errors.txt b/test262_errors.txt index 48ad730..0034884 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -72,52 +72,6 @@ test262/test/built-ins/RegExp/property-escapes/generated/XID_Start.js:16: Test26 test262/test/built-ins/RegExp/property-escapes/generated/XID_Start.js:16: strict mode: Test262Error: `\p{XID_Start}` should match U+02EBF0 (`𮯰`) test262/test/built-ins/RegExp/unicode_full_case_folding.js:20: Test262Error: \u0390 does not match \u1fd3 test262/test/built-ins/RegExp/unicode_full_case_folding.js:20: strict mode: Test262Error: \u0390 does not match \u1fd3 -test262/test/built-ins/Set/prototype/intersection/add-not-called.js:21: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/add-not-called.js:21: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/allows-set-like-class.js:32: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/allows-set-like-class.js:32: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/allows-set-like-object.js:30: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/allows-set-like-object.js:30: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/builtins.js:9: Test262Error: Built-in objects must be extensible. Expected SameValue(«false», «true») to be true -test262/test/built-ins/Set/prototype/intersection/builtins.js:9: strict mode: Test262Error: Built-in objects must be extensible. Expected SameValue(«false», «true») to be true -test262/test/built-ins/Set/prototype/intersection/combines-Map.js:16: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-Map.js:16: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-empty-sets.js:13: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-empty-sets.js:13: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-itself.js:12: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-itself.js:12: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-same-sets.js:13: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-same-sets.js:13: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-sets.js:13: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/combines-sets.js:13: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/converts-negative-zero.js:25: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/converts-negative-zero.js:25: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/intersection.js:10: Test262Error: `typeof Set.prototype.intersection` is `'function'` Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/intersection.js:10: strict mode: Test262Error: `typeof Set.prototype.intersection` is `'function'` Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/length.js:11: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/length.js:11: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/name.js:11: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/name.js:11: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/not-a-constructor.js:17: Test262Error: isConstructor invoked with a non-function value -test262/test/built-ins/Set/prototype/intersection/not-a-constructor.js:17: strict mode: Test262Error: isConstructor invoked with a non-function value -test262/test/built-ins/Set/prototype/intersection/require-internal-slot.js:17: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/require-internal-slot.js:17: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true -test262/test/built-ins/Set/prototype/intersection/result-order.js:15: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/result-order.js:15: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-array.js:23: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-array.js:23: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-class-mutation.js:44: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-class-mutation.js:44: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-class-order.js:67: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/set-like-class-order.js:67: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/size-is-a-number.js:24: Test262Error: GetSetRecord coerces size Expected SameValue(«0», «1») to be true -test262/test/built-ins/Set/prototype/intersection/size-is-a-number.js:24: strict mode: Test262Error: GetSetRecord coerces size Expected SameValue(«0», «1») to be true -test262/test/built-ins/Set/prototype/intersection/subclass-receiver-methods.js:34: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/subclass-receiver-methods.js:34: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/subclass-symbol-species.js:20: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/subclass-symbol-species.js:20: strict mode: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/subclass.js:15: TypeError: not a function -test262/test/built-ins/Set/prototype/intersection/subclass.js:15: strict mode: TypeError: not a function test262/test/built-ins/Set/prototype/isDisjointFrom/allows-set-like-class.js:30: TypeError: not a function test262/test/built-ins/Set/prototype/isDisjointFrom/allows-set-like-class.js:30: strict mode: TypeError: not a function test262/test/built-ins/Set/prototype/isDisjointFrom/allows-set-like-object.js:28: TypeError: not a function @@ -263,10 +217,4 @@ test262/test/staging/set-is-subset-table-receiver-cleared.js:25: TypeError: not test262/test/staging/set-is-subset-table-receiver-cleared.js:25: strict mode: TypeError: not a function test262/test/staging/set-is-subset-table-transition.js:28: TypeError: not a function test262/test/staging/set-is-subset-table-transition.js:28: strict mode: TypeError: not a function -test262/test/staging/set-methods/set-intersect-other-is-set-like.js:29: TypeError: not a function -test262/test/staging/set-methods/set-intersect-other-is-set-like.js:29: strict mode: TypeError: not a function -test262/test/staging/set-methods/set-intersection-other-is-map.js:22: TypeError: not a function -test262/test/staging/set-methods/set-intersection-other-is-map.js:22: strict mode: TypeError: not a function -test262/test/staging/set-methods/set-intersection-other-is-set.js:22: TypeError: not a function -test262/test/staging/set-methods/set-intersection-other-is-set.js:22: strict mode: TypeError: not a function test262/test/staging/top-level-await/tla-hang-entry.js:10: TypeError: $DONE() not called