@msb235/blits 0.14.0 → 0.15.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.
Files changed (187) hide show
  1. package/CHANGELOG.md +198 -0
  2. package/README.md +3 -3
  3. package/dist/ahead.d.ts +26 -0
  4. package/dist/ahead.js +264 -0
  5. package/dist/around.d.ts +11 -0
  6. package/dist/around.js +32 -0
  7. package/dist/bare.js +37 -14
  8. package/dist/blank.d.ts +10 -0
  9. package/dist/blank.js +26 -0
  10. package/dist/blend.d.ts +2 -1
  11. package/dist/blend.js +1 -6
  12. package/dist/bound.d.ts +70 -0
  13. package/dist/bound.js +351 -0
  14. package/dist/chain.d.ts +2 -1
  15. package/dist/chain.js +7 -5
  16. package/dist/changes.d.ts +24 -0
  17. package/dist/changes.js +189 -0
  18. package/dist/channels.d.ts +39 -13
  19. package/dist/channels.js +14 -5
  20. package/dist/color.d.ts +12 -10
  21. package/dist/color.js +25 -25
  22. package/dist/columns.d.ts +2 -1
  23. package/dist/columns.js +62 -38
  24. package/dist/contribution.d.ts +30 -0
  25. package/dist/contribution.js +374 -0
  26. package/dist/copyout.d.ts +10 -0
  27. package/dist/copyout.js +69 -24
  28. package/dist/crowd.d.ts +16 -6
  29. package/dist/crowd.js +20 -11
  30. package/dist/cue.d.ts +8 -1
  31. package/dist/cue.js +39 -13
  32. package/dist/cut.d.ts +8 -0
  33. package/dist/cut.js +4 -0
  34. package/dist/delay.d.ts +3 -0
  35. package/dist/delay.js +7 -0
  36. package/dist/drop.d.ts +9 -0
  37. package/dist/drop.js +84 -0
  38. package/dist/due.d.ts +24 -5
  39. package/dist/due.js +114 -34
  40. package/dist/easing.d.ts +6 -4
  41. package/dist/easing.js +7 -3
  42. package/dist/everyone.d.ts +8 -2
  43. package/dist/everyone.js +33 -3
  44. package/dist/fade.d.ts +2 -1
  45. package/dist/fade.js +2 -1
  46. package/dist/fill.d.ts +3 -2
  47. package/dist/fill.js +52 -20
  48. package/dist/fit.d.ts +44 -26
  49. package/dist/fit.js +10 -9
  50. package/dist/fold.d.ts +4 -37
  51. package/dist/fold.js +5 -513
  52. package/dist/gather.d.ts +12 -7
  53. package/dist/gather.js +179 -44
  54. package/dist/gone.js +2 -2
  55. package/dist/grid.d.ts +47 -0
  56. package/dist/grid.js +247 -0
  57. package/dist/handle.d.ts +2 -0
  58. package/dist/handle.js +14 -8
  59. package/dist/held.d.ts +2 -1
  60. package/dist/held.js +2 -1
  61. package/dist/history.d.ts +6 -5
  62. package/dist/history.js +7 -9
  63. package/dist/hosts.js +9 -15
  64. package/dist/index.d.ts +5 -4
  65. package/dist/keyfill.d.ts +1 -1
  66. package/dist/keyfill.js +5 -3
  67. package/dist/keyrows.d.ts +12 -0
  68. package/dist/keyrows.js +99 -12
  69. package/dist/lane.d.ts +38 -11
  70. package/dist/lane.js +46 -11
  71. package/dist/lanes.d.ts +30 -12
  72. package/dist/lanes.js +56 -36
  73. package/dist/leavings.d.ts +2 -2
  74. package/dist/leavings.js +1 -1
  75. package/dist/lives.d.ts +47 -0
  76. package/dist/lives.js +180 -0
  77. package/dist/meet.d.ts +2 -2
  78. package/dist/meet.js +95 -7
  79. package/dist/mixer.d.ts +56 -37
  80. package/dist/mixer.js +57 -171
  81. package/dist/motion.d.ts +14 -118
  82. package/dist/motion.js +16 -8
  83. package/dist/motions.d.ts +62 -155
  84. package/dist/motions.js +56 -370
  85. package/dist/moved.d.ts +1 -1
  86. package/dist/moved.js +16 -7
  87. package/dist/named.d.ts +6 -2
  88. package/dist/named.js +49 -3
  89. package/dist/numbers.d.ts +7 -0
  90. package/dist/numbers.js +33 -0
  91. package/dist/owed.d.ts +2 -0
  92. package/dist/owed.js +4 -0
  93. package/dist/pack.d.ts +2 -1
  94. package/dist/pack.js +2 -3
  95. package/dist/patch.d.ts +7 -3
  96. package/dist/patch.js +6 -2
  97. package/dist/places.d.ts +53 -0
  98. package/dist/places.js +171 -0
  99. package/dist/plot.d.ts +12 -0
  100. package/dist/plot.js +52 -0
  101. package/dist/project.d.ts +4 -4
  102. package/dist/project.js +9 -212
  103. package/dist/pull.js +22 -9
  104. package/dist/qualify.js +93 -31
  105. package/dist/reading.d.ts +6 -0
  106. package/dist/reading.js +5 -0
  107. package/dist/record.d.ts +5 -1
  108. package/dist/record.js +3 -2
  109. package/dist/relink.d.ts +1 -1
  110. package/dist/renumber.d.ts +10 -0
  111. package/dist/renumber.js +75 -0
  112. package/dist/restored.d.ts +2 -2
  113. package/dist/restored.js +1 -1
  114. package/dist/rests.d.ts +9 -0
  115. package/dist/rests.js +76 -0
  116. package/dist/revive.d.ts +3 -2
  117. package/dist/revive.js +2 -2
  118. package/dist/{locus.d.ts → role.d.ts} +10 -9
  119. package/dist/{locus.js → role.js} +3 -3
  120. package/dist/roles.d.ts +10 -0
  121. package/dist/roles.js +158 -0
  122. package/dist/roster.js +3 -3
  123. package/dist/rotation.d.ts +1 -1
  124. package/dist/rotation.js +1 -1
  125. package/dist/rows.js +28 -20
  126. package/dist/sample.d.ts +2 -2
  127. package/dist/sample.js +33 -7
  128. package/dist/seat.d.ts +17 -0
  129. package/dist/seat.js +25 -0
  130. package/dist/seek.js +5 -5
  131. package/dist/setting.d.ts +27 -0
  132. package/dist/setting.js +55 -0
  133. package/dist/shared.d.ts +1 -1
  134. package/dist/shared.js +1 -1
  135. package/dist/signals.d.ts +64 -32
  136. package/dist/signals.js +20 -18
  137. package/dist/stack.d.ts +5 -5
  138. package/dist/stack.js +5 -5
  139. package/dist/standing.d.ts +2 -1
  140. package/dist/standing.js +3 -2
  141. package/dist/store.d.ts +9 -0
  142. package/dist/store.js +24 -0
  143. package/dist/strays.d.ts +2 -1
  144. package/dist/strays.js +23 -15
  145. package/dist/stretch.d.ts +112 -0
  146. package/dist/stretch.js +9 -0
  147. package/dist/subject.d.ts +142 -0
  148. package/dist/subject.js +1 -0
  149. package/dist/tape.d.ts +9 -5
  150. package/dist/tape.js +5 -1
  151. package/dist/then.d.ts +9 -0
  152. package/dist/then.js +57 -0
  153. package/dist/ticker.d.ts +4 -4
  154. package/dist/trace.d.ts +4 -0
  155. package/dist/trace.js +255 -0
  156. package/dist/transport.d.ts +0 -8
  157. package/dist/transport.js +0 -4
  158. package/dist/turns.d.ts +4 -3
  159. package/dist/turns.js +4 -3
  160. package/dist/types/arc.d.ts +12 -11
  161. package/dist/types/channel.d.ts +12 -8
  162. package/dist/types/history.d.ts +35 -19
  163. package/dist/types/mix.d.ts +237 -163
  164. package/dist/types/motion.d.ts +151 -0
  165. package/dist/types/motion.js +1 -0
  166. package/dist/types/patch.d.ts +67 -34
  167. package/dist/types/place.d.ts +51 -36
  168. package/dist/types/trace.d.ts +51 -0
  169. package/dist/types/trace.js +1 -0
  170. package/dist/types/transport.d.ts +20 -18
  171. package/dist/types/voice.d.ts +144 -73
  172. package/dist/types/watch.d.ts +88 -40
  173. package/dist/types.d.ts +2 -0
  174. package/dist/unreached.d.ts +2 -0
  175. package/dist/unreached.js +7 -0
  176. package/dist/voice.d.ts +10 -143
  177. package/dist/voice.js +37 -82
  178. package/dist/warn.d.ts +2 -0
  179. package/dist/warn.js +1 -1
  180. package/dist/watch.d.ts +2 -2
  181. package/dist/watch.js +5 -3
  182. package/dist/wave.d.ts +4 -3
  183. package/dist/wave.js +3 -2
  184. package/dist/weigh.d.ts +7 -1
  185. package/dist/weigh.js +27 -0
  186. package/docs/schema.html +223 -34
  187. package/package.json +2 -2
