@msb235/blits 0.7.1 → 0.8.1
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 +193 -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 +8 -0
- package/dist/clone.js +22 -0
- 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 +31 -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 +34 -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 +216 -31
- package/dist/frames.d.ts +21 -0
- package/dist/frames.js +59 -0
- package/dist/gather.d.ts +15 -9
- package/dist/gather.js +60 -25
- package/dist/gone.js +10 -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 +47 -28
- package/dist/hosts.js +55 -8
- 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/locus.js +2 -2
- package/dist/meet.js +14 -8
- package/dist/mixer.d.ts +39 -7
- package/dist/mixer.js +50 -10
- 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 +23 -16
- 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 +39 -4
- package/dist/patch.d.ts +14 -9
- package/dist/patch.js +83 -21
- package/dist/place.js +18 -3
- 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/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 +45 -6
- package/dist/transport.js +64 -19
- 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 +53 -25
- package/dist/voice.d.ts +90 -22
- package/dist/voice.js +105 -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.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Column } from './columns.js';
|
|
2
|
+
import { copy } from './copyout.js';
|
|
2
3
|
import { type Crowd, row } from './crowd.js';
|
|
3
|
-
import { call, foldKeys, one, parting, readKeyed, reset, run, signalled, subjectAt } from './fill.js';
|
|
4
|
-
import { fold, foldDelta, foldInto, foldRun, gate, gather } from './gather.js';
|
|
4
|
+
import { call, foldKeys, one, parting, readKeyed, reset, run, runEveryone, signalled, subjectAt } from './fill.js';
|
|
5
|
+
import { fold, foldDelta, foldInto, foldRun, gate, gather, unplain } from './gather.js';
|
|
5
6
|
import { type Lane, type Laned, type Locus } from './lane.js';
|
|
6
7
|
import type { Watcher } from './motions.js';
|
|
7
|
-
import {
|
|
8
|
+
import { absent, Numbers } from './numbers.js';
|
|
8
9
|
import { Owed } from './owed.js';
|
|
9
10
|
import type { Channel } from './types.js';
|
|
10
11
|
import type { Subject, Voice } from './voice.js';
|
|
@@ -61,7 +62,7 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
61
62
|
/** The lanes over every subject that have started playing, by epoch. */
|
|
62
63
|
dense: Lane<I, O>[];
|
|
63
64
|
readonly byId: Map<number, Lane<I, O>>;
|
|
64
|
-
/** The crowds of single-subject
|
|
65
|
+
/** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
|
|
65
66
|
crowds: Crowd<I, O>[];
|
|
66
67
|
readonly crowdOf: Map<number, Crowd<I, O>>;
|
|
67
68
|
/** Whether two crowds share a channel, so their rows must interleave in voice order. */
|
|
@@ -71,13 +72,20 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
71
72
|
/** The lane and record `one` is folding, whose band state a rest-less channel reads. */
|
|
72
73
|
folding: Lane<I, O> | null;
|
|
73
74
|
rec: Subject<unknown> | null;
|
|
75
|
+
/** The numbers a fill's methods hand each other: see `Arg`. */
|
|
76
|
+
readonly arg: Float64Array<ArrayBuffer>;
|
|
74
77
|
/** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
|
|
75
78
|
into: Locus<I, O> | null;
|
|
76
79
|
intoId: number;
|
|
77
80
|
readonly lawsByKey: Map<string, Float64Array<ArrayBufferLike>>;
|
|
78
81
|
lastLaw: Float64Array | null;
|
|
79
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* The lanes the last `meet` gave a position, the first `metN` of `met`, and whether it placed a
|
|
84
|
+
* crowd row. Counted, not cut to length: an array emptied by its length takes new room at its
|
|
85
|
+
* next push, about 150 B a subject met (the `swap` row, bench/allocs.mjs, 2026-10-09).
|
|
86
|
+
*/
|
|
80
87
|
readonly met: number[];
|
|
88
|
+
metN: number;
|
|
81
89
|
metCrowd: boolean;
|
|
82
90
|
/** By subject number, the laned voices its probes fold on the general path this fill. */
|
|
83
91
|
readonly owed: Owed;
|
|
@@ -137,8 +145,9 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
137
145
|
keeps: boolean;
|
|
138
146
|
now: number;
|
|
139
147
|
filledAt: number;
|
|
140
|
-
/** `reading.moved` at the last fill
|
|
148
|
+
/** `reading.moved` and `reading.inputs` at the last fill: see `current`. */
|
|
141
149
|
moved: number;
|
|
150
|
+
inputs: number;
|
|
142
151
|
/** The `now` of the latest probe, and the probe count before its first, to tell a probe this frame. */
|
|
143
152
|
frameAt: number;
|
|
144
153
|
frameProbes: number;
|
|
@@ -191,6 +200,13 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
191
200
|
prepare(slot: number, subject: I, version: number, head: Subject<unknown> | null): boolean;
|
|
192
201
|
/** Whether this frame's lanes are filled and nothing since asks `begin` to look again. */
|
|
193
202
|
filled(now: number, version: number): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Whether the last fill still stands: everything a fill reads that can change between two probes,
|
|
205
|
+
* each stamped by `fillAll`. The clock; the mix's version, which voices coming, going, starting
|
|
206
|
+
* and stopping move; a motion's retargets and pushes; and a `level` set. Whatever else can change
|
|
207
|
+
* between probes keeps its voice off lanes in `fits`.
|
|
208
|
+
*/
|
|
209
|
+
current(now: number, version: number): boolean;
|
|
194
210
|
/**
|
|
195
211
|
* What a probe does before its subject, once a frame's lanes are settled: qualifies and fills as
|
|
196
212
|
* needed. Says whether the subject takes the general path or the lanes are filled.
|
|
@@ -215,8 +231,6 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
215
231
|
* would write: each number within 1e-9 of its rest.
|
|
216
232
|
*/
|
|
217
233
|
rests(slot: number): boolean;
|
|
218
|
-
/** Writes a subject's laned values into a pose, each array channel into a new array. */
|
|
219
|
-
copy(slot: number, pose: Record<string, unknown>): void;
|
|
220
234
|
forget(slot: number): void;
|
|
221
235
|
grow(size: number): void;
|
|
222
236
|
/**
|
|
@@ -224,16 +238,25 @@ export declare class Lanes<I, O> implements Watcher {
|
|
|
224
238
|
* next fill, and a lane keeps the sample the old one gave.
|
|
225
239
|
*/
|
|
226
240
|
stretchChanged(id: number, s: number): void;
|
|
241
|
+
/**
|
|
242
|
+
* A voice that kept one record for every subject keeps one each from now on: each of its lane's
|
|
243
|
+
* positions takes the record `of` gives its subject.
|
|
244
|
+
*/
|
|
245
|
+
rerecord(id: number, of: (subject: I, slot: number) => Subject<unknown>): void;
|
|
246
|
+
/** A voice's clock moved the `shown` of records it had already placed: copies them again. */
|
|
247
|
+
reshown(id: number): void;
|
|
227
248
|
/** Something on a voice changed: a crowd copies it again at the next fill. */
|
|
228
249
|
voiceChanged(id: number): void;
|
|
229
250
|
}
|
|
230
251
|
declare const methods: {
|
|
252
|
+
copy: typeof copy;
|
|
231
253
|
row: typeof row;
|
|
232
254
|
signalled: typeof signalled;
|
|
233
255
|
parting: typeof parting;
|
|
234
256
|
subjectAt: typeof subjectAt;
|
|
235
257
|
reset: typeof reset;
|
|
236
258
|
run: typeof run;
|
|
259
|
+
runEveryone: typeof runEveryone;
|
|
237
260
|
one: typeof one;
|
|
238
261
|
foldKeys: typeof foldKeys;
|
|
239
262
|
readKeyed: typeof readKeyed;
|
|
@@ -244,6 +267,7 @@ declare const methods: {
|
|
|
244
267
|
foldRun: typeof foldRun;
|
|
245
268
|
foldInto: typeof foldInto;
|
|
246
269
|
gate: typeof gate;
|
|
270
|
+
unplain: typeof unplain;
|
|
247
271
|
};
|
|
248
272
|
type Methods = typeof methods;
|
|
249
273
|
export interface Lanes<I, O> extends Methods {
|
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/locus.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { first } from './clone.js';
|
|
2
2
|
export function locusScratch(channels) {
|
|
3
3
|
return {
|
|
4
4
|
n: 0,
|
|
@@ -70,7 +70,7 @@ export function foldLocus(k, group) {
|
|
|
70
70
|
k.values[slot] =
|
|
71
71
|
this.lerpsInto[slot] !== undefined && channel.scale && Array.isArray(value)
|
|
72
72
|
? own(k, slot, value, channel.rest)
|
|
73
|
-
:
|
|
73
|
+
: first(value);
|
|
74
74
|
continue;
|
|
75
75
|
}
|
|
76
76
|
const total = taken[slot] + weight;
|
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,10 @@ 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';
|
|
8
9
|
import { GoneIndex } from './gone.js';
|
|
9
10
|
import type { HandleHost } from './handle.js';
|
|
10
11
|
import { held, shownOf, sinceOf, unreachedOf } from './held.js';
|
|
@@ -23,6 +24,13 @@ import { type Announced, Transport } from './transport.js';
|
|
|
23
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';
|
|
24
25
|
import { type Subject, type Voice } from './voice.js';
|
|
25
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
|
+
};
|
|
26
34
|
export declare class Mixer<I, O> implements Mix<I, O> {
|
|
27
35
|
readonly kit: Kit<O>;
|
|
28
36
|
readonly opts: MixOptions;
|
|
@@ -37,12 +45,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
37
45
|
backward: boolean;
|
|
38
46
|
/** True during a sync, so a control change it makes is recorded as showing in that frame. */
|
|
39
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;
|
|
40
53
|
/**
|
|
41
54
|
* Under `history` with `inputs`, the host fields patches read, copied each frame they changed. In
|
|
42
55
|
* a projection reading back, the copy in force then.
|
|
43
56
|
*/
|
|
44
57
|
hostLog: {
|
|
45
58
|
at: number;
|
|
59
|
+
seq: number;
|
|
46
60
|
fields: Record<string, unknown>;
|
|
47
61
|
}[];
|
|
48
62
|
hostThen: {
|
|
@@ -62,20 +76,23 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
62
76
|
/** Taken off its transport, so it takes no more calls until a seek puts it back. */
|
|
63
77
|
dropped: boolean;
|
|
64
78
|
readonly name: string | undefined;
|
|
65
|
-
/**
|
|
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
|
+
*/
|
|
66
83
|
frame: number;
|
|
67
84
|
/** Pending voices whose start the host gave, by its host time, kept where the rate puts it. */
|
|
68
85
|
pins: Map<Voice<I, O>, number> | null;
|
|
69
86
|
wantsPose: boolean;
|
|
70
87
|
/** The pose `pull` folds a subject into where it cannot read straight from the lanes. */
|
|
71
88
|
scratch: O | undefined;
|
|
72
|
-
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
73
89
|
/** Live voices by the earliest mix time `moveTo` would change each, a binary heap. */
|
|
74
90
|
due: Due<I, O>[];
|
|
75
91
|
/** Voices retired since `moveTo` last pruned them, in the order they retired. */
|
|
76
92
|
retired: Voice<I, O>[];
|
|
77
93
|
/** Visit every voice each sync, as before the due queue; for tests that compare the two. */
|
|
78
94
|
walkAll: boolean;
|
|
95
|
+
/** The last array `pull` read, by position, with each subject's chain head, to skip the lookup. */
|
|
79
96
|
pulled: I[];
|
|
80
97
|
pulledHeads: (Subject<unknown> | undefined)[];
|
|
81
98
|
/** Each remembered head's lane slot, and the `version` and `relinks` they were all current at. */
|
|
@@ -97,16 +114,18 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
97
114
|
onWake(fn: () => void): () => void;
|
|
98
115
|
/**
|
|
99
116
|
* Per subject, the first record of the chain through every live voice that reaches it, or a stub
|
|
100
|
-
* where none does. Relinked when `version` moves,
|
|
101
|
-
*
|
|
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`.
|
|
102
119
|
*/
|
|
103
120
|
chains: Store<I, Subject<unknown>>;
|
|
104
121
|
version: number;
|
|
105
|
-
readonly steps: Steps<Voice<I, O
|
|
122
|
+
readonly steps: Steps<Voice<I, O>, I>;
|
|
106
123
|
/** Per subject, the voices whose `subjects` name it, in voice order. */
|
|
107
124
|
named: Store<I, Voice<I, O>[]>;
|
|
108
125
|
/** Voices a subject has been faded out of, which `drop` looks in besides those that reach it. */
|
|
109
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;
|
|
110
129
|
/**
|
|
111
130
|
* Motion patches that may hold state for a subject no voice still reaching it plays, which `drop`
|
|
112
131
|
* frees besides those voices' own: per subject, a patch a voice naming it left while another
|
|
@@ -120,6 +139,15 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
120
139
|
naming: number;
|
|
121
140
|
/** The voices in the list that name no subjects, in voice order. */
|
|
122
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;
|
|
123
151
|
/** How many voices in the list carry a locus; with none, a fold allocates nothing. */
|
|
124
152
|
loci: number;
|
|
125
153
|
/** What every motion patch it plays asks for its voice's time, holding this mix weakly. */
|
|
@@ -216,6 +244,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
216
244
|
over?: number;
|
|
217
245
|
}): void;
|
|
218
246
|
drop(subject: I): void;
|
|
247
|
+
touch(subject?: I): void;
|
|
219
248
|
drain<E = unknown>(tag?: string): Sent<I, E>[];
|
|
220
249
|
/** Voices whose stop 0 is mid-computation, so a fold for one cannot re-enter itself. */
|
|
221
250
|
readonly folding: Set<number>;
|
|
@@ -225,7 +254,7 @@ export declare class Mixer<I, O> implements Mix<I, O> {
|
|
|
225
254
|
* is first asked, when probes start writing it.
|
|
226
255
|
*/
|
|
227
256
|
restStamps: Store<I, number> | null;
|
|
228
|
-
/** 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. */
|
|
229
258
|
private restsEpoch;
|
|
230
259
|
private restsFrame;
|
|
231
260
|
private restsVersion;
|
|
@@ -243,6 +272,9 @@ declare const methods: {
|
|
|
243
272
|
foldWith: typeof foldWith;
|
|
244
273
|
owedBy: typeof owedBy;
|
|
245
274
|
foldLoci: typeof foldLoci;
|
|
275
|
+
foldDetour: typeof foldDetour;
|
|
276
|
+
foldSharers: typeof foldSharers;
|
|
277
|
+
shared: typeof shared;
|
|
246
278
|
read: typeof read;
|
|
247
279
|
contribution: typeof contribution;
|
|
248
280
|
keyed: typeof keyed;
|