@msb235/blits 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +196 -0
- package/README.md +22 -4
- package/dist/book.js +4 -4
- package/dist/chain.d.ts +1 -1
- package/dist/chain.js +57 -54
- package/dist/channels.d.ts +26 -5
- package/dist/channels.js +12 -8
- package/dist/clock.d.ts +8 -1
- package/dist/clock.js +14 -3
- package/dist/clone.d.ts +3 -0
- package/dist/clone.js +16 -1
- package/dist/closed.d.ts +1 -1
- package/dist/closed.js +3 -2
- package/dist/color.d.ts +0 -11
- package/dist/color.js +4 -24
- package/dist/columns.js +0 -1
- package/dist/copyout.d.ts +6 -0
- package/dist/copyout.js +38 -0
- package/dist/crowd.d.ts +7 -5
- package/dist/crowd.js +32 -18
- package/dist/cue.d.ts +3 -1
- package/dist/cue.js +33 -20
- package/dist/departed.d.ts +34 -0
- package/dist/departed.js +73 -0
- package/dist/easing.d.ts +5 -0
- package/dist/easing.js +31 -2
- package/dist/everyone.d.ts +56 -0
- package/dist/everyone.js +221 -0
- package/dist/fade.d.ts +8 -1
- package/dist/fade.js +36 -6
- package/dist/fill.d.ts +22 -13
- package/dist/fill.js +104 -41
- package/dist/fit.js +2 -1
- package/dist/fold.d.ts +37 -0
- package/dist/fold.js +213 -28
- package/dist/gather.d.ts +15 -9
- package/dist/gather.js +60 -25
- package/dist/gone.d.ts +32 -0
- package/dist/gone.js +144 -0
- package/dist/handle.d.ts +16 -5
- package/dist/handle.js +56 -6
- package/dist/held.d.ts +8 -5
- package/dist/held.js +56 -58
- package/dist/history.d.ts +17 -13
- package/dist/history.js +49 -28
- package/dist/hosts.js +57 -9
- package/dist/index.d.ts +9 -4
- package/dist/index.js +5 -2
- package/dist/keyfill.d.ts +7 -0
- package/dist/keyfill.js +124 -0
- package/dist/keyrows.d.ts +1 -0
- package/dist/keyrows.js +1 -1
- package/dist/lane.d.ts +32 -2
- package/dist/lane.js +5 -0
- package/dist/lanes.d.ts +32 -8
- package/dist/lanes.js +69 -37
- package/dist/leavings.d.ts +26 -0
- package/dist/leavings.js +70 -0
- package/dist/meet.js +14 -8
- package/dist/mixer.d.ts +43 -7
- package/dist/mixer.js +60 -11
- package/dist/motion.d.ts +2 -0
- package/dist/motion.js +4 -1
- package/dist/motions.d.ts +22 -15
- package/dist/motions.js +40 -34
- package/dist/move.js +31 -20
- package/dist/moved.d.ts +11 -0
- package/dist/moved.js +29 -0
- package/dist/origin.d.ts +19 -0
- package/dist/origin.js +68 -0
- package/dist/owed.d.ts +4 -4
- package/dist/owed.js +8 -8
- package/dist/owner.d.ts +1 -1
- package/dist/owner.js +2 -2
- package/dist/pace.d.ts +13 -5
- package/dist/pace.js +21 -8
- package/dist/pack.d.ts +3 -1
- package/dist/pack.js +15 -24
- package/dist/paging.d.ts +8 -2
- package/dist/paging.js +44 -4
- package/dist/patch.d.ts +14 -9
- package/dist/patch.js +83 -21
- package/dist/place.js +188 -30
- package/dist/project.d.ts +12 -1
- package/dist/project.js +101 -83
- package/dist/pull.d.ts +2 -0
- package/dist/pull.js +8 -0
- package/dist/qualify.js +10 -2
- package/dist/reading.d.ts +5 -0
- package/dist/reading.js +5 -0
- package/dist/record.d.ts +9 -0
- package/dist/record.js +42 -0
- package/dist/relink.d.ts +11 -5
- package/dist/relink.js +7 -5
- package/dist/restored.d.ts +41 -0
- package/dist/restored.js +91 -0
- package/dist/revive.d.ts +10 -3
- package/dist/revive.js +31 -23
- package/dist/roster.d.ts +11 -0
- package/dist/roster.js +46 -0
- package/dist/rotation.d.ts +29 -0
- package/dist/rotation.js +91 -0
- package/dist/rows.d.ts +5 -5
- package/dist/rows.js +5 -5
- package/dist/sample.d.ts +3 -2
- package/dist/sample.js +32 -15
- package/dist/scored.d.ts +57 -0
- package/dist/scored.js +196 -0
- package/dist/seek.js +97 -114
- package/dist/shared.d.ts +6 -0
- package/dist/shared.js +15 -0
- package/dist/signals.d.ts +24 -3
- package/dist/signals.js +50 -11
- package/dist/spans.js +7 -0
- package/dist/stack.d.ts +11 -0
- package/dist/stack.js +47 -0
- package/dist/standing.d.ts +10 -0
- package/dist/standing.js +79 -0
- package/dist/store.d.ts +3 -3
- package/dist/store.js +3 -3
- package/dist/strays.js +3 -0
- package/dist/tape.d.ts +8 -5
- package/dist/tape.js +21 -13
- package/dist/testing.d.ts +35 -0
- package/dist/testing.js +116 -0
- package/dist/touch.d.ts +6 -0
- package/dist/touch.js +28 -0
- package/dist/transport.d.ts +53 -6
- package/dist/transport.js +102 -20
- package/dist/turns.d.ts +18 -0
- package/dist/turns.js +72 -0
- package/dist/tweened.js +1 -1
- package/dist/types/channel.d.ts +46 -0
- package/dist/types/channel.js +1 -0
- package/dist/types/history.d.ts +139 -0
- package/dist/types/history.js +1 -0
- package/dist/types/mix.d.ts +336 -0
- package/dist/types/mix.js +1 -0
- package/dist/types/patch.d.ts +187 -0
- package/dist/types/patch.js +1 -0
- package/dist/types/place.d.ts +157 -0
- package/dist/types/place.js +1 -0
- package/dist/types/transport.d.ts +71 -0
- package/dist/types/transport.js +1 -0
- package/dist/types/voice.d.ts +323 -0
- package/dist/types/voice.js +1 -0
- package/dist/types.d.ts +7 -1162
- package/dist/unpage.d.ts +2 -2
- package/dist/unpage.js +55 -25
- package/dist/voice.d.ts +92 -22
- package/dist/voice.js +108 -43
- package/dist/wave.d.ts +42 -0
- package/dist/wave.js +62 -0
- package/dist/weigh.js +1 -1
- package/docs/schema.html +42 -36
- package/package.json +8 -3
package/dist/lanes.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { copy } from './copyout.js';
|
|
1
2
|
import { row } from './crowd.js';
|
|
2
|
-
import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, signalled, subjectAt, } from './fill.js';
|
|
3
|
-
import { fold, foldDelta, foldInto, foldRun, gate, gather } from './gather.js';
|
|
3
|
+
import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, runEveryone, signalled, subjectAt, } from './fill.js';
|
|
4
|
+
import { fold, foldDelta, foldInto, foldRun, gate, gather, unplain } from './gather.js';
|
|
4
5
|
import { meet, reach } from './meet.js';
|
|
5
|
-
import { Numbers } from './numbers.js';
|
|
6
|
+
import { absent, Numbers } from './numbers.js';
|
|
6
7
|
import { Owed } from './owed.js';
|
|
7
8
|
import { requalify, retouch } from './qualify.js';
|
|
8
9
|
import { reading } from './reading.js';
|
|
@@ -19,7 +20,7 @@ export class Lanes {
|
|
|
19
20
|
/** The lanes over every subject that have started playing, by epoch. */
|
|
20
21
|
dense = [];
|
|
21
22
|
byId = new Map();
|
|
22
|
-
/** The crowds of single-subject
|
|
23
|
+
/** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
|
|
23
24
|
crowds = [];
|
|
24
25
|
crowdOf = new Map();
|
|
25
26
|
/** Whether two crowds share a channel, so their rows must interleave in voice order. */
|
|
@@ -29,13 +30,20 @@ export class Lanes {
|
|
|
29
30
|
/** The lane and record `one` is folding, whose band state a rest-less channel reads. */
|
|
30
31
|
folding = null;
|
|
31
32
|
rec = null;
|
|
33
|
+
/** The numbers a fill's methods hand each other: see `Arg`. */
|
|
34
|
+
arg = new Float64Array(6 /* Arg.SIZE */);
|
|
32
35
|
/** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
|
|
33
36
|
into = null;
|
|
34
37
|
intoId = 0;
|
|
35
38
|
lawsByKey = new Map();
|
|
36
39
|
lastLaw = null;
|
|
37
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* The lanes the last `meet` gave a position, the first `metN` of `met`, and whether it placed a
|
|
42
|
+
* crowd row. Counted, not cut to length: an array emptied by its length takes new room at its
|
|
43
|
+
* next push, about 150 B a subject met (the `swap` row, bench/allocs.mjs, 2026-10-09).
|
|
44
|
+
*/
|
|
38
45
|
met = [];
|
|
46
|
+
metN = 0;
|
|
39
47
|
metCrowd = false;
|
|
40
48
|
/** By subject number, the laned voices its probes fold on the general path this fill. */
|
|
41
49
|
owed = new Owed();
|
|
@@ -95,8 +103,9 @@ export class Lanes {
|
|
|
95
103
|
keeps = false;
|
|
96
104
|
now = Number.NaN;
|
|
97
105
|
filledAt = Number.NaN;
|
|
98
|
-
/** `reading.moved` at the last fill
|
|
106
|
+
/** `reading.moved` and `reading.inputs` at the last fill: see `current`. */
|
|
99
107
|
moved = 0;
|
|
108
|
+
inputs = 0;
|
|
100
109
|
/** The `now` of the latest probe, and the probe count before its first, to tell a probe this frame. */
|
|
101
110
|
frameAt = Number.NaN;
|
|
102
111
|
frameProbes = 0;
|
|
@@ -233,13 +242,23 @@ export class Lanes {
|
|
|
233
242
|
}
|
|
234
243
|
/** Whether this frame's lanes are filled and nothing since asks `begin` to look again. */
|
|
235
244
|
filled(now, version) {
|
|
245
|
+
return (this.frameAt === now &&
|
|
246
|
+
this.qualifiedVersion === version &&
|
|
247
|
+
this.touched.length === 0 &&
|
|
248
|
+
!this.filling &&
|
|
249
|
+
this.current(now, version));
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Whether the last fill still stands: everything a fill reads that can change between two probes,
|
|
253
|
+
* each stamped by `fillAll`. The clock; the mix's version, which voices coming, going, starting
|
|
254
|
+
* and stopping move; a motion's retargets and pushes; and a `level` set. Whatever else can change
|
|
255
|
+
* between probes keeps its voice off lanes in `fits`.
|
|
256
|
+
*/
|
|
257
|
+
current(now, version) {
|
|
236
258
|
return (this.filledAt === now &&
|
|
237
|
-
this.frameAt === now &&
|
|
238
259
|
this.filledVersion === version &&
|
|
239
|
-
this.qualifiedVersion === version &&
|
|
240
260
|
this.moved === reading.moved &&
|
|
241
|
-
this.
|
|
242
|
-
!this.filling);
|
|
261
|
+
this.inputs === reading.inputs);
|
|
243
262
|
}
|
|
244
263
|
/**
|
|
245
264
|
* What a probe does before its subject, once a frame's lanes are settled: qualifies and fills as
|
|
@@ -257,8 +276,9 @@ export class Lanes {
|
|
|
257
276
|
}
|
|
258
277
|
if (this.filling)
|
|
259
278
|
return 0 /* Begin.GENERAL */;
|
|
260
|
-
//
|
|
261
|
-
// waiting, each of which touches it,
|
|
279
|
+
// Past a qualify that stands, the mix's version moves when a voice over every subject comes,
|
|
280
|
+
// goes, starts or stops waiting, each of which touches it, or stops sharing one record, which
|
|
281
|
+
// moves no voice on or off a lane: so with voices touched it is a set of touches.
|
|
262
282
|
if (this.qualifiedVersion !== version) {
|
|
263
283
|
if (!Number.isNaN(this.qualifiedVersion) && this.touched.length > 0 && retouch(this))
|
|
264
284
|
this.qualifiedVersion = version;
|
|
@@ -269,7 +289,7 @@ export class Lanes {
|
|
|
269
289
|
requalify(this, version);
|
|
270
290
|
if (this.laned.length === 0)
|
|
271
291
|
return 0 /* Begin.GENERAL */;
|
|
272
|
-
if (this.
|
|
292
|
+
if (!this.current(now, version)) {
|
|
273
293
|
fillAll(this, now, version);
|
|
274
294
|
// A patch call in that fill made kept state, which took its voice off its lane: fill without it.
|
|
275
295
|
if (this.qualifiedVersion !== version) {
|
|
@@ -349,30 +369,6 @@ export class Lanes {
|
|
|
349
369
|
}
|
|
350
370
|
return true;
|
|
351
371
|
}
|
|
352
|
-
/** Writes a subject's laned values into a pose, each array channel into a new array. */
|
|
353
|
-
copy(slot, pose) {
|
|
354
|
-
const laned = this.laned;
|
|
355
|
-
for (let c = 0; c < laned.length; c++) {
|
|
356
|
-
const ch = laned[c];
|
|
357
|
-
const axes = ch.axes;
|
|
358
|
-
// Never `delete`: it drops a reused out object into dictionary mode for good.
|
|
359
|
-
if (ch.op === 'last' && Number.isNaN(ch.values[slot * axes])) {
|
|
360
|
-
if (pose[ch.name] !== undefined)
|
|
361
|
-
pose[ch.name] = undefined;
|
|
362
|
-
continue;
|
|
363
|
-
}
|
|
364
|
-
if (ch.scalar) {
|
|
365
|
-
pose[ch.name] = ch.values[slot];
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
// Made as the general path makes it, a copy of rest, so poses from either path share a shape.
|
|
369
|
-
const arr = [...ch.start];
|
|
370
|
-
const base = slot * axes;
|
|
371
|
-
for (let a = 0; a < axes; a++)
|
|
372
|
-
arr[a] = ch.values[base + a];
|
|
373
|
-
pose[ch.name] = arr;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
372
|
forget(slot) {
|
|
377
373
|
this.host.forgot(slot);
|
|
378
374
|
this.live--;
|
|
@@ -417,6 +413,39 @@ export class Lanes {
|
|
|
417
413
|
if (q >= 0)
|
|
418
414
|
lane.fix(q);
|
|
419
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* A voice that kept one record for every subject keeps one each from now on: each of its lane's
|
|
418
|
+
* positions takes the record `of` gives its subject.
|
|
419
|
+
*/
|
|
420
|
+
rerecord(id, of) {
|
|
421
|
+
const lane = this.byId.get(id);
|
|
422
|
+
if (lane === undefined)
|
|
423
|
+
return;
|
|
424
|
+
for (let p = 0; p < lane.list.length; p++) {
|
|
425
|
+
const slot = lane.list[p];
|
|
426
|
+
const subject = this.subjectAt(slot);
|
|
427
|
+
if (subject !== absent)
|
|
428
|
+
lane.records[p] = of(subject, slot);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/** A voice's clock moved the `shown` of records it had already placed: copies them again. */
|
|
432
|
+
reshown(id) {
|
|
433
|
+
const c = this.crowdOf.get(id);
|
|
434
|
+
const p = c?.rowOf.get(id);
|
|
435
|
+
if (c !== undefined && p !== undefined) {
|
|
436
|
+
const held = c.records[p];
|
|
437
|
+
if (held !== undefined)
|
|
438
|
+
c.data[p * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
|
|
439
|
+
}
|
|
440
|
+
const lane = this.byId.get(id);
|
|
441
|
+
if (lane === undefined)
|
|
442
|
+
return;
|
|
443
|
+
for (let q = 0; q < lane.list.length; q++) {
|
|
444
|
+
const held = lane.records[q];
|
|
445
|
+
if (held !== undefined)
|
|
446
|
+
lane.data[q * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
420
449
|
/** Something on a voice changed: a crowd copies it again at the next fill. */
|
|
421
450
|
voiceChanged(id) {
|
|
422
451
|
const c = this.crowdOf.get(id);
|
|
@@ -430,12 +459,14 @@ export class Lanes {
|
|
|
430
459
|
// A fill's per-subject path is methods, installed here from the modules that own them: as
|
|
431
460
|
// functions called directly they made fills 5-8% slower (bench/ab.sh on teitou, 2026-10-05).
|
|
432
461
|
const methods = {
|
|
462
|
+
copy,
|
|
433
463
|
row,
|
|
434
464
|
signalled,
|
|
435
465
|
parting,
|
|
436
466
|
subjectAt,
|
|
437
467
|
reset,
|
|
438
468
|
run,
|
|
469
|
+
runEveryone,
|
|
439
470
|
one,
|
|
440
471
|
foldKeys,
|
|
441
472
|
readKeyed,
|
|
@@ -446,6 +477,7 @@ const methods = {
|
|
|
446
477
|
foldRun,
|
|
447
478
|
foldInto,
|
|
448
479
|
gate,
|
|
480
|
+
unplain,
|
|
449
481
|
};
|
|
450
482
|
for (const [name, value] of Object.entries(methods))
|
|
451
483
|
Object.defineProperty(Lanes.prototype, name, { value, writable: true, configurable: true });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Cut } from './transport.js';
|
|
2
|
+
import type { Left, Subject } from './voice.js';
|
|
3
|
+
/**
|
|
4
|
+
* Under history, the records subjects left a voice with, while a seek or a read back may reach
|
|
5
|
+
* them: in the order they left, the oldest let go of from the front, and each subject's found
|
|
6
|
+
* without looking through the others'.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Leavings<I> {
|
|
9
|
+
private list;
|
|
10
|
+
/** How many at the front of `list` have been let go of, cleared out once they are half of it. */
|
|
11
|
+
private head;
|
|
12
|
+
private readonly by;
|
|
13
|
+
static from<I>(entries: readonly Left<I>[]): Leavings<I> | null;
|
|
14
|
+
push(e: Left<I>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Lets go of every entry that left before `reach`, handing each to `out` first. They are at the
|
|
17
|
+
* front: entries are in the order they left, and mix time does not run back along it.
|
|
18
|
+
*/
|
|
19
|
+
expire(reach: number, out: ((e: Left<I>) => void) | null): void;
|
|
20
|
+
/** The record `subject` had at `cut` and left with after it, if it left after `cut`. */
|
|
21
|
+
at(subject: I, cut: Cut): Subject<unknown> | undefined;
|
|
22
|
+
/** Each time `subject` left, oldest first. */
|
|
23
|
+
of(subject: I): readonly Left<I>[];
|
|
24
|
+
/** Every entry, oldest first. */
|
|
25
|
+
all(): readonly Left<I>[];
|
|
26
|
+
}
|
package/dist/leavings.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Store } from './store.js';
|
|
2
|
+
import { within } from './transport.js';
|
|
3
|
+
/**
|
|
4
|
+
* Under history, the records subjects left a voice with, while a seek or a read back may reach
|
|
5
|
+
* them: in the order they left, the oldest let go of from the front, and each subject's found
|
|
6
|
+
* without looking through the others'.
|
|
7
|
+
*/
|
|
8
|
+
export class Leavings {
|
|
9
|
+
list = [];
|
|
10
|
+
/** How many at the front of `list` have been let go of, cleared out once they are half of it. */
|
|
11
|
+
head = 0;
|
|
12
|
+
by = new Store();
|
|
13
|
+
static from(entries) {
|
|
14
|
+
if (entries.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
const out = new Leavings();
|
|
17
|
+
for (const e of entries)
|
|
18
|
+
out.push(e);
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
push(e) {
|
|
22
|
+
this.list.push(e);
|
|
23
|
+
const own = this.by.get(e.subject);
|
|
24
|
+
if (own === undefined)
|
|
25
|
+
this.by.set(e.subject, [e]);
|
|
26
|
+
else
|
|
27
|
+
own.push(e);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Lets go of every entry that left before `reach`, handing each to `out` first. They are at the
|
|
31
|
+
* front: entries are in the order they left, and mix time does not run back along it.
|
|
32
|
+
*/
|
|
33
|
+
expire(reach, out) {
|
|
34
|
+
const list = this.list;
|
|
35
|
+
let head = this.head;
|
|
36
|
+
while (head < list.length && !(list[head].at >= reach)) {
|
|
37
|
+
const e = list[head++];
|
|
38
|
+
if (out !== null)
|
|
39
|
+
out(e);
|
|
40
|
+
const own = this.by.get(e.subject);
|
|
41
|
+
if (own.length === 1)
|
|
42
|
+
this.by.delete(e.subject);
|
|
43
|
+
else
|
|
44
|
+
own.shift();
|
|
45
|
+
}
|
|
46
|
+
this.head = head;
|
|
47
|
+
if (head >= 32 && head * 2 >= list.length) {
|
|
48
|
+
this.list = list.slice(head);
|
|
49
|
+
this.head = 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** The record `subject` had at `cut` and left with after it, if it left after `cut`. */
|
|
53
|
+
at(subject, cut) {
|
|
54
|
+
const own = this.by.get(subject);
|
|
55
|
+
if (own === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
for (const e of own)
|
|
58
|
+
if (!within(cut, e.seq, e.sync))
|
|
59
|
+
return e.held;
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
/** Each time `subject` left, oldest first. */
|
|
63
|
+
of(subject) {
|
|
64
|
+
return this.by.get(subject) ?? [];
|
|
65
|
+
}
|
|
66
|
+
/** Every entry, oldest first. */
|
|
67
|
+
all() {
|
|
68
|
+
return this.head === 0 ? this.list : this.list.slice(this.head);
|
|
69
|
+
}
|
|
70
|
+
}
|
package/dist/meet.js
CHANGED
|
@@ -8,21 +8,27 @@ export function owable(lanes, slot) {
|
|
|
8
8
|
if (lanes.metCrowd || lanes.owes(slot))
|
|
9
9
|
return false;
|
|
10
10
|
// Subjects meeting the same lanes in one fill get the same answer, and a list is kept only once true.
|
|
11
|
-
if (lanes.owed.last(lanes.met))
|
|
12
|
-
return true;
|
|
13
11
|
const met = lanes.met;
|
|
12
|
+
const n = lanes.metN;
|
|
13
|
+
if (lanes.owed.last(met, n))
|
|
14
|
+
return true;
|
|
14
15
|
let other = Number.NEGATIVE_INFINITY;
|
|
15
16
|
for (const lane of lanes.lanes) {
|
|
16
17
|
const id = lane.voice.id;
|
|
17
|
-
if (id
|
|
18
|
+
if (id <= other)
|
|
19
|
+
continue;
|
|
20
|
+
const at = met.indexOf(id);
|
|
21
|
+
if (at < 0 || at >= n)
|
|
18
22
|
other = id;
|
|
19
23
|
}
|
|
20
24
|
for (const c of lanes.crowds)
|
|
21
25
|
if (c.size > 0)
|
|
22
26
|
other = Math.max(other, c.hot[(c.size - 1) * c.stride + 7 /* Hot.ID */]);
|
|
23
|
-
for (
|
|
27
|
+
for (let i = 0; i < n; i++) {
|
|
28
|
+
const id = met[i];
|
|
24
29
|
if (id <= other || lanes.byId.get(id).group !== null)
|
|
25
30
|
return false;
|
|
31
|
+
}
|
|
26
32
|
return true;
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
@@ -35,7 +41,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
35
41
|
const from = seen < 0 ? -1 - seen : seen;
|
|
36
42
|
lanes.per[slot * 6 /* Per.SLOT */ + 1 /* Per.SEEN */] = lanes.epochs;
|
|
37
43
|
let met = false;
|
|
38
|
-
lanes.
|
|
44
|
+
lanes.metN = 0;
|
|
39
45
|
lanes.metCrowd = false;
|
|
40
46
|
const dense = lanes.dense;
|
|
41
47
|
for (let i = dense.length - 1; i >= 0; i--) {
|
|
@@ -50,7 +56,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
50
56
|
lane.add(slot, held);
|
|
51
57
|
if (lane.idle)
|
|
52
58
|
reach(lanes, slot, 1);
|
|
53
|
-
lanes.met.
|
|
59
|
+
lanes.met[lanes.metN++] = lane.voice.id;
|
|
54
60
|
met = true;
|
|
55
61
|
}
|
|
56
62
|
// `open` marks every subject a voice naming it starts on, so an unmarked one has none to meet.
|
|
@@ -73,7 +79,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
73
79
|
lane.add(slot, held);
|
|
74
80
|
if (lane.idle)
|
|
75
81
|
reach(lanes, slot, 1);
|
|
76
|
-
lanes.met.
|
|
82
|
+
lanes.met[lanes.metN++] = voice.id;
|
|
77
83
|
met = true;
|
|
78
84
|
}
|
|
79
85
|
if (!met)
|
|
@@ -83,7 +89,7 @@ export function meet(lanes, slot, subject, head, lane) {
|
|
|
83
89
|
// otherwise it reads the general path all frame.
|
|
84
90
|
const o = slot * 6 /* Per.SLOT */;
|
|
85
91
|
if (lane && lanes.per[o + 2 /* Per.IDLE */] === 0 && owable(lanes, slot)) {
|
|
86
|
-
lanes.owed.owe(slot, lanes.met);
|
|
92
|
+
lanes.owed.owe(slot, lanes.met, lanes.metN);
|
|
87
93
|
return true;
|
|
88
94
|
}
|
|
89
95
|
lanes.per[o + 0 /* Per.FILLED */] = lanes.fills;
|
package/dist/mixer.d.ts
CHANGED
|
@@ -2,9 +2,11 @@ import { blended, laneRead, shareKept } from './blend.js';
|
|
|
2
2
|
import type { Book } from './book.js';
|
|
3
3
|
import { aims, chain, linkable, relink } from './chain.js';
|
|
4
4
|
import { type LerpInto } from './channels.js';
|
|
5
|
+
import { DepartedIndex } from './departed.js';
|
|
5
6
|
import type { Due } from './due.js';
|
|
6
7
|
import { parting } from './fade.js';
|
|
7
|
-
import { apply, baseFor, clamp, contribution, fold, folded, foldLoci, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, slopeFor, tick } from './fold.js';
|
|
8
|
+
import { apply, baseFor, clamp, contribution, fold, foldDetour, folded, foldLoci, foldSharers, foldWith, isRest, type Key, keyed, linked, owedBy, passes, read, shared, slopeFor, tick } from './fold.js';
|
|
9
|
+
import { GoneIndex } from './gone.js';
|
|
8
10
|
import type { HandleHost } from './handle.js';
|
|
9
11
|
import { held, shownOf, sinceOf, unreachedOf } from './held.js';
|
|
10
12
|
import { Lanes } from './lanes.js';
|
|
@@ -15,30 +17,46 @@ import { Keys } from './paging.js';
|
|
|
15
17
|
import { keep } from './pull.js';
|
|
16
18
|
import { Steps } from './relink.js';
|
|
17
19
|
import { Outs } from './revive.js';
|
|
20
|
+
import { ScoreIndex } from './scored.js';
|
|
18
21
|
import { Fitting } from './spans.js';
|
|
19
22
|
import { Store } from './store.js';
|
|
20
23
|
import { type Announced, Transport } from './transport.js';
|
|
21
24
|
import type { Booker, BookOptions, Channel, Columns, Engine, Handle, Kit, Marked, Mix, MixOptions, OwnerSpec, Patch, Projection, Sent, Signal, SpanHandle, SpanSpec, Tape, VoiceSpec } from './types.js';
|
|
22
25
|
import { type Subject, type Voice } from './voice.js';
|
|
23
26
|
import { base, capped, fadeOf, horizonFor, ownedBy, ownerBase, prime, weigh, weighOwned } from './weigh.js';
|
|
27
|
+
/**
|
|
28
|
+
* What a mix takes where its options say nothing. Not exported from the package: the suite turns
|
|
29
|
+
* `lanes` off to run every test on the general path, which is what makes each one an equivalence check.
|
|
30
|
+
*/
|
|
31
|
+
export declare const defaults: {
|
|
32
|
+
lanes: boolean;
|
|
33
|
+
};
|
|
24
34
|
export declare class Mixer<I, O> implements Mix<I, O> {
|
|
25
35
|
readonly kit: Kit<O>;
|
|
26
36
|
readonly opts: MixOptions;
|
|
27
37
|
cued: Voice<I, O>[];
|
|
28
38
|
/** Under `history`, voices that have left but that a read back may still reach. */
|
|
29
39
|
gone: Voice<I, O>[];
|
|
40
|
+
goneIx: GoneIndex<I, O>;
|
|
41
|
+
scored: ScoreIndex<I, O>;
|
|
30
42
|
/** Set on a projection's own mixer: it sends nothing, keeps no history, and reads without committing. */
|
|
31
43
|
projecting: boolean;
|
|
32
44
|
/** Set on a projection reading back: a subject it has nothing on starts from its voice's start. */
|
|
33
45
|
backward: boolean;
|
|
34
46
|
/** True during a sync, so a control change it makes is recorded as showing in that frame. */
|
|
35
47
|
moving: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a probe or pull has read the mix since its clock last moved. A control change made
|
|
50
|
+
* before that shows in this frame live, so it is recorded as showing in it.
|
|
51
|
+
*/
|
|
52
|
+
looked: boolean;
|
|
36
53
|
/**
|
|
37
54
|
* Under `history` with `inputs`, the host fields patches read, copied each frame they changed. In
|
|
38
55
|
* a projection reading back, the copy in force then.
|
|
39
56
|
*/
|
|
40
57
|
hostLog: {
|
|
41
58
|
at: number;
|
|
59
|
+
seq: number;
|
|
42
60
|
fields: Record<string, unknown>;
|
|
43
61
|
}[];
|
|
44
62
|
hostThen: {
|
|
@@ -58,20 +76,23 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
58
76
|
/** Taken off its transport, so it takes no more calls until a seek puts it back. */
|
|
59
77
|
dropped: boolean;
|
|
60
78
|
readonly name: string | undefined;
|
|
61
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* This mix's frame among every mix's: moved by a sync or seek, and by a control change, drop,
|
|
81
|
+
* or touch within one.
|
|
82
|
+
*/
|
|
62
83
|
frame: number;
|
|
63
84
|
/** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
|
|
64
85
|
pins: Map<Voice<I, O>, number> | null;
|
|
65
86
|
wantsPose: boolean;
|
|
66
87
|
/** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
|
|
67
88
|
scratch: O | undefined;
|
|
68
|
-
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
69
89
|
/** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
|
|
70
90
|
due: Due<I, O>[];
|
|
71
91
|
/** Voices retired since `moveTo` last pruned them, in the order they retired. */
|
|
72
92
|
retired: Voice<I, O>[];
|
|
73
93
|
/** Visit every voice each sync, as before the due queue; for tests that compare the two. */
|
|
74
94
|
walkAll: boolean;
|
|
95
|
+
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
75
96
|
pulled: I[];
|
|
76
97
|
pulledHeads: (Subject<unknown> | undefined)[];
|
|
77
98
|
/** Each remembered head's lane slot, and the `version` and `relinks` they were all current at. */
|
|
@@ -93,16 +114,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
93
114
|
onWake(fn: () => void): () => void;
|
|
94
115
|
/**
|
|
95
116
|
* Per subject, the first record of the chain through every live voice that reaches it, or a stub
|
|
96
|
-
* where none does. Relinked when `version` moves,
|
|
97
|
-
*
|
|
117
|
+
* where none does. Relinked when `version` moves, or when a voice naming the subject marks its
|
|
118
|
+
* head stale: see `changed` in `chain.ts`.
|
|
98
119
|
*/
|
|
99
120
|
chains: Store<I, Subject<unknown>>;
|
|
100
121
|
version: number;
|
|
101
|
-
readonly steps: Steps<Voice<I, O
|
|
122
|
+
readonly steps: Steps<Voice<I, O>, I>;
|
|
102
123
|
/** Per subject, the voices whose `subjects` name it, in voice order. */
|
|
103
124
|
named: Store<I, Voice<I, O>[]>;
|
|
104
125
|
/** Voices a subject has been faded out of, which `drop` looks in besides those that reach it. */
|
|
105
126
|
readonly parters: Set<Voice<I, O>>;
|
|
127
|
+
/** What an anchor can still find of voices that left without history, or past its reach. */
|
|
128
|
+
readonly departed: DepartedIndex;
|
|
106
129
|
/**
|
|
107
130
|
* Motion patches that may hold state for a subject no voice still reaching it plays, which `drop`
|
|
108
131
|
* frees besides those voices' own: per subject, a patch a voice naming it left while another
|
|
@@ -116,6 +139,15 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
116
139
|
naming: number;
|
|
117
140
|
/** The voices in the list that name no subjects, in voice order. */
|
|
118
141
|
general: Voice<I, O>[];
|
|
142
|
+
/** Those of `general` that keep one record for every subject, in voice order: see `everyone.ts`. */
|
|
143
|
+
sharers: Voice<I, O>[];
|
|
144
|
+
/**
|
|
145
|
+
* Whether a voice stopped sharing this frame: a probe or pull under way then holds chains linked
|
|
146
|
+
* before it joined them, and takes each again.
|
|
147
|
+
*/
|
|
148
|
+
unshared: boolean;
|
|
149
|
+
/** 0 where a fold is a walk of the chain: see `detour` in `everyone.ts`. */
|
|
150
|
+
detours: number;
|
|
119
151
|
/** How many voices in the list carry a locus; with none, a fold allocates nothing. */
|
|
120
152
|
loci: number;
|
|
121
153
|
/** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
|
|
@@ -212,6 +244,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
212
244
|
over?: number;
|
|
213
245
|
}): void;
|
|
214
246
|
drop(subject: I): void;
|
|
247
|
+
touch(subject?: I): void;
|
|
215
248
|
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
216
249
|
/** Voices whose stop 0 is mid-computation, so a fold for one cannot re-enter itself. */
|
|
217
250
|
readonly folding: Set<number>;
|
|
@@ -221,7 +254,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
221
254
|
* is first asked, when probes start writing it.
|
|
222
255
|
*/
|
|
223
256
|
restStamps: Store<I, number> | null;
|
|
224
|
-
/** What a probe's record of rest is good for: moved by a new frame, version or
|
|
257
|
+
/** What a probe's record of rest is good for: moved by a new frame, version, relink, or stir. */
|
|
225
258
|
private restsEpoch;
|
|
226
259
|
private restsFrame;
|
|
227
260
|
private restsVersion;
|
|
@@ -239,6 +272,9 @@ declare const methods: {
|
|
|
239
272
|
foldWith: typeof foldWith;
|
|
240
273
|
owedBy: typeof owedBy;
|
|
241
274
|
foldLoci: typeof foldLoci;
|
|
275
|
+
foldDetour: typeof foldDetour;
|
|
276
|
+
foldSharers: typeof foldSharers;
|
|
277
|
+
shared: typeof shared;
|
|
242
278
|
read: typeof read;
|
|
243
279
|
contribution: typeof contribution;
|
|
244
280
|
keyed: typeof keyed;
|