package/dist/lane.js CHANGED
@@ -1,6 +1,14 @@
1
1
  import { unbareLane } from './bare.js';
2
- import { frozenTime } from './clock.js';
3
2
  import { motionOf } from './motion.js';
3
+ /**
4
+ * Keeps the weight a probe read from the last fill as `Row.PROBED`, for `weightOf`, before a fill
5
+ * writes the position's new weight; reads `per` only where the copy could change a bit.
6
+ */
7
+ export function keepProbed(data, o, per, q, fills) {
8
+ const w = data[o + 2 /* Row.WEIGHT */];
9
+ if ((w !== data[o + 3 /* Row.PROBED */] || w === 0) && per[q + 5 /* Per.LANE_FILL */] === fills - 1)
10
+ data[o + 3 /* Row.PROBED */] = w;
11
+ }
4
12
  /**
5
13
  * Below what share of its subjects probed last frame a lane stops filling, and above what share it
6
14
  * fills again; between the two it keeps doing what it did, so a host near the line does not flip
@@ -70,6 +78,8 @@ export class Lane {
70
78
  fade = 1;
71
79
  /** Whether the voice has no fade in or out this fill, so its envelope is 1 for every subject. */
72
80
  flat = false;
81
+ /** The fill that last ran it, so what it remembers within one fill is that fill's. */
82
+ ran = -1;
73
83
  /** The voice's clock at this fill, set before `one` runs its subjects. */
