Skip to content

Commit 6ba2448

Browse files
authored
Add Set.prototype.symmetricDifference (#507)
1 parent 61c8fe6 commit 6ba2448

File tree

2 files changed

+93
-50
lines changed

2 files changed

+93
-50
lines changed

quickjs.c

+93-4
Original file line numberDiff line numberDiff line change
@@ -46327,13 +46327,100 @@ static JSValue js_set_difference(JSContext *ctx, JSValue this_val,
4632746327
return newset;
4632846328
}
4632946329

46330+
static JSValue js_set_symmetricDifference(JSContext *ctx, JSValue this_val,
46331+
int argc, JSValue *argv)
46332+
{
46333+
JSValue newset, item, iter, next, rv;
46334+
struct list_head *el;
46335+
JSMapState *s, *t;
46336+
JSMapRecord *mr;
46337+
int64_t size;
46338+
BOOL done, present;
46339+
46340+
s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
46341+
if (!s)
46342+
return JS_EXCEPTION;
46343+
// order matters! they're JS-observable side effects
46344+
if (js_setlike_get_size(ctx, argv[0], &size) < 0)
46345+
return JS_EXCEPTION;
46346+
if (js_setlike_get_has(ctx, argv[0], &rv) < 0)
46347+
return JS_EXCEPTION;
46348+
JS_FreeValue(ctx, rv);
46349+
newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
46350+
if (JS_IsException(newset))
46351+
return JS_EXCEPTION;
46352+
t = JS_GetOpaque(newset, JS_CLASS_SET);
46353+
iter = JS_UNDEFINED;
46354+
next = JS_UNDEFINED;
46355+
// can't clone this_val using js_map_constructor(),
46356+
// test262 mandates we don't call the .add method
46357+
list_for_each(el, &s->records) {
46358+
mr = list_entry(el, JSMapRecord, link);
46359+
if (mr->empty)
46360+
continue;
46361+
mr = map_add_record(ctx, t, js_dup(mr->key));
46362+
if (!mr)
46363+
goto exception;
46364+
mr->value = JS_UNDEFINED;
46365+
}
46366+
iter = JS_GetProperty(ctx, argv[0], JS_ATOM_keys);
46367+
if (JS_IsException(iter))
46368+
goto exception;
46369+
iter = JS_CallFree(ctx, iter, argv[0], 0, NULL);
46370+
if (JS_IsException(iter))
46371+
goto exception;
46372+
next = JS_GetProperty(ctx, iter, JS_ATOM_next);
46373+
if (JS_IsException(next))
46374+
goto exception;
46375+
for (;;) {
46376+
item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
46377+
if (JS_IsException(item))
46378+
goto exception;
46379+
if (done) // item is JS_UNDEFINED
46380+
break;
46381+
// note the subtlety here: due to mutating iterators, it's
46382+
// possible for keys to disappear during iteration; test262
46383+
// still expects us to maintain insertion order though, so
46384+
// we first check |this|, then |new|; |new| is a copy of |this|
46385+
// - if item exists in |this|, delete (if it exists) from |new|
46386+
// - if item misses in |this| and |new|, add to |new|
46387+
// - if item exists in |new| but misses in |this|, *don't* add it,
46388+
// mutating iterator erased it
46389+
item = map_normalize_key(ctx, item);
46390+
present = (NULL != map_find_record(ctx, s, item));
46391+
mr = map_find_record(ctx, t, item);
46392+
if (present) {
46393+
if (mr)
46394+
map_delete_record(ctx->rt, t, mr);
46395+
JS_FreeValue(ctx, item);
46396+
} else if (mr) {
46397+
JS_FreeValue(ctx, item);
46398+
} else {
46399+
mr = map_add_record(ctx, t, item);
46400+
if (!mr) {
46401+
JS_FreeValue(ctx, item);
46402+
goto exception;
46403+
}
46404+
mr->value = JS_UNDEFINED;
46405+
}
46406+
}
46407+
goto fini;
46408+
exception:
46409+
JS_FreeValue(ctx, newset);
46410+
newset = JS_EXCEPTION;
46411+
fini:
46412+
JS_FreeValue(ctx, next);
46413+
JS_FreeValue(ctx, iter);
46414+
return newset;
46415+
}
46416+
4633046417
static JSValue js_set_union(JSContext *ctx, JSValue this_val,
4633146418
int argc, JSValue *argv)
4633246419
{
4633346420
JSValue newset, item, iter, next, rv;
4633446421
struct list_head *el;
46422+
JSMapState *s, *t;
4633546423
JSMapRecord *mr;
46336-
JSMapState *s;
4633746424
int64_t size;
4633846425
BOOL done;
4633946426

@@ -46349,16 +46436,17 @@ static JSValue js_set_union(JSContext *ctx, JSValue this_val,
4634946436
newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
4635046437
if (JS_IsException(newset))
4635146438
return JS_EXCEPTION;
46439+
t = JS_GetOpaque(newset, JS_CLASS_SET);
4635246440
iter = JS_UNDEFINED;
4635346441
next = JS_UNDEFINED;
4635446442
list_for_each(el, &s->records) {
4635546443
mr = list_entry(el, JSMapRecord, link);
4635646444
if (mr->empty)
4635746445
continue;
46358-
rv = js_map_set(ctx, newset, 1, &mr->key, MAGIC_SET);
46359-
if (JS_IsException(rv))
46446+
mr = map_add_record(ctx, t, js_dup(mr->key));
46447+
if (!mr)
4636046448
goto exception;
46361-
JS_FreeValue(ctx, rv);
46449+
mr->value = JS_UNDEFINED;
4636246450
}
4636346451
iter = JS_GetProperty(ctx, argv[0], JS_ATOM_keys);
4636446452
if (JS_IsException(iter))
@@ -46424,6 +46512,7 @@ static const JSCFunctionListEntry js_set_proto_funcs[] = {
4642446512
JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
4642546513
JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
4642646514
JS_CFUNC_DEF("difference", 1, js_set_difference ),
46515+
JS_CFUNC_DEF("symmetricDifference", 1, js_set_symmetricDifference ),
4642746516
JS_CFUNC_DEF("union", 1, js_set_union ),
4642846517
JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
4642946518
JS_ALIAS_DEF("keys", "values" ),

test262_errors.txt

-46
Original file line numberDiff line numberDiff line change
@@ -230,52 +230,6 @@ test262/test/built-ins/Set/prototype/isSupersetOf/size-is-a-number.js:24: Test26
230230
test262/test/built-ins/Set/prototype/isSupersetOf/size-is-a-number.js:24: strict mode: Test262Error: GetSetRecord coerces size Expected SameValue(«0», «1») to be true
231231
test262/test/built-ins/Set/prototype/isSupersetOf/subclass-receiver-methods.js:32: TypeError: not a function
232232
test262/test/built-ins/Set/prototype/isSupersetOf/subclass-receiver-methods.js:32: strict mode: TypeError: not a function
233-
test262/test/built-ins/Set/prototype/symmetricDifference/add-not-called.js:21: TypeError: not a function
234-
test262/test/built-ins/Set/prototype/symmetricDifference/add-not-called.js:21: strict mode: TypeError: not a function
235-
test262/test/built-ins/Set/prototype/symmetricDifference/allows-set-like-class.js:31: TypeError: not a function
236-
test262/test/built-ins/Set/prototype/symmetricDifference/allows-set-like-class.js:31: strict mode: TypeError: not a function
237-
test262/test/built-ins/Set/prototype/symmetricDifference/allows-set-like-object.js:29: TypeError: not a function
238-
test262/test/built-ins/Set/prototype/symmetricDifference/allows-set-like-object.js:29: strict mode: TypeError: not a function
239-
test262/test/built-ins/Set/prototype/symmetricDifference/builtins.js:9: Test262Error: Built-in objects must be extensible. Expected SameValue(«false», «true») to be true
240-
test262/test/built-ins/Set/prototype/symmetricDifference/builtins.js:9: strict mode: Test262Error: Built-in objects must be extensible. Expected SameValue(«false», «true») to be true
241-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-Map.js:16: TypeError: not a function
242-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-Map.js:16: strict mode: TypeError: not a function
243-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-empty-sets.js:13: TypeError: not a function
244-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-empty-sets.js:13: strict mode: TypeError: not a function
245-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-itself.js:12: TypeError: not a function
246-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-itself.js:12: strict mode: TypeError: not a function
247-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-same-sets.js:13: TypeError: not a function
248-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-same-sets.js:13: strict mode: TypeError: not a function
249-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-sets.js:13: TypeError: not a function
250-
test262/test/built-ins/Set/prototype/symmetricDifference/combines-sets.js:13: strict mode: TypeError: not a function
251-
test262/test/built-ins/Set/prototype/symmetricDifference/converts-negative-zero.js:25: TypeError: not a function
252-
test262/test/built-ins/Set/prototype/symmetricDifference/converts-negative-zero.js:25: strict mode: TypeError: not a function
253-
test262/test/built-ins/Set/prototype/symmetricDifference/length.js:11: Test262Error: Expected SameValue(«undefined», «function») to be true
254-
test262/test/built-ins/Set/prototype/symmetricDifference/length.js:11: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true
255-
test262/test/built-ins/Set/prototype/symmetricDifference/name.js:11: Test262Error: Expected SameValue(«undefined», «function») to be true
256-
test262/test/built-ins/Set/prototype/symmetricDifference/name.js:11: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true
257-
test262/test/built-ins/Set/prototype/symmetricDifference/not-a-constructor.js:17: Test262Error: isConstructor invoked with a non-function value
258-
test262/test/built-ins/Set/prototype/symmetricDifference/not-a-constructor.js:17: strict mode: Test262Error: isConstructor invoked with a non-function value
259-
test262/test/built-ins/Set/prototype/symmetricDifference/require-internal-slot.js:17: Test262Error: Expected SameValue(«undefined», «function») to be true
260-
test262/test/built-ins/Set/prototype/symmetricDifference/require-internal-slot.js:17: strict mode: Test262Error: Expected SameValue(«undefined», «function») to be true
261-
test262/test/built-ins/Set/prototype/symmetricDifference/result-order.js:15: TypeError: not a function
262-
test262/test/built-ins/Set/prototype/symmetricDifference/result-order.js:15: strict mode: TypeError: not a function
263-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-array.js:21: TypeError: not a function
264-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-array.js:21: strict mode: TypeError: not a function
265-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-class-mutation.js:44: TypeError: not a function
266-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-class-mutation.js:44: strict mode: TypeError: not a function
267-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-class-order.js:66: TypeError: not a function
268-
test262/test/built-ins/Set/prototype/symmetricDifference/set-like-class-order.js:66: strict mode: TypeError: not a function
269-
test262/test/built-ins/Set/prototype/symmetricDifference/size-is-a-number.js:24: Test262Error: GetSetRecord coerces size Expected SameValue(«0», «1») to be true
270-
test262/test/built-ins/Set/prototype/symmetricDifference/size-is-a-number.js:24: strict mode: Test262Error: GetSetRecord coerces size Expected SameValue(«0», «1») to be true
271-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass-receiver-methods.js:34: TypeError: not a function
272-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass-receiver-methods.js:34: strict mode: TypeError: not a function
273-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass-symbol-species.js:20: TypeError: not a function
274-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass-symbol-species.js:20: strict mode: TypeError: not a function
275-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass.js:15: TypeError: not a function
276-
test262/test/built-ins/Set/prototype/symmetricDifference/subclass.js:15: strict mode: TypeError: not a function
277-
test262/test/built-ins/Set/prototype/symmetricDifference/symmetricDifference.js:10: Test262Error: `typeof Set.prototype.symmetricDifference` is `'function'` Expected SameValue(«undefined», «function») to be true
278-
test262/test/built-ins/Set/prototype/symmetricDifference/symmetricDifference.js:10: strict mode: Test262Error: `typeof Set.prototype.symmetricDifference` is `'function'` Expected SameValue(«undefined», «function») to be true
279233
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js:35: Test262Error: value should not be coerced Expected SameValue(«22», «0») to be true
280234
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js:35: strict mode: Test262Error: value should not be coerced Expected SameValue(«22», «0») to be true
281235
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js:35: Test262Error: value should not be coerced Expected SameValue(«32», «0») to be true

0 commit comments

Comments
 (0)