tuple->object

async-another-try
Simon Holthausen 5 days ago
parent bd0faecdaa
commit 408d51b362
No known key found for this signature in database

@ -155,17 +155,16 @@ export class Batch {
/** /**
* The current values of any signals that are updated in this batch. * The current values of any signals that are updated in this batch.
* Tuple format: [value, is_derived, write_version] (note: is_derived is false for deriveds, too, if they were overridden via assignment) * `is_derived` is false for deriveds, too, if they were overridden via assignment.
* They keys of this map are identical to `this.previous` * They keys of this map are identical to `this.previous`
* @type {Map<Value, [any, boolean, number]>} * @type {Map<Value, { v: any, wv: number, is_derived: boolean }>}
*/ */
current = new Map(); current = new Map();
/** /**
* The values and write versions of any signals (sources and deriveds) that are updated in this batch _before_ those updates took place. * The values and write versions of any signals (sources and deriveds) that are updated in this batch _before_ those updates took place.
* Tuple format: [value, write_version]
* They keys of this map are identical to `this.current` * They keys of this map are identical to `this.current`
* @type {Map<Value, [any, number]>} * @type {Map<Value, { v: any, wv: number }>}
*/ */
previous = new Map(); previous = new Map();
@ -679,7 +678,10 @@ export class Batch {
#merge(batch) { #merge(batch) {
for (const [source, value] of batch.current) { for (const [source, value] of batch.current) {
if (!this.previous.has(source) && batch.previous.has(source)) { if (!this.previous.has(source) && batch.previous.has(source)) {
this.previous.set(source, /** @type {[any, number]} */ (batch.previous.get(source))); this.previous.set(
source,
/** @type {{ v: any, wv: number }} */ (batch.previous.get(source))
);
} }
this.current.set(source, value); this.current.set(source, value);
@ -759,14 +761,14 @@ export class Batch {
*/ */
capture(source, value, is_derived = false) { capture(source, value, is_derived = false) {
if (source.v !== UNINITIALIZED && !this.previous.has(source)) { if (source.v !== UNINITIALIZED && !this.previous.has(source)) {
this.previous.set(source, [source.v, source.wv]); this.previous.set(source, { v: source.v, wv: source.wv });
} }
const wv = increment_write_version(); const wv = increment_write_version();
// Don't save errors in `batch_values`, or they won't be thrown in `runtime.js#get` // Don't save errors in `batch_values`, or they won't be thrown in `runtime.js#get`
if ((source.f & ERROR_VALUE) === 0) { if ((source.f & ERROR_VALUE) === 0) {
this.current.set(source, [value, is_derived, wv]); this.current.set(source, { v: value, wv, is_derived });
batch_values?.set(source, value); batch_values?.set(source, value);
wv_values?.set(source, wv); wv_values?.set(source, wv);
} }
@ -798,8 +800,7 @@ export class Batch {
/** @type {Derived} */ (source).deps?.some( /** @type {Derived} */ (source).deps?.some(
(d) => (d) =>
/** @type {Batch} */ (batch).current.has(d) || /** @type {Batch} */ (batch).current.has(d) ||
(this.current.has(d) && (this.current.has(d) && /** @type {{ v: any }} */ (this.current.get(d)).v !== d.v)
/** @type {[any, boolean, number]} */ (this.current.get(d))[0] !== d.v)
)) ))
) { ) {
is_latest_value = false; is_latest_value = false;
@ -834,17 +835,17 @@ export class Batch {
const current = batch.current.get(source); const current = batch.current.get(source);
batch.current.delete(source); batch.current.delete(source);
if (![...batch.current.values()].some((v) => !v[1])) { if (![...batch.current.values()].some((value) => !value.is_derived)) {
// The real world has overtaken every write of this fork, so it is obsolete. Discard it // The real world has overtaken every write of this fork, so it is obsolete. Discard it
// right away (its speculative branches must not be adopted by anyone), and empty // right away (its speculative branches must not be adopted by anyone), and empty
// `current` so that `commit()` can tell this apart from a user-initiated discard // `current` so that `commit()` can tell this apart from a user-initiated discard
batch.current.clear(); batch.current.clear();
batch.discard(); batch.discard();
} else { } else {
if (current && current[0] !== value) batch.current.set(source, current); if (current && current.v !== value) batch.current.set(source, current);
if ( if (
!is_derived && !is_derived &&
(!current || current[0] !== value) && (!current || current.v !== value) &&
((source.f & ASYNC) === 0 || ((source.f & ASYNC) === 0 ||
!depends_on( !depends_on(
/** @type {Effect} */ (/** @type {Source} */ (source).e), /** @type {Effect} */ (/** @type {Source} */ (source).e),
@ -1044,9 +1045,9 @@ export class Batch {
held_sources = new Map(); held_sources = new Map();
stale_sources = new Map(); stale_sources = new Map();
for (const [source, [value, _, wv]] of this.current) { for (const [source, current] of this.current) {
batch_values.set(source, value); batch_values.set(source, current.v);
wv_values.set(source, wv); wv_values.set(source, current.wv);
} }
for (let batch = first_batch; batch !== null; batch = batch.next) { for (let batch = first_batch; batch !== null; batch = batch.next) {
@ -1067,10 +1068,10 @@ export class Batch {
} }
if (batch.id > this.id || include_earlier || this.is_eager) { if (batch.id > this.id || include_earlier || this.is_eager) {
for (const [source, [value, wv]] of batch.previous) { for (const [source, previous] of batch.previous) {
if (!batch_values.has(source)) { if (!batch_values.has(source)) {
batch_values.set(source, value); batch_values.set(source, previous.v);
wv_values.set(source, wv); wv_values.set(source, previous.wv);
} }
} }
} }
@ -1548,21 +1549,21 @@ export function fork(fn) {
// in `batch.current` at this point is the latest value: sources that the real world has // in `batch.current` at this point is the latest value: sources that the real world has
// written to in the meantime were removed from the fork via `notify_fork` (an async // written to in the meantime were removed from the fork via `notify_fork` (an async
// source only survives if its effect depends on inputs that only the fork changed). // source only survives if its effect depends on inputs that only the fork changed).
// We use fresh versions rather than the fork-time `content[2]`, because the real world // We use fresh versions rather than the fork-time `content.wv`, because the real world
// may have run reactions since then whose versions would otherwise outrank them. // may have run reactions since then whose versions would otherwise outrank them.
for (var [source, content] of batch.current) { for (var [source, content] of batch.current) {
var changed = source.v !== content[0]; var changed = source.v !== content.v;
source.v = content[0]; source.v = content.v;
if (!content[1]) { if (!content.is_derived) {
content[2] = source.wv = increment_write_version(); content.wv = source.wv = increment_write_version();
// dirty those effects the fork did not see yet, e.g. because a later batch created new branches // dirty those effects the fork did not see yet, e.g. because a later batch created new branches
batch.mark(source, MAYBE_DIRTY, true); batch.mark(source, MAYBE_DIRTY, true);
} else if (changed) { } else if (changed) {
// A derived that was evaluated inside the fork: bump its version too, so that reactions // A derived that was evaluated inside the fork: bump its version too, so that reactions
// which read the (then still old) real value _after_ the fork evaluated it — and which are // which read the (then still old) real value _after_ the fork evaluated it — and which are
// therefore not in `stale_effects` — see a newer dependency version and re-run. // therefore not in `stale_effects` — see a newer dependency version and re-run.
content[2] = source.wv = increment_write_version(); content.wv = source.wv = increment_write_version();
} }
} }
@ -1600,10 +1601,10 @@ export function fork(fn) {
// Other forks might need to rerun now with the updated state. // Other forks might need to rerun now with the updated state.
let next_batch = batch.next; let next_batch = batch.next;
while (next_batch) { while (next_batch) {
for (const [source, [value, is_derived]] of batch.current) { for (const [source, current] of batch.current) {
if (next_batch.current.has(source)) { if (next_batch.current.has(source)) {
batch.notify_fork(next_batch, source, is_derived, value); batch.notify_fork(next_batch, source, current.is_derived, current.v);
} else if (!is_derived) { } else if (!current.is_derived) {
next_batch.queue_revalidation(source); next_batch.queue_revalidation(source);
} }
} }

Loading…
Cancel
Save