async-svelte-set-alternative
Rich Harris 6 months ago
parent 40f05ab9d3
commit 2c2bc766e9

@ -2,7 +2,8 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { source, set, state, increment } from '../internal/client/reactivity/sources.js'; import { source, set, state, increment } from '../internal/client/reactivity/sources.js';
import { label, tag } from '../internal/client/dev/tracing.js'; import { label, tag } from '../internal/client/dev/tracing.js';
import { get, update_version } from '../internal/client/runtime.js'; import { active_effect, get, untrack, update_version } from '../internal/client/runtime.js';
import { async_mode_flag } from '../internal/flags/index.js';
var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf']; var read_methods = ['forEach', 'isDisjointFrom', 'isSubsetOf', 'isSupersetOf'];
var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union']; var set_like_methods = ['difference', 'intersection', 'symmetricDifference', 'union'];
@ -47,8 +48,8 @@ var inited = false;
export class SvelteSet extends Set { export class SvelteSet extends Set {
/** @type {Map<T, Source<boolean>>} */ /** @type {Map<T, Source<boolean>>} */
#sources = new Map(); #sources = new Map();
#version = state(0); /** @type {Source<Set<T>>} */
#size = state(0); #items = state(new Set());
#update_version = update_version || -1; #update_version = update_version || -1;
/** /**
@ -57,19 +58,10 @@ export class SvelteSet extends Set {
constructor(value) { constructor(value) {
super(); super();
if (DEV) { this.#items = state(new Set(value))
// If the value is invalid then the native exception will fire here
value = new Set(value);
tag(this.#version, 'SvelteSet version');
tag(this.#size, 'SvelteSet.size');
}
if (value) { if (DEV) {
for (var element of value) { tag(this.#items, 'SvelteSet items');
super.add(element);
}
this.#size.v = super.size;
} }
if (!inited) this.#init(); if (!inited) this.#init();
@ -98,7 +90,7 @@ export class SvelteSet extends Set {
for (const method of read_methods) { for (const method of read_methods) {
// @ts-ignore // @ts-ignore
proto[method] = function (...v) { proto[method] = function (...v) {
get(this.#version); get(this.#items);
// @ts-ignore // @ts-ignore
return set_proto[method].apply(this, v); return set_proto[method].apply(this, v);
}; };
@ -107,7 +99,7 @@ export class SvelteSet extends Set {
for (const method of set_like_methods) { for (const method of set_like_methods) {
// @ts-ignore // @ts-ignore
proto[method] = function (...v) { proto[method] = function (...v) {
get(this.#version); get(this.#items);
// @ts-ignore // @ts-ignore
var set = /** @type {Set<T>} */ (set_proto[method].apply(this, v)); var set = /** @type {Set<T>} */ (set_proto[method].apply(this, v));
return new SvelteSet(set); return new SvelteSet(set);
@ -117,19 +109,18 @@ export class SvelteSet extends Set {
/** @param {T} value */ /** @param {T} value */
has(value) { has(value) {
var has = super.has(value);
var sources = this.#sources; var sources = this.#sources;
var s = sources.get(value); var s = sources.get(value);
if (s === undefined) { if (s === undefined) {
if (!has) { if (active_effect === null && (!async_mode_flag || !untrack(() => get(this.#items)).has(value))) {
// If the value doesn't exist, track the version in case it's added later // If the value doesn't exist, track the version in case it's added later
// but don't create sources willy-nilly to track all possible values // but don't create sources willy-nilly to track all possible values
get(this.#version); get(this.#items);
return false; return false;
} }
s = this.#source(true); s = this.#source((get(this.#items)).has(value));
if (DEV) { if (DEV) {
tag(s, `SvelteSet has(${label(value)})`); tag(s, `SvelteSet has(${label(value)})`);
@ -138,16 +129,22 @@ export class SvelteSet extends Set {
sources.set(value, s); sources.set(value, s);
} }
get(s); return get(s);
return has;
} }
/** @param {T} value */ /** @param {T} value */
add(value) { add(value) {
if (!super.has(value)) { if (!get(this.#items).has(value)) {
super.add(value); const clone = new Set(get(this.#items));
set(this.#size, super.size); clone.add(value);
increment(this.#version);
set(this.#items, clone);
}
var s = this.#sources.get(value);
if (s !== undefined) {
set(s, true);
} }
return this; return this;
@ -155,7 +152,7 @@ export class SvelteSet extends Set {
/** @param {T} value */ /** @param {T} value */
delete(value) { delete(value) {
var deleted = super.delete(value); var has = get(this.#items).has(value);
var sources = this.#sources; var sources = this.#sources;
var s = sources.get(value); var s = sources.get(value);
@ -164,20 +161,24 @@ export class SvelteSet extends Set {
set(s, false); set(s, false);
} }
if (deleted) { if (has) {
set(this.#size, super.size); const clone = new Set(get(this.#items));
increment(this.#version); clone.delete(value);
set(this.#items, clone);
} }
return deleted; return has;
} }
clear() { clear() {
if (super.size === 0) { if (get(this.#items).size === 0) {
return; return;
} }
// Clear first, so we get nice console.log outputs with $inspect // Clear first, so we get nice console.log outputs with $inspect
super.clear(); set(this.#items, new Set());
var sources = this.#sources; var sources = this.#sources;
for (var s of sources.values()) { for (var s of sources.values()) {
@ -185,8 +186,6 @@ export class SvelteSet extends Set {
} }
sources.clear(); sources.clear();
set(this.#size, 0);
increment(this.#version);
} }
keys() { keys() {
@ -194,20 +193,18 @@ export class SvelteSet extends Set {
} }
values() { values() {
get(this.#version); return get(this.#items).values();
return super.values();
} }
entries() { entries() {
get(this.#version); return get(this.#items).entries();
return super.entries();
} }
[Symbol.iterator]() { [Symbol.iterator]() {
return this.keys(); return this.values();
} }
get size() { get size() {
return get(this.#size); return get(this.#items).size;
} }
} }

Loading…
Cancel
Save