74
84
  elapsedNow = 0;
75
85
  /** A motion patch's state, which the lane samples in place of calling the patch. */
@@ -80,8 +90,12 @@ export class Lane {
80
90
  bareFill = -1;
81
91
  bareElapsed = Number.NaN;
82
92
  bareSeeks = Number.NaN;
83
- /** The locus its voice shares, gathered before the voices are folded in order. */
93
+ /** The role its voice shares, gathered before the voices are folded in order. */
84
94
  group = null;
95
+ /** The `Arg.MARK` it was last placed under, for a role run a subject at a time to put back. */
96
+ mark = Number.NaN;
97
+ /** Whether it took every subject when it opened, so a fill makes each one's first call. */
98
+ every = false;
85
99
  voiceAt() {
86
100
  return this.voice;
87
101
  }
@@ -128,6 +142,22 @@ export class Lane {
128
142
  positionOf(slot) {
129
143
  return slot < this.at.length ? this.at[slot] - 1 : -1;
130
144
  }
145
+ /**
146
+ * Room for `n` positions and subject numbers below `cap`, for a voice that reaches every subject:
147
+ * grown as it met them, a voice replaced every frame regrew both from nothing each frame.
148
+ */
149
+ reserve(n, cap) {
150
+ if (n * 8 /* Row.STRIDE */ > this.data.length) {
151
+ const data = new Float64Array(n * 8 /* Row.STRIDE */);
152
+ data.set(this.data);
153
+ this.data = data;
154
+ }
155
+ if (cap > this.at.length) {
156
+ const at = new Int32Array(cap);
157
+ at.set(this.at);
158
+ this.at = at;
159
+ }
160
+ }
131
161
  /** Gives a subject the voice reaches a position, from what its record fixed on first sight. */
132
162
  add(slot, held) {
133
163
  const p = this.list.length;
@@ -154,6 +184,20 @@ export class Lane {
154
184
  this.records[p] = held;
155
185
  this.deltas[p] = null;
156
186
  }
187
+ /** The subject numbered `from` is numbered `to` now, a number no position holds: same position. */
188
+ renumber(from, to) {
189
+ const p = this.positionOf(from);
190
+ if (p < 0)
191
+ return;
192
+ if (to >= this.at.length) {
193
+ const at = new Int32Array(Math.max(to + 1, this.at.length * 2, 64));
194
+ at.set(this.at);
195
+ this.at = at;
196
+ }
197
+ this.list[p] = to;
198
+ this.at[to] = p + 1;
199
+ this.at[from] = 0;
200
+ }
157
201
  /** A subject lost its number: the last position moves into its place. */
158
202
  remove(slot) {
159
203
  const p = this.positionOf(slot);
@@ -183,12 +227,3 @@ export class Lane {
183
227
  this.deltas[last] = null;
184
228
  }
185
229
  }
186
- /**
187
- * A subject's voice time once its voice's freezes apply: frozen at 0 before it starts and at the end
188
- * of its passes after, and NaN where it shows nothing, as past its end running back.
189
- */
190
- export function frozenAt(voice, elapsed) {
191
- if (elapsed > voice.span && voice.hidesPast)
192
- return Number.NaN;
193
- return frozenTime(elapsed, voice.freezesBefore, voice.freezesAfter, voice.span);
194
- }
package/dist/lanes.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  import type { Column } from './columns.js';
2
- import { copy } from './copyout.js';
2
+ import { type Copier, copy } from './copyout.js';
3
3
  import { type Crowd, row } from './crowd.js';
4
4
  import { call, foldKeys, one, parting, readKeyed, reset, run, runEveryone, signalled, subjectAt } from './fill.js';
5
5
  import { fold, foldDelta, foldInto, foldRun, gate, gather, unplain } from './gather.js';
6
- import { type Lane, type Laned, type Locus } from './lane.js';
7
- import type { Watcher } from './motions.js';
6
+ import { type Lane, type Laned, type Role } from './lane.js';
8
7
  import { absent, Numbers } from './numbers.js';
9
8
  import { Owed } from './owed.js';
10
9
  import { Placed } from './placed.js';
10
+ import { type Seat } from './seat.js';
11
+ import type { Watcher } from './stretch.js';
12
+ import type { Subject } from './subject.js';
11
13
  import type { Channel } from './types.js';
12
- import type { Subject, Voice } from './voice.js';
14
+ import type { Voice } from './voice.js';
13
15
  /** What a lane fill asks of the mix it belongs to. */
14
16
  export interface LaneHost<I, O> {
15
17
  readonly voices: readonly Voice<I, O>[];
@@ -69,7 +71,7 @@ export declare class Lanes<I, O> implements Watcher {
69
71
  readonly byId: Map<number, Lane<I, O>>;
70
72
  /** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
71
73
  crowds: Crowd<I, O>[];
72
- readonly crowdOf: Map<number, Crowd<I, O>>;
74
+ readonly seats: Map<number, Seat<I, O>>;
73
75
  /** Which crowd voices' rows are placed on each subject. */
74
76
  readonly placed: Placed;
75
77
  /**
@@ -79,15 +81,20 @@ export declare class Lanes<I, O> implements Watcher {
79
81
  unlinked: Float64Array<ArrayBuffer>;
80
82
  /** Whether two crowds share a channel, so their rows must interleave in voice order. */
81
83
  overlap: boolean;
82
- /** The loci whose voices are on lanes, every member of each on one. */
83
- loci: Locus<I, O>[];
84
+ /** The roles whose voices are on lanes, every member of each on one. */
85
+ roles: Role<I, O>[];
84
86
  /** The lane and record `one` is folding, whose band state a rest-less channel reads. */
85
87
  folding: Lane<I, O> | null;
88
+ /** Whether a probe meeting lanes has `one` make their first call for its subject: see `meet`. */
89
+ meeting: boolean;
90
+ /** The lanes the last subject met and `foldNow` folded at its probe, and the fill it did so in. */
91
+ folds: number[];
92
+ foldsFill: number;
86
93
  rec: Subject<unknown> | null;
87
94
  /** The numbers a fill's methods hand each other: see `Arg`. */
88
95
  readonly arg: Float64Array<ArrayBuffer>;
89
- /** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
90
- into: Locus<I, O> | null;
96
+ /** While a fill gathers a role: that role and the member gathering, where folds go instead. */
97
+ into: Role<I, O> | null;
91
98
  intoId: number;
92
99
  readonly lawsByKey: Map<string, Float64Array<ArrayBufferLike>>;
93
100
  lastLaw: Float64Array | null;
@@ -102,6 +109,8 @@ export declare class Lanes<I, O> implements Watcher {
102
109
  /** By subject number, the laned voices its probes fold on the general path this fill. */
103
110
  readonly owed: Owed;
104
111
  laned: Laned[];
112
+ /** Writes `laned`'s values for a subject into a pose; made at the first copy after they change. */
113
+ copier: Copier | null;
105
114
  /** By kit slot, the laned channel there. */
106
115
  bySlot: (Laned | undefined)[];
107
116
  /** By kit slot, whether a fill leaves the channel's values for probes to copy. */
@@ -138,6 +147,13 @@ export declare class Lanes<I, O> implements Watcher {
138
147
  subjects: (I | typeof absent | undefined)[];
139
148
  /** Whether a probe has held a subject since the last fill let them go. */
140
149
  holding: boolean;
150
+ /**
151
+ * Whether probes hold their subjects for the next fill: while the last fill looked one up. A
152
+ * fill of bare tweens never does, and holding cost a store a subject and a clear a frame.
153
+ */
154
+ holds: boolean;
155
+ /** How many times a fill or a probe has looked a subject up by number, for `holds`. */
156
+ lookups: number;
141
157
  /** While a fill runs, so a probe a patch makes from inside it takes the general path. */
142
158
  filling: boolean;
143
159
  /**
@@ -146,14 +162,16 @@ export declare class Lanes<I, O> implements Watcher {
146
162
  */
147
163
  readonly late: number[];
148
164
  /**
149
- * What `writeLater` and `pullRun` have queued, for one set of columns, as runs: each run's first
150
- * lane slot, the row it goes to, and how many subjects follow both one apart.
165
+ * What `writeLater` and `pullRun` have queued, for one set of columns, as runs of rows: each
166
+ * run's first row and how many follow, and its first lane slot where its slots follow one apart
167
+ * too, else -1, when each row's slot is read from `queueFrom` by row.
151
168
  */
152
169
  queueSlots: Int32Array<ArrayBuffer>;
153
170
  queueRows: Int32Array<ArrayBuffer>;
154
171
  queueCounts: Int32Array<ArrayBuffer>;
155
172
  queued: number;
156
173
  queuedFor: readonly Column[] | null;
174
+ queueFrom: Int32Array | null;
157
175
  keeps: boolean;
158
176
  now: number;
159
177
  filledAt: number;
@@ -270,7 +288,7 @@ export declare class Lanes<I, O> implements Watcher {
270
288
  /** A voice's clock moved the `shown` of records it had already placed: copies them again. */
271
289
  reshown(id: number): void;
272
290
  /** Something on a voice changed: a crowd copies it again at the next fill. */
273
- voiceChanged(id: number): void;
291
+ voiceChanged(voice: Voice<I, O>): void;
274
292
  }
275
293
  declare const methods: {
276
294
  copy: typeof copy;
package/dist/lanes.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { lit } from './bound.js';
1
2
  import { copy } from './copyout.js';
2
3
  import { row } from './crowd.js';
3
4
  import { call, fillAll, foldKeys, one, parting, readKeyed, reset, run, runEveryone, signalled, subjectAt, } from './fill.js';
@@ -9,6 +10,7 @@ import { Placed } from './placed.js';
9
10
  import { requalify, retouch } from './qualify.js';
10
11
  import { reading } from './reading.js';
11
12
  import { reportedRow, unplace } from './rows.js';
13
+ import { seatOf } from './seat.js';
12
14
  /**
13
15
  * The lanes of one mix: subject numbers, which channels and voices run on lanes, and the values a
14
16
  * frame's fill leaves for probes to copy.
@@ -23,7 +25,7 @@ export class Lanes {
23
25
  byId = new Map();
24
26
  /** The crowds of single-subject voices, one per list of channels, and which holds each voice. */
25
27
  crowds = [];
26
- crowdOf = new Map();
28
+ seats = new Map();
27
29
  /** Which crowd voices' rows are placed on each subject. */
28
30
  placed = new Placed();
29
31
  /**
@@ -33,14 +35,19 @@ export class Lanes {
33
35
  unlinked = new Float64Array(0);
34
36
  /** Whether two crowds share a channel, so their rows must interleave in voice order. */
35
37
  overlap = false;
36
- /** The loci whose voices are on lanes, every member of each on one. */
37
- loci = [];
38
+ /** The roles whose voices are on lanes, every member of each on one. */
39
+ roles = [];
38
40
  /** The lane and record `one` is folding, whose band state a rest-less channel reads. */
39
41
  folding = null;
42
+ /** Whether a probe meeting lanes has `one` make their first call for its subject: see `meet`. */
43
+ meeting = false;
44
+ /** The lanes the last subject met and `foldNow` folded at its probe, and the fill it did so in. */
45
+ folds = [];
46
+ foldsFill = -1;
40
47
  rec = null;
41
48
  /** The numbers a fill's methods hand each other: see `Arg`. */
42
- arg = new Float64Array(6 /* Arg.SIZE */);
43
- /** While a fill gathers a locus: that locus and the member gathering, where folds go instead. */
49
+ arg = new Float64Array(8 /* Arg.SIZE */);
50
+ /** While a fill gathers a role: that role and the member gathering, where folds go instead. */
44
51
  into = null;
45
52
  intoId = 0;
46
53
  lawsByKey = new Map();
@@ -56,6 +63,8 @@ export class Lanes {
56
63
  /** By subject number, the laned voices its probes fold on the general path this fill. */
57
64
  owed = new Owed();
58
65
  laned = [];
66
+ /** Writes `laned`'s values for a subject into a pose; made at the first copy after they change. */
67
+ copier = null;
59
68
  /** By kit slot, the laned channel there. */
60
69
  bySlot = [];
61
70
  /** By kit slot, whether a fill leaves the channel's values for probes to copy. */
@@ -92,6 +101,13 @@ export class Lanes {
92
101
  subjects = [];
93
102
  /** Whether a probe has held a subject since the last fill let them go. */
94
103
  holding = false;
104
+ /**
105
+ * Whether probes hold their subjects for the next fill: while the last fill looked one up. A
106
+ * fill of bare tweens never does, and holding cost a store a subject and a clear a frame.
107
+ */
108
+ holds = true;
109
+ /** How many times a fill or a probe has looked a subject up by number, for `holds`. */
110
+ lookups = 0;
95
111
  /** While a fill runs, so a probe a patch makes from inside it takes the general path. */
96
112
  filling = false;
97
113
  /**
@@ -100,14 +116,16 @@ export class Lanes {
100
116
  */
101
117
  late = [];
102
118
  /**
103
- * What `writeLater` and `pullRun` have queued, for one set of columns, as runs: each run's first
104
- * lane slot, the row it goes to, and how many subjects follow both one apart.
119
+ * What `writeLater` and `pullRun` have queued, for one set of columns, as runs of rows: each
120
+ * run's first row and how many follow, and its first lane slot where its slots follow one apart
121
+ * too, else -1, when each row's slot is read from `queueFrom` by row.
105
122
  */
106
123
  queueSlots = new Int32Array(0);
107
124
  queueRows = new Int32Array(0);
108
125
  queueCounts = new Int32Array(0);
109
126
  queued = 0;
110
127
  queuedFor = null;
128
+ queueFrom = null;
111
129
  keeps = false;
112
130
  now = Number.NaN;
113
131
  filledAt = Number.NaN;
@@ -218,10 +236,9 @@ export class Lanes {
218
236
  lane.remove(slot);
219
237
  return;
220
238
  }
221
- const c = this.crowdOf.get(id);
222
- const p = c?.rowOf.get(id);
223
- if (c !== undefined && p !== undefined && c.list[p] === slot)
224
- unplace(this, c, p);
239
+ const s = this.seats.get(id);
240
+ if (s !== undefined && s.crowd.list[s.row] === slot)
241
+ unplace(this, s.crowd, s.row);
225
242
  }
226
243
  /** A voice brought a subject back: its next probe meets every lane again, as it met them first. */
227
244
  rejoin(slot) {
@@ -239,9 +256,8 @@ export class Lanes {
239
256
  const lane = this.byId.get(id);
240
257
  if (lane !== undefined)
241
258
  return this.reported(lane, slot);
242
- const c = this.crowdOf.get(id);
243
- const p = c?.rowOf.get(id);
244
- return c === undefined || p === undefined ? undefined : reportedRow(this, c, p, slot);
259
+ const s = this.seats.get(id);
260
+ return s === undefined ? undefined : reportedRow(this, s.crowd, s.row, slot);
245
261
  }
246
262
  reported(lane, slot) {
247
263
  const o = slot * 6 /* Per.SLOT */;
@@ -275,8 +291,10 @@ export class Lanes {
275
291
  if (lane) {
276
292
  per[o + 3 /* Per.LANE_PROBE */] = probe;
277
293
  per[o + 5 /* Per.LANE_FILL */] = this.fills;
278
- this.subjects[slot] = subject;
279
- this.holding = true;
294
+ if (this.holds) {
295
+ this.subjects[slot] = subject;
296
+ this.holding = true;
297
+ }
280
298
  }
281
299
  else
282
300
  per[o + 4 /* Per.GENERAL_PROBE */] = probe;
@@ -381,8 +399,12 @@ export class Lanes {
381
399
  paid(id, slot, w) {
382
400
  const lane = this.byId.get(id);
383
401
  const p = lane === undefined ? -1 : lane.positionOf(slot);
384
- if (p >= 0)
385
- lane.data[p * 8 /* Row.STRIDE */ + 2 /* Row.WEIGHT */] = w;
402
+ if (p < 0)
403
+ return;
404
+ lane.data[p * 8 /* Row.STRIDE */ + 2 /* Row.WEIGHT */] = w;
405
+ const b = lane.voice.bound;
406
+ if (b !== null && w !== 0)
407
+ lit(b, slot, this.fills);
386
408
  }
387
409
  /**
388
410
  * Whether a subject's laned values are at their channels' rest, as `atRest` reads the pose `copy`
@@ -418,10 +440,9 @@ export class Lanes {
418
440
  lane.remove(slot);
419
441
  const placed = this.placed;
420
442
  for (let id = placed.any(slot); id !== 0; id = placed.any(slot)) {
421
- const c = this.crowdOf.get(id);
422
- const p = c?.rowOf.get(id);
423
- if (c !== undefined && p !== undefined && c.list[p] === slot)
424
- unplace(this, c, p);
443
+ const s = this.seats.get(id);
444
+ if (s !== undefined && s.crowd.list[s.row] === slot)
445
+ unplace(this, s.crowd, s.row);
425
446
  else
426
447
  placed.remove(slot, id);
427
448
  }
@@ -453,10 +474,10 @@ export class Lanes {
453
474
  * next fill, and a lane keeps the sample the old one gave.
454
475
  */
455
476
  stretchChanged(id, s) {
456
- const c = this.crowdOf.get(id);
457
- const p = c?.rowOf.get(id);
458
- if (c !== undefined && p !== undefined) {
459
- c.restale(p, c.hot[p * c.stride + 0 /* Hot.FLAGS */]);
477
+ const seat = this.seats.get(id);
478
+ if (seat !== undefined) {
479
+ const c = seat.crowd;
480
+ c.restale(seat.row, c.hot[seat.row * c.stride + 0 /* Hot.FLAGS */]);
460
481
  return;
461
482
  }
462
483
  const lane = this.byId.get(id);
@@ -481,12 +502,11 @@ export class Lanes {
481
502
  }
482
503
  /** A voice's clock moved the `shown` of records it had already placed: copies them again. */
483
504
  reshown(id) {
484
- const c = this.crowdOf.get(id);
485
- const p = c?.rowOf.get(id);
486
- if (c !== undefined && p !== undefined) {
487
- const held = c.records[p];
505
+ const s = this.seats.get(id);
506
+ if (s !== undefined) {
507
+ const held = s.crowd.records[s.row];
488
508
  if (held !== undefined)
489
- c.data[p * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
509
+ s.crowd.data[s.row * 8 /* Row.STRIDE */ + 1 /* Row.SINCE */] = held.shown;
490
510
  }
491
511
  const lane = this.byId.get(id);
492
512
  if (lane === undefined)
@@ -498,12 +518,12 @@ export class Lanes {
498
518
  }
499
519
  }
500
520
  /** Something on a voice changed: a crowd copies it again at the next fill. */
501
- voiceChanged(id) {
502
- const c = this.crowdOf.get(id);
503
- const p = c?.rowOf.get(id);
504
- if (c === undefined || p === undefined)
521
+ voiceChanged(voice) {
522
+ const s = seatOf(this, voice);
523
+ if (s === null)
505
524
  return;
506
- const f = p * c.stride + 0 /* Hot.FLAGS */;
525
+ const c = s.crowd;
526
+ const f = s.row * c.stride + 0 /* Hot.FLAGS */;
507
527
  c.hot[f] = c.hot[f] | 64 /* Flag.VOICE */;
508
528
  }
509
529
  }
@@ -1,5 +1,5 @@
1
- import { type Cut } from './transport.js';
2
- import type { Left, Subject } from './voice.js';
1
+ import { type Cut } from './cut.js';
2
+ import type { Left, Subject } from './subject.js';
3
3
  /**
4
4
  * Under history, the records subjects left a voice with, while a seek or a read back may reach
5
5
  * them: in the order they left, the oldest let go of from the front, and each subject's found
package/dist/leavings.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { within } from './cut.js';
1
2
  import { Store } from './store.js';
2
- import { within } from './transport.js';
3
3
  /**
4
4
  * Under history, the records subjects left a voice with, while a seek or a read back may reach
5
5
  * them: in the order they left, the oldest let go of from the front, and each subject's found
@@ -0,0 +1,47 @@
1
+ import { type Cut } from './cut.js';
2
+ import type { Motions } from './motions.js';
3
+ import { type Change, type Paging, type Run } from './stretch.js';
4
+ /** A run a release kept, with when: `early` where the release came before anything read its frame. */
5
+ export type Released<I> = {
6
+ subject: I;
7
+ at: number;
8
+ seq: number;
9
+ early: boolean;
10
+ } & Run;
11
+ /**
12
+ * Forgets a subject, so a later ask starts it afresh from `from`. Given the mix time `at` and frame
13
+ * `seq`, under history, its run is kept for a rewind before then, until `reach` passes it.
14
+ */
15
+ export declare function release<I>(this: Motions<I>, subject: I, at?: number, reach?: number, seq?: number, early?: boolean): void;
16
+ /** Puts back each subject released after frame `seq`, as it stood when released. */
17
+ export declare function unrelease<I>(this: Motions<I>, seq: number): void;
18
+ /** Subject `s`'s run as it stands. */
19
+ export declare function runAt<I>(this: Motions<I>, s: number): Run;
20
+ /** A subject's run as plain data, for a voice leaving memory; undefined where it has none. */
21
+ export declare function pack<I>(this: Motions<I>, subject: I): Run | undefined;
22
+ /** Puts a subject's run back as `pack` or a release left it, replacing any it has now. */
23
+ export declare function unpack<I>(this: Motions<I>, subject: I, run: Run): void;
24
+ /** A released run a history store gave back, for a rewind to before its release. */
25
+ export declare function reclaim<I>(this: Motions<I>, subject: I, at: number, seq: number, run: Run & {
26
+ early?: boolean;
27
+ }): void;
28
+ /**
29
+ * The run `subject` had in frame `cut`: the one a release after the cut kept, else the one it has
30
+ * now; undefined where it has neither. Its changes after the cut are still on it.
31
+ */
32
+ export declare function runThen<I>(this: Motions<I>, subject: I, cut: Cut): Run | undefined;
33
+ /**
34
+ * Stretches a history store gave back, each by the frame it was in force by: each life of the
35
+ * subject, ended by a release, takes those from its own, ahead of the earliest it still keeps.
36
+ */
37
+ export declare function restretch<I>(this: Motions<I>, subject: I, back: readonly Paging[]): void;
38
+ /**
39
+ * The mix time and frame a stretch was in force by, which a store keys it under: when the change
40
+ * that ended it was made, which falls in the same life of the subject.
41
+ */
42
+ export declare function made<I>(this: Motions<I>, c: Change | undefined): {
43
+ at: number;
44
+ seq: number;
45
+ };
46
+ /** Lets go of stretches older than the one in force at `reading.horizon`. */
47
+ export declare function prune<I>(this: Motions<I>, s: number): void;
package/dist/lives.js ADDED
@@ -0,0 +1,180 @@
1
+ import { within } from './cut.js';
2
+ import { absent } from './numbers.js';
3
+ import { reading } from './reading.js';
4
+ const PENDING = 2 /* RunFlag.PENDING */;
5
+ const OLDER = 4 /* RunFlag.OLDER */;
6
+ /** A run that shares nothing with the patch's own. */
7
+ const runOf = (r) => ({
8
+ flags: r.flags,
9
+ stretches: r.stretches.map((seg) => ({ ...seg })),
10
+ pending: r.pending?.map((c) => ({ ...c })),
11
+ });
12
+ /** `segs`, in time order, ahead of `list`: those older than its first, one per time. */
13
+ function ahead(segs, list) {
14
+ const first = list[0].at;
15
+ const out = [];
16
+ for (const seg of [...segs].sort((x, y) => x.at - y.at))
17
+ if (seg.at < first && out[out.length - 1]?.at !== seg.at)
18
+ out.push(seg);
19
+ return out.length === 0 ? list : [...out, ...list];
20
+ }
21
+ /**
22
+ * Forgets a subject, so a later ask starts it afresh from `from`. Given the mix time `at` and frame
23
+ * `seq`, under history, its run is kept for a rewind before then, until `reach` passes it.
24
+ */
25
+ export function release(subject, at, reach = Number.NEGATIVE_INFINITY, seq = Number.NaN, early = false) {
26
+ const s = this.known(subject);
27
+ if (s === undefined)
28
+ return;
29
+ if (at !== undefined) {
30
+ const kept = [];
31
+ for (const e of this.released)
32
+ if (e.at >= reach)
33
+ kept.push(e);
34
+ else
35
+ this.owner?.page(this.ownerId, 'released', e.subject, [
36
+ { at: e.at, seq: e.seq, data: { ...runOf(e), early: e.early } },
37
+ ]);
38
+ this.released = kept;
39
+ this.released.push({ subject, at, seq, early, ...this.runAt(s) });
40
+ }
41
+ this.slots.delete(subject);
42
+ this.numbers.release(s);
43
+ }
44
+ /** Puts back each subject released after frame `seq`, as it stood when released. */
45
+ export function unrelease(seq) {
46
+ const back = this.released.filter((e) => e.seq > seq).sort((a, b) => a.seq - b.seq);
47
+ if (back.length === 0)
48
+ return;
49
+ this.released = this.released.filter((e) => e.seq <= seq);
50
+ const done = new Set();
51
+ for (const e of back) {
52
+ if (done.has(e.subject))
53
+ continue;
54
+ done.add(e.subject);
55
+ this.unpack(e.subject, e);
56
+ }
57
+ }
58
+ /** Subject `s`'s run as it stands. */
59
+ export function runAt(s) {
60
+ const older = this.older?.[s];
61
+ const pending = this.pending?.[s];
62
+ return {
63
+ flags: this.runs[this.base(s) + 1],
64
+ stretches: older === undefined ? [this.latest(s)] : [...older, this.latest(s)],
65
+ pending: pending === undefined ? undefined : [...pending],
66
+ };
67
+ }
68
+ /** A subject's run as plain data, for a voice leaving memory; undefined where it has none. */
69
+ export function pack(subject) {
70
+ const s = this.known(subject);
71
+ return s === undefined ? undefined : runOf(this.runAt(s));
72
+ }
73
+ /** Puts a subject's run back as `pack` or a release left it, replacing any it has now. */
74
+ export function unpack(subject, run) {
75
+ const now = this.known(subject);
76
+ if (now !== undefined) {
77
+ this.slots.delete(subject);
78
+ this.numbers.release(now);
79
+ }
80
+ if (this.n < 0)
81
+ this.size(run.stretches[0].x0.length);
82
+ const s = this.take(subject);
83
+ this.runs[this.base(s) + 1] = run.flags & ~(OLDER | PENDING);
84
+ const latest = run.stretches[run.stretches.length - 1];
85
+ this.write(s, latest);
86
+ if (run.stretches.length > 1) {
87
+ if (this.older === null)
88
+ this.older = [undefined];
89
+ this.older[s] = run.stretches.slice(0, -1);
90
+ this.flag(s, OLDER, true);
91
+ }
92
+ if (run.pending !== undefined) {
93
+ if (this.pending === null)
94
+ this.pending = [undefined];
95
+ this.pending[s] = run.pending;
96
+ this.flag(s, PENDING, true);
97
+ }
98
+ }
99
+ /** A released run a history store gave back, for a rewind to before its release. */
100
+ export function reclaim(subject, at, seq, run) {
101
+ if (this.released.some((e) => e.seq === seq && Object.is(e.subject, subject)))
102
+ return;
103
+ this.released.push({ subject, at, seq, ...run, early: run.early === true });
104
+ }
105
+ /**
106
+ * The run `subject` had in frame `cut`: the one a release after the cut kept, else the one it has
107
+ * now; undefined where it has neither. Its changes after the cut are still on it.
108
+ */
109
+ export function runThen(subject, cut) {
110
+ let life;
111
+ for (const e of this.released)
112
+ if (Object.is(e.subject, subject) &&
113
+ !within(cut, e.seq, e.early) &&
114
+ (life === undefined || e.seq < life.seq))
115
+ life = e;
116
+ if (life !== undefined)
117
+ return life;
118
+ const s = this.known(subject);
119
+ return s === undefined ? undefined : this.runAt(s);
120
+ }
121
+ /**
122
+ * Stretches a history store gave back, each by the frame it was in force by: each life of the
123
+ * subject, ended by a release, takes those from its own, ahead of the earliest it still keeps.
124
+ */
125
+ export function restretch(subject, back) {
126
+ const lives = this.released
127
+ .filter((e) => Object.is(e.subject, subject))
128
+ .sort((x, y) => x.seq - y.seq);
129
+ let from = Number.NEGATIVE_INFINITY;
130
+ const within = (to) => back.filter((r) => r.seq > from && r.seq <= to).map((r) => r.data);
131
+ for (const e of lives) {
132
+ e.stretches = ahead(within(e.seq), e.stretches);
133
+ from = e.seq;
134
+ }
135
+ const s = this.known(subject);
136
+ if (s === undefined)
137
+ return;
138
+ const older = this.older?.[s] ?? [];
139
+ const list = ahead(within(Number.POSITIVE_INFINITY), [...older, this.latest(s)]);
140
+ if (list.length === older.length + 1)
141
+ return;
142
+ if (this.older === null)
143
+ this.older = [undefined];
144
+ this.older[s] = list.slice(0, -1);
145
+ this.flag(s, OLDER, true);
146
+ }
147
+ /**
148
+ * The mix time and frame a stretch was in force by, which a store keys it under: when the change
149
+ * that ended it was made, which falls in the same life of the subject.
150
+ */
151
+ export function made(c) {
152
+ const made = c?.made;
153
+ if (made === undefined || Number.isNaN(made))
154
+ return { at: this.owner?.now() ?? Number.NaN, seq: this.owner?.seq() ?? Number.NaN };
155
+ return { at: made, seq: c?.seq ?? Number.NaN };
156
+ }
157
+ /** Lets go of stretches older than the one in force at `reading.horizon`. */
158
+ export function prune(s) {
159
+ const list = this.older?.[s];
160
+ if (list === undefined)
161
+ return;
162
+ let n = 0;
163
+ while (n < list.length &&
164
+ (n + 1 < list.length ? list[n + 1].at : this.runs[this.base(s)]) <=
165
+ reading.horizon)
166
+ n++;
167
+ if (n === 0)
168
+ return;
169
+ const out = list.splice(0, n);
170
+ const subject = this.numbers.subject(s);
171
+ if (this.owner !== null && subject !== absent)
172
+ this.owner.page(this.ownerId, 'stretch', subject, out.map((seg, i) => {
173
+ const next = out[i + 1] ?? list[0];
174
+ return { ...this.made(next === undefined ? this.causes?.[s] : next.change), data: seg };
175
+ }));
176
+ if (list.length === 0) {
177
+ this.older[s] = undefined;
178
+ this.flag(s, OLDER, false);
179
+ }
180
+ }
package/dist/meet.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { Lanes } from './lanes.js';
2
- import type { Subject } from './voice.js';
2
+ import type { Subject } from './subject.js';
3
3
  /**
4
4
  * Whether the lanes a probe of the subject at `slot` just met (`met`) can be folded on the general
5
- * path after the lanes' values: none is in a locus or a crowd, the subject owes none already this
5
+ * path after the lanes' values: none is in a role or a crowd, the subject owes none already this
6
6
  * fill, and each comes after every other laned voice in voice order, so folding it last folds in
7
7
  * the general path's order.
8
8
  */