@solidjs/signals 2.0.0-rc.15 → 2.0.0-rc.17
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/dist/dev-shared.js +2268 -1734
- package/dist/dev.attribution.js +75 -52
- package/dist/dev.js +1348 -658
- package/dist/observe/affects-marks.js +86 -0
- package/dist/observe/affects.js +22 -73
- package/dist/observe/boundaries.js +192 -190
- package/dist/observe/core/async.js +177 -131
- package/dist/observe/core/attribution-queries.js +1 -1
- package/dist/observe/core/attribution.js +176 -159
- package/dist/observe/core/constants.js +17 -3
- package/dist/observe/core/context.js +5 -3
- package/dist/observe/core/core.js +520 -364
- package/dist/observe/core/dev.js +66 -38
- package/dist/observe/core/effect.js +50 -48
- package/dist/observe/core/error.js +5 -3
- package/dist/observe/core/external.js +5 -6
- package/dist/observe/core/graph.js +60 -44
- package/dist/observe/core/heap.js +33 -33
- package/dist/observe/core/identities.js +62 -0
- package/dist/observe/core/lanes.js +238 -260
- package/dist/observe/core/owner.js +117 -79
- package/dist/observe/core/scheduler.js +381 -217
- package/dist/observe/core/truth.js +45 -0
- package/dist/observe/core/verdict.js +91 -50
- package/dist/observe/deferred.js +184 -0
- package/dist/observe/index.js +7 -1
- package/dist/observe/map.js +345 -260
- package/dist/observe/reveal.js +76 -76
- package/dist/observe/signals.js +47 -31
- package/dist/observe/store/affects.js +18 -18
- package/dist/observe/store/edges.js +39 -0
- package/dist/observe/store/optimistic.js +146 -100
- package/dist/observe/store/projection.js +68 -55
- package/dist/observe/store/store.js +180 -118
- package/dist/prod/affects-marks.js +86 -0
- package/dist/prod/affects.js +23 -72
- package/dist/prod/boundaries.js +156 -154
- package/dist/prod/core/async.js +173 -127
- package/dist/prod/core/constants.js +17 -3
- package/dist/prod/core/context.js +5 -3
- package/dist/prod/core/core.js +495 -343
- package/dist/prod/core/effect.js +70 -68
- package/dist/prod/core/error.js +5 -3
- package/dist/prod/core/external.js +5 -6
- package/dist/prod/core/graph.js +60 -44
- package/dist/prod/core/heap.js +38 -38
- package/dist/prod/core/identities.js +62 -0
- package/dist/prod/core/lanes.js +230 -252
- package/dist/prod/core/owner.js +114 -77
- package/dist/prod/core/scheduler.js +327 -163
- package/dist/prod/core/truth.js +45 -0
- package/dist/prod/core/verdict.js +90 -49
- package/dist/prod/deferred.js +182 -0
- package/dist/prod/index.js +7 -1
- package/dist/prod/map.js +360 -275
- package/dist/prod/reveal.js +76 -76
- package/dist/prod/signals.js +42 -26
- package/dist/prod/store/affects.js +6 -6
- package/dist/prod/store/edges.js +39 -0
- package/dist/prod/store/optimistic.js +143 -98
- package/dist/prod/store/projection.js +25 -19
- package/dist/prod/store/store.js +157 -100
- package/dist/types/affects-marks.d.ts +14 -0
- package/dist/types/boundaries.d.ts +1 -1
- package/dist/types/core/async.d.ts +10 -0
- package/dist/types/core/constants.d.ts +13 -1
- package/dist/types/core/core.d.ts +54 -5
- package/dist/types/core/dev.d.ts +51 -13
- package/dist/types/core/error.d.ts +9 -1
- package/dist/types/core/graph.d.ts +11 -0
- package/dist/types/core/identities.d.ts +17 -0
- package/dist/types/core/index.d.ts +2 -1
- package/dist/types/core/lanes.d.ts +2 -14
- package/dist/types/core/owner.d.ts +9 -3
- package/dist/types/core/scheduler.d.ts +70 -32
- package/dist/types/core/truth.d.ts +16 -0
- package/dist/types/core/types.d.ts +21 -0
- package/dist/types/core/verdict.d.ts +32 -0
- package/dist/types/deferred.d.ts +28 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/map.d.ts +2 -2
- package/dist/types/signals.d.ts +28 -7
- package/dist/types/store/edges.d.ts +9 -0
- package/dist/types/store/index.d.ts +10 -3
- package/dist/types/store/optimistic.d.ts +3 -2
- package/dist/types/store/projection.d.ts +4 -3
- package/dist/types/store/store.d.ts +1 -1
- package/dist/types/store/target.d.ts +16 -8
- package/dist/types/store/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/prod/map.js
CHANGED
|
@@ -16,98 +16,98 @@ import { accessor } from "./signals.js";
|
|
|
16
16
|
|
|
17
17
|
import { $TRACK } from "./store/types.js";
|
|
18
18
|
|
|
19
|
-
function mapArray(t,
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
19
|
+
function mapArray(t, e, i) {
|
|
20
|
+
const s = typeof i?.keyed === "function" ? i.keyed : undefined;
|
|
21
|
+
const n = e.length > 1;
|
|
22
|
+
const r = e;
|
|
23
23
|
const o = {
|
|
24
24
|
L: createOwner(),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
it: 0,
|
|
26
|
+
st: t,
|
|
27
|
+
ot: [],
|
|
28
|
+
ft: r,
|
|
29
|
+
ht: [],
|
|
30
|
+
tn: [],
|
|
31
|
+
ze: s,
|
|
32
|
+
ct: s || i?.keyed === false ? [] : undefined,
|
|
33
|
+
lt: n && i?.keyed !== false ? [] : undefined,
|
|
34
|
+
ut: i?.keyed === false,
|
|
35
|
+
H: i?.fallback
|
|
36
36
|
};
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
return accessor(
|
|
37
|
+
const f = computed(updateKeyedMap.bind(o), undefined);
|
|
38
|
+
f.l &= ~CONFIG_AUTO_DISPOSE;
|
|
39
|
+
return accessor(f);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const pureOptions = {
|
|
43
43
|
ownedWrite: true
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
function trySmallMove(t,
|
|
47
|
-
const
|
|
48
|
-
const
|
|
46
|
+
function trySmallMove(t, e, i, s) {
|
|
47
|
+
const n = t.ot;
|
|
48
|
+
const r = t.it - 1;
|
|
49
49
|
const o = [];
|
|
50
|
-
const h = [];
|
|
51
50
|
const f = [];
|
|
51
|
+
const h = [];
|
|
52
52
|
// flat triples: oldStart, newStart, length
|
|
53
53
|
let c = 256;
|
|
54
|
-
let a =
|
|
55
|
-
let
|
|
56
|
-
let
|
|
57
|
-
while (a <=
|
|
58
|
-
const t =
|
|
59
|
-
const
|
|
60
|
-
if (t ===
|
|
61
|
-
if (!
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
let a = s;
|
|
55
|
+
let l = s;
|
|
56
|
+
let u = false;
|
|
57
|
+
while (a <= r && l <= i - 1) {
|
|
58
|
+
const t = n[a];
|
|
59
|
+
const s = e[l];
|
|
60
|
+
if (t === s) {
|
|
61
|
+
if (!u) {
|
|
62
|
+
h.push(a, l, 0);
|
|
63
|
+
u = true;
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
h[h.length - 1]++;
|
|
66
66
|
a++;
|
|
67
|
-
|
|
67
|
+
l++;
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
u = false;
|
|
71
71
|
// Bounded realignment lookahead, shorter distance wins.
|
|
72
|
-
let
|
|
73
|
-
let
|
|
74
|
-
for (let t = 1; t <=
|
|
75
|
-
if (
|
|
76
|
-
|
|
72
|
+
let d = -1;
|
|
73
|
+
let w = Math.min(32 - o.length, r - a, c);
|
|
74
|
+
for (let t = 1; t <= w; t++) {
|
|
75
|
+
if (n[a + t] === s) {
|
|
76
|
+
d = t;
|
|
77
77
|
break;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
c -=
|
|
81
|
-
let
|
|
82
|
-
|
|
83
|
-
for (let
|
|
84
|
-
if (
|
|
85
|
-
|
|
80
|
+
c -= d === -1 ? w : d;
|
|
81
|
+
let p = -1;
|
|
82
|
+
w = Math.min(32 - f.length, i - 1 - l, c);
|
|
83
|
+
for (let i = 1; i <= w; i++) {
|
|
84
|
+
if (e[l + i] === t) {
|
|
85
|
+
p = i;
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
-
c -=
|
|
90
|
-
if (
|
|
91
|
-
while (
|
|
89
|
+
c -= p === -1 ? w : p;
|
|
90
|
+
if (d !== -1 && (p === -1 || d <= p)) {
|
|
91
|
+
while (d-- > 0) o.push(a++);
|
|
92
92
|
continue;
|
|
93
93
|
}
|
|
94
|
-
if (
|
|
95
|
-
while (
|
|
94
|
+
if (p !== -1) {
|
|
95
|
+
while (p-- > 0) f.push(l++);
|
|
96
96
|
continue;
|
|
97
97
|
}
|
|
98
|
-
if (c <= 0 || o.length === 32 ||
|
|
98
|
+
if (c <= 0 || o.length === 32 || f.length === 32) return false;
|
|
99
99
|
o.push(a++);
|
|
100
|
-
|
|
100
|
+
f.push(l++);
|
|
101
101
|
}
|
|
102
|
-
for (;a <=
|
|
102
|
+
for (;a <= r; a++) {
|
|
103
103
|
if (o.length === 32) return false;
|
|
104
104
|
o.push(a);
|
|
105
105
|
}
|
|
106
|
-
for (;
|
|
107
|
-
if (
|
|
108
|
-
|
|
106
|
+
for (;l <= i - 1; l++) {
|
|
107
|
+
if (f.length === 32) return false;
|
|
108
|
+
f.push(l);
|
|
109
109
|
}
|
|
110
|
-
return commitSmallMove(t,
|
|
110
|
+
return commitSmallMove(t, e, i, o, f, h);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/** PHASE 2 of the small-move path, in its OWN function so that a pass which
|
|
@@ -116,24 +116,24 @@ function trySmallMove(t, s, e, i) {
|
|
|
116
116
|
* per function, and cold `replace` measured +0.5 ms with both phases in one
|
|
117
117
|
* body. Pairs displaced sources with destinations (an unmatched destination
|
|
118
118
|
* is a replacement/insertion → general path), then commits: slice() the live
|
|
119
|
-
* arrays, copy shifted runs, patch displaced pairs, dispose leftovers. */ function commitSmallMove(t,
|
|
120
|
-
const o = t.
|
|
121
|
-
let h;
|
|
119
|
+
* arrays, copy shifted runs, patch displaced pairs, dispose leftovers. */ function commitSmallMove(t, e, i, s, n, r) {
|
|
120
|
+
const o = t.ot;
|
|
122
121
|
let f;
|
|
122
|
+
let h;
|
|
123
123
|
let c;
|
|
124
|
-
if (
|
|
125
|
-
c = new Array(
|
|
126
|
-
for (
|
|
124
|
+
if (n.length !== 0) {
|
|
125
|
+
c = new Array(s.length);
|
|
126
|
+
for (h = 0; h < n.length; h++) {
|
|
127
127
|
let t = -1;
|
|
128
|
-
for (
|
|
129
|
-
if (!c[
|
|
130
|
-
t =
|
|
128
|
+
for (f = 0; f < s.length; f++) {
|
|
129
|
+
if (!c[f] && o[s[f]] === e[n[h]]) {
|
|
130
|
+
t = f;
|
|
131
131
|
break;
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
if (t === -1) return false;
|
|
135
135
|
c[t] = true;
|
|
136
|
-
|
|
136
|
+
n[h] = n[h] << 6 | t;
|
|
137
137
|
// pack pairing (found < 32)
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -143,46 +143,119 @@ function trySmallMove(t, s, e, i) {
|
|
|
143
143
|
// and if a displaced identity also occurs inside a run the two algorithms
|
|
144
144
|
// can hand different occurrences different owners (row-local state moves;
|
|
145
145
|
// a shrink could dispose the wrong one). Decline that case — general path.
|
|
146
|
-
if (
|
|
146
|
+
if (s.length !== 0 || n.length !== 0) {
|
|
147
147
|
const t = new Set;
|
|
148
|
-
for (
|
|
149
|
-
for (
|
|
150
|
-
for (let
|
|
151
|
-
const
|
|
152
|
-
for (let
|
|
148
|
+
for (f = 0; f < s.length; f++) t.add(o[s[f]]);
|
|
149
|
+
for (h = 0; h < n.length; h++) t.add(e[n[h] >> 6]);
|
|
150
|
+
for (let e = 0; e < r.length; e += 3) {
|
|
151
|
+
const i = r[e];
|
|
152
|
+
for (let s = 0, n = r[e + 2]; s < n; s++) if (t.has(o[i + s])) return false;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
const a = t.
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
for (let t = 0; t <
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
163
|
-
for (let
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
const a = t.ht;
|
|
156
|
+
const l = t.tn;
|
|
157
|
+
const u = a.slice(0, i);
|
|
158
|
+
const d = l.slice(0, i);
|
|
159
|
+
for (let t = 0; t < r.length; t += 3) {
|
|
160
|
+
const e = r[t];
|
|
161
|
+
const i = r[t + 1];
|
|
162
|
+
if (e !== i) {
|
|
163
|
+
for (let s = 0; s < r[t + 2]; s++) {
|
|
164
|
+
u[i + s] = a[e + s];
|
|
165
|
+
d[i + s] = l[e + s];
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
for (
|
|
170
|
-
const t =
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
for (h = 0; h < n.length; h++) {
|
|
170
|
+
const t = n[h] >> 6;
|
|
171
|
+
const e = s[n[h] & 63];
|
|
172
|
+
u[t] = a[e];
|
|
173
|
+
d[t] = l[e];
|
|
174
174
|
}
|
|
175
|
-
t.
|
|
176
|
-
t.
|
|
177
|
-
t.
|
|
178
|
-
t.
|
|
175
|
+
t.ht = u;
|
|
176
|
+
t.tn = d;
|
|
177
|
+
t.it = i;
|
|
178
|
+
t.ot = e.slice(0);
|
|
179
179
|
// Dispose unmatched sources LAST (general-path ordering).
|
|
180
|
-
for (
|
|
181
|
-
if (c === undefined || !c[
|
|
180
|
+
for (f = 0; f < s.length; f++) {
|
|
181
|
+
if (c === undefined || !c[f]) l[s[f]].dispose();
|
|
182
182
|
}
|
|
183
183
|
return true;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/** Stage a PURE REMOVAL without the key map: when the new window is the old
|
|
187
|
+
* window with items dropped, in order (one-item removals, every-nth, the
|
|
188
|
+
* table filters), a two-pointer walk lands every survivor in the window
|
|
189
|
+
* stage with one key call per item and returns the leavers; a shape that is
|
|
190
|
+
* not an ordered subsequence returns null with the node stage cleared, and
|
|
191
|
+
* the map path below starts from scratch (it rewrites every window slot of
|
|
192
|
+
* `temp` / `rows` / `indexes`, so only `tempNodes`' `!== undefined` probe
|
|
193
|
+
* needs the reset). The stage arrays are scratch — nothing live is touched. */ function stageRemoval(t, e, i, s, n, r, o, f, h) {
|
|
194
|
+
const c = t.ze;
|
|
195
|
+
const a = t.ot;
|
|
196
|
+
const l = t.tn;
|
|
197
|
+
const u = [];
|
|
198
|
+
let d = i;
|
|
199
|
+
for (let w = i; w <= n; d++, w++) {
|
|
200
|
+
const n = c ? c(e[w]) : e[w];
|
|
201
|
+
while (d <= s && (c ? c(a[d]) : a[d]) !== n) u.push(l[d++]);
|
|
202
|
+
if (d > s) {
|
|
203
|
+
o.fill(undefined);
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
r[w] = t.ht[d];
|
|
207
|
+
o[w - i] = l[d];
|
|
208
|
+
if (f) f[w - i] = t.ct[d];
|
|
209
|
+
if (h) h[w - i] = t.lt[d];
|
|
210
|
+
}
|
|
211
|
+
for (;d <= s; d++) u.push(l[d]);
|
|
212
|
+
return u;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Land a staged window into the live bookkeeping arrays in place: shift the
|
|
216
|
+
* suffix by `dif` (a loop walked from the side that never overwrites an
|
|
217
|
+
* unread slot), take the window from the stage, write survivors' row and
|
|
218
|
+
* index signals. Its own function so the general path's body stays under
|
|
219
|
+
* the JIT's optimization budget — the inlined commit measured ~10% slower on
|
|
220
|
+
* full-window reorders (the small-move note has the same finding). */ function commitWindow(t, e, i, s, n, r, o, f, h) {
|
|
221
|
+
const c = t.tn;
|
|
222
|
+
const a = t.ct;
|
|
223
|
+
const l = t.lt;
|
|
224
|
+
const u = t.it;
|
|
225
|
+
const d = i - u;
|
|
226
|
+
let w, p;
|
|
227
|
+
if (d > 0) {
|
|
228
|
+
// Grow first: a store past the end from the top is a third slower than
|
|
229
|
+
// filling a pre-sized tail (measured on 1k refs, 2026-10-15).
|
|
230
|
+
c.length = i;
|
|
231
|
+
if (a) a.length = i;
|
|
232
|
+
if (l) l.length = i;
|
|
233
|
+
for (w = u - 1, p = i - 1; w > n; w--, p--) {
|
|
234
|
+
c[p] = c[w];
|
|
235
|
+
if (a) a[p] = a[w];
|
|
236
|
+
if (l) l[p] = l[w];
|
|
237
|
+
}
|
|
238
|
+
} else if (d < 0) {
|
|
239
|
+
for (w = n + 1, p = r + 1; w < u; w++, p++) {
|
|
240
|
+
c[p] = c[w];
|
|
241
|
+
if (a) a[p] = a[w];
|
|
242
|
+
if (l) l[p] = l[w];
|
|
243
|
+
}
|
|
244
|
+
c.length = i;
|
|
245
|
+
if (a) a.length = i;
|
|
246
|
+
if (l) l.length = i;
|
|
247
|
+
}
|
|
248
|
+
for (p = s; p <= r; p++) {
|
|
249
|
+
c[p] = o[p - s];
|
|
250
|
+
if (a) setSignal(a[p] = f[p - s], e[p]);
|
|
251
|
+
if (l) setSignal(l[p] = h[p - s], p);
|
|
252
|
+
}
|
|
253
|
+
for (p = r + 1; p < i; p++) {
|
|
254
|
+
if (a) setSignal(a[p], e[p]);
|
|
255
|
+
if (l && d !== 0) setSignal(l[p], p);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
186
259
|
function updateKeyedMap() {
|
|
187
260
|
// Untracked reads inside the internal owner resolve via _parentComputed:
|
|
188
261
|
// routed through the node, a store-proxy lookup sees pending writes (not a
|
|
@@ -190,73 +263,80 @@ function updateKeyedMap() {
|
|
|
190
263
|
// the flight's reader (pending tracking + post-settle retry) instead of
|
|
191
264
|
// vanishing. Set per pass: the first pass runs inside `computed()`, before
|
|
192
265
|
// the node exists to the caller.
|
|
193
|
-
this.L.
|
|
194
|
-
const t = this.
|
|
266
|
+
this.L.Ye = getOwner();
|
|
267
|
+
const t = this.st() || [], e = t.length;
|
|
195
268
|
t[$TRACK];
|
|
196
269
|
// top level tracking (a store array's container node)
|
|
197
270
|
runWithOwner(this.L, () => {
|
|
198
|
-
let
|
|
271
|
+
let i, s,
|
|
272
|
+
// The stage slot a mapper writes its row/index signal into: `j` on the
|
|
273
|
+
// create-all path, `j - start` on the general path, whose stage arrays
|
|
274
|
+
// are sized to the changed WINDOW, not the list.
|
|
275
|
+
n, r, o,
|
|
199
276
|
// Mappers write freshly-created row/index signals into the STAGE
|
|
200
277
|
// arrays (`rows`/`indexes`), never into `this._rows`/`this._indexes`.
|
|
201
|
-
|
|
202
|
-
r[
|
|
203
|
-
return this.
|
|
278
|
+
f = this.ct ? this.ut ? () => {
|
|
279
|
+
r[n] = signal(t[s], pureOptions);
|
|
280
|
+
return this.ft(accessor(r[n]), s);
|
|
204
281
|
} : () => {
|
|
205
|
-
r[
|
|
206
|
-
|
|
207
|
-
return this.
|
|
208
|
-
} : this.
|
|
209
|
-
const
|
|
210
|
-
n
|
|
211
|
-
return this.
|
|
282
|
+
r[n] = signal(t[s], pureOptions);
|
|
283
|
+
o && (o[n] = signal(s, pureOptions));
|
|
284
|
+
return this.ft(accessor(r[n]), o ? accessor(o[n]) : undefined);
|
|
285
|
+
} : this.lt ? () => {
|
|
286
|
+
const e = t[s];
|
|
287
|
+
o[n] = signal(s, pureOptions);
|
|
288
|
+
return this.ft(e, accessor(o[n]));
|
|
212
289
|
} : () => {
|
|
213
|
-
const
|
|
214
|
-
return this.
|
|
290
|
+
const e = t[s];
|
|
291
|
+
return this.ft(e);
|
|
215
292
|
};
|
|
216
293
|
// fast path for empty arrays
|
|
217
|
-
if (
|
|
218
|
-
if (this.
|
|
294
|
+
if (e === 0) {
|
|
295
|
+
if (this.it !== 0) {
|
|
219
296
|
this.L.dispose(false);
|
|
220
|
-
this.
|
|
221
|
-
this.
|
|
222
|
-
this.
|
|
223
|
-
this.
|
|
224
|
-
this.
|
|
225
|
-
this.
|
|
297
|
+
this.tn = [];
|
|
298
|
+
this.ot = [];
|
|
299
|
+
this.ht = [];
|
|
300
|
+
this.it = 0;
|
|
301
|
+
this.ct && (this.ct = []);
|
|
302
|
+
this.lt && (this.lt = []);
|
|
226
303
|
}
|
|
227
|
-
if (this.
|
|
304
|
+
if (this.H && !this.ht.length) {
|
|
228
305
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
229
306
|
// dispose it before re-creating
|
|
230
|
-
this.
|
|
231
|
-
this.
|
|
307
|
+
this.tn[0]?.dispose();
|
|
308
|
+
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.H);
|
|
232
309
|
}
|
|
233
310
|
}
|
|
234
311
|
// fast path for new create
|
|
235
|
-
else if (this.
|
|
236
|
-
const h = new Array(
|
|
237
|
-
const
|
|
238
|
-
r = this.
|
|
239
|
-
|
|
312
|
+
else if (this.it === 0) {
|
|
313
|
+
const h = new Array(e);
|
|
314
|
+
const c = new Array(e);
|
|
315
|
+
r = this.ct && new Array(e);
|
|
316
|
+
o = this.lt && new Array(e);
|
|
240
317
|
try {
|
|
241
|
-
for (
|
|
318
|
+
for (s = 0; s < e; s++) {
|
|
319
|
+
n = s;
|
|
320
|
+
h[s] = runWithOwner(c[s] = createOwner(), f);
|
|
321
|
+
}
|
|
242
322
|
} catch (t) {
|
|
243
|
-
for (
|
|
323
|
+
for (i = 0; i <= s; i++) c[i]?.dispose();
|
|
244
324
|
throw t;
|
|
245
325
|
}
|
|
246
326
|
// commit
|
|
247
|
-
if (this.
|
|
327
|
+
if (this.tn[0]) this.tn[0].dispose();
|
|
248
328
|
// previous fallback
|
|
249
|
-
this.
|
|
250
|
-
this.
|
|
251
|
-
r && (this.
|
|
252
|
-
|
|
253
|
-
this.
|
|
254
|
-
this.
|
|
329
|
+
this.ht = h;
|
|
330
|
+
this.tn = c;
|
|
331
|
+
r && (this.ct = r);
|
|
332
|
+
o && (this.lt = o);
|
|
333
|
+
this.ot = t.slice(0);
|
|
334
|
+
this.it = e;
|
|
255
335
|
} else {
|
|
256
|
-
let h,
|
|
336
|
+
let h, c, a, l, u, d, w, p, m,
|
|
257
337
|
// Dev (attribution engine installed): the items behind the exited and
|
|
258
338
|
// entered rows, for the list-identity census.
|
|
259
|
-
|
|
339
|
+
O, _;
|
|
260
340
|
// The pass's write to a per-slot signal (a row accessor in index mode,
|
|
261
341
|
// an index accessor in keyed mode). The list's frame lives in these
|
|
262
342
|
// writes as much as in the computed's result, so under a LANE pass they
|
|
@@ -278,20 +358,20 @@ function updateKeyedMap() {
|
|
|
278
358
|
// takes `setSignal` directly. The engine is installed whenever a lane
|
|
279
359
|
// is active.
|
|
280
360
|
// CARVE 2: the lane-slot arm (`_landOnOverride`, F1) went with the engine.
|
|
281
|
-
const
|
|
361
|
+
const y = setSignal;
|
|
282
362
|
// skip common prefix
|
|
283
|
-
for (h = 0,
|
|
284
|
-
if (this.
|
|
363
|
+
for (h = 0, c = Math.min(this.it, e); h < c && (this.ot[h] === t[h] || this.ct && compare(this.ze, this.ot[h], t[h])); h++) {
|
|
364
|
+
if (this.ct) y(this.ct[h], t[h]);
|
|
285
365
|
}
|
|
286
366
|
// skip common suffix — counted only; retained entries land in one pass
|
|
287
367
|
// at commit instead of being staged and copied twice
|
|
288
|
-
for (
|
|
289
|
-
|
|
368
|
+
for (c = this.it - 1, a = e - 1; c >= h && a >= h && (this.ot[c] === t[a] || this.ct && compare(this.ze, this.ot[c], t[a])); c--,
|
|
369
|
+
a--) ;
|
|
290
370
|
// no structural change (every position matched in place at equal
|
|
291
371
|
// length — the common post-reconcile shape): keep the same mapped
|
|
292
372
|
// array identity so downstream consumers don't re-run at all
|
|
293
|
-
if (h ===
|
|
294
|
-
this.
|
|
373
|
+
if (h === e && this.it === e) {
|
|
374
|
+
this.ot = t.slice(0);
|
|
295
375
|
return;
|
|
296
376
|
}
|
|
297
377
|
// SMALL-MOVE FAST PATH: extracted to its own function — inlining it
|
|
@@ -301,103 +381,108 @@ function updateKeyedMap() {
|
|
|
301
381
|
// (plain removals, tail edits), the general path is window-
|
|
302
382
|
// proportional and cheap — the fast path would only re-walk what the
|
|
303
383
|
// trims proved.
|
|
304
|
-
if (
|
|
384
|
+
if (e <= this.it && c - h > 64 && this.ct === undefined && this.lt === undefined) {
|
|
305
385
|
// PROBE before the scan: a small move keeps a mid-window item within
|
|
306
386
|
// ±32 of its old position; a REPLACE (all fresh items — the shape
|
|
307
387
|
// every page's first structural pass usually is) has it nowhere.
|
|
308
388
|
// ~65 compares, no allocation, and the scan function is never
|
|
309
389
|
// compiled for a replace (its cold first-call compile was the cost).
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
const
|
|
313
|
-
let
|
|
314
|
-
while (
|
|
315
|
-
if (
|
|
316
|
-
}
|
|
317
|
-
const y = s - this.ht;
|
|
318
|
-
const A = new Array(s);
|
|
319
|
-
const M = new Array(s);
|
|
320
|
-
r = this.At ? new Array(s) : undefined;
|
|
321
|
-
n = this.Mt ? new Array(s) : undefined;
|
|
322
|
-
// 0) prepare a map of all indices in the changed window of newItems,
|
|
323
|
-
// scanning backwards so we encounter them in natural order
|
|
324
|
-
l = new Map;
|
|
325
|
-
p = new Array(c + 1);
|
|
326
|
-
for (i = c; i >= h; i--) {
|
|
327
|
-
a = t[i];
|
|
328
|
-
u = this.ot ? this.ot(a) : a;
|
|
329
|
-
e = l.get(u);
|
|
330
|
-
p[i] = e === undefined ? -1 : e;
|
|
331
|
-
l.set(u, i);
|
|
332
|
-
}
|
|
333
|
-
// 1) step through the old changed window and see if items can be found
|
|
334
|
-
// in the new set; if so, stage them at their new positions; if not,
|
|
335
|
-
// queue them for disposal at commit
|
|
336
|
-
for (e = h; e <= f; e++) {
|
|
337
|
-
a = this.wt[e];
|
|
338
|
-
u = this.ot ? this.ot(a) : a;
|
|
339
|
-
i = l.get(u);
|
|
340
|
-
if (i !== undefined && i !== -1) {
|
|
341
|
-
A[i] = this.yt[e];
|
|
342
|
-
M[i] = this.ln[e];
|
|
343
|
-
r && (r[i] = this.At[e]);
|
|
344
|
-
n && (n[i] = this.Mt[e]);
|
|
345
|
-
i = p[i];
|
|
346
|
-
l.set(u, i);
|
|
347
|
-
} else {
|
|
348
|
-
(d ??= []).push(this.ln[e]);
|
|
349
|
-
if (false && attrHooks !== null) ;
|
|
350
|
-
}
|
|
390
|
+
const i = h + (a - h >> 1);
|
|
391
|
+
const s = t[i];
|
|
392
|
+
const n = Math.min(c, i + 32);
|
|
393
|
+
let r = Math.max(h, i - 32);
|
|
394
|
+
while (r <= n && this.ot[r] !== s) r++;
|
|
395
|
+
if (r <= n && trySmallMove(this, t, e, h)) return;
|
|
351
396
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
397
|
+
const g = e - this.it;
|
|
398
|
+
// WINDOW-SIZED STAGING, IN-PLACE COMMIT (2026-10-15). The strong-abort
|
|
399
|
+
// contract (#2903) only needs the pass to touch nothing live before
|
|
400
|
+
// every mapper has succeeded; it never needed four fresh newLen-sized
|
|
401
|
+
// arrays. Only the changed window [start, newEnd] is staged — the
|
|
402
|
+
// prefix and suffix are, by construction, the rows that did not move
|
|
403
|
+
// relative to each other — and at commit the bookkeeping arrays
|
|
404
|
+
// (`_nodes`, `_rows`, `_indexes`) take the window in place with the
|
|
405
|
+
// suffix shifted by a plain loop (`copyWithin` is a generic
|
|
406
|
+
// per-element builtin in V8 — 30× slower than the loop on 1k refs,
|
|
407
|
+
// measured 2026-10-15). `_mappings` alone is
|
|
408
|
+
// rebuilt: its fresh identity is the change signal downstream relies
|
|
409
|
+
// on. A one-row edit on a 500-row list used to allocate ~20 KB of
|
|
410
|
+
// staging plus a position-sized chain array per commit (uibench's
|
|
411
|
+
// one-item tree ops at 4–6× Octane, jfb-reorder `removefirst` at
|
|
412
|
+
// 2.5×); now it stages one slot.
|
|
413
|
+
const A = a - h + 1;
|
|
414
|
+
const S = new Array(e);
|
|
415
|
+
const M = new Array(A);
|
|
416
|
+
r = this.ct ? new Array(A) : undefined;
|
|
417
|
+
o = this.lt ? new Array(A) : undefined;
|
|
418
|
+
// A shrinking pass is tried as a pure removal first (stageRemoval: no
|
|
419
|
+
// key map, one key call per item); anything else takes the map path.
|
|
420
|
+
const k = g < 0 ? stageRemoval(this, t, h, c, a, S, M, r, o) : null;
|
|
421
|
+
if (k !== null) {
|
|
422
|
+
// (The list-churn census below wants removals AND creations in one
|
|
423
|
+
// pass; a pure removal has none, so no item ledger is kept here.)
|
|
424
|
+
if (k.length !== 0) p = k;
|
|
425
|
+
} else {
|
|
426
|
+
// 0) prepare a map of all indices in the changed window of newItems,
|
|
427
|
+
// scanning backwards so we encounter them in natural order
|
|
428
|
+
d = new Map;
|
|
429
|
+
w = new Array(A);
|
|
430
|
+
for (s = a; s >= h; s--) {
|
|
431
|
+
l = t[s];
|
|
432
|
+
u = this.ze ? this.ze(l) : l;
|
|
433
|
+
i = d.get(u);
|
|
434
|
+
w[s - h] = i === undefined ? -1 : i;
|
|
435
|
+
d.set(u, s);
|
|
359
436
|
}
|
|
360
|
-
|
|
361
|
-
if
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
A[i] = this.yt[i - y];
|
|
379
|
-
M[i] = this.ln[i - y];
|
|
380
|
-
if (r) {
|
|
381
|
-
r[i] = this.At[i - y];
|
|
382
|
-
_(r[i], t[i]);
|
|
437
|
+
// 1) step through the old changed window and see if items can be found
|
|
438
|
+
// in the new set; if so, stage them at their new positions; if not,
|
|
439
|
+
// queue them for disposal at commit
|
|
440
|
+
for (i = h; i <= c; i++) {
|
|
441
|
+
l = this.ot[i];
|
|
442
|
+
u = this.ze ? this.ze(l) : l;
|
|
443
|
+
s = d.get(u);
|
|
444
|
+
if (s !== undefined && s !== -1) {
|
|
445
|
+
S[s] = this.ht[i];
|
|
446
|
+
M[s - h] = this.tn[i];
|
|
447
|
+
r && (r[s - h] = this.ct[i]);
|
|
448
|
+
o && (o[s - h] = this.lt[i]);
|
|
449
|
+
s = w[s - h];
|
|
450
|
+
d.set(u, s);
|
|
451
|
+
} else {
|
|
452
|
+
(p ??= []).push(this.tn[i]);
|
|
453
|
+
if (false && attrHooks !== null) ;
|
|
454
|
+
}
|
|
383
455
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
456
|
+
// 2) create new rows into the window stage; an abort disposes only these
|
|
457
|
+
try {
|
|
458
|
+
for (s = h; s <= a; s++) {
|
|
459
|
+
if (M[s - h] !== undefined) continue;
|
|
460
|
+
(m ??= []).push(M[s - h] = createOwner());
|
|
461
|
+
if (false && attrHooks !== null) ;
|
|
462
|
+
n = s - h;
|
|
463
|
+
S[s] = runWithOwner(M[s - h], f);
|
|
464
|
+
}
|
|
465
|
+
} catch (t) {
|
|
466
|
+
if (m) for (i = 0; i < m.length; i++) m[i].dispose();
|
|
467
|
+
throw t;
|
|
387
468
|
}
|
|
388
469
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
470
|
+
// 3) commit: the retained prefix and suffix land in the fresh mapped
|
|
471
|
+
// array; the bookkeeping arrays take the staged window IN PLACE (own
|
|
472
|
+
// function: kept out of this body on purpose, see commitWindow); then
|
|
473
|
+
// the exited rows dispose
|
|
474
|
+
for (i = 0; i < h; i++) S[i] = this.ht[i];
|
|
475
|
+
for (s = a + 1; s < e; s++) S[s] = this.ht[s - g];
|
|
476
|
+
commitWindow(this, t, e, h, c, a, M, r, o);
|
|
477
|
+
this.ht = S;
|
|
478
|
+
this.it = e;
|
|
394
479
|
// save a copy of the mapped items for the next update
|
|
395
|
-
this.
|
|
396
|
-
if (
|
|
397
|
-
if (false && attrHooks !== null &&
|
|
480
|
+
this.ot = t.slice(0);
|
|
481
|
+
if (p) for (i = 0; i < p.length; i++) p[i].dispose();
|
|
482
|
+
if (false && attrHooks !== null && O !== undefined && _ !== undefined) ;
|
|
398
483
|
}
|
|
399
484
|
});
|
|
400
|
-
return this.
|
|
485
|
+
return this.ht;
|
|
401
486
|
}
|
|
402
487
|
|
|
403
488
|
/**
|
|
@@ -413,23 +498,23 @@ function updateKeyedMap() {
|
|
|
413
498
|
* const view = repeat(count, i => `Item ${i}`, { fallback: () => "empty" });
|
|
414
499
|
* ```
|
|
415
500
|
*
|
|
416
|
-
* @description https://
|
|
417
|
-
*/ function repeat(t,
|
|
418
|
-
const
|
|
419
|
-
const
|
|
501
|
+
* @description https://v2.solidjs.com/reference/solid-js/advanced/jsx-component-primitives/repeat
|
|
502
|
+
*/ function repeat(t, e, i) {
|
|
503
|
+
const s = e;
|
|
504
|
+
const n = {
|
|
420
505
|
L: createOwner(),
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
506
|
+
it: 0,
|
|
507
|
+
dt: 0,
|
|
508
|
+
wt: t,
|
|
509
|
+
ft: s,
|
|
510
|
+
tn: [],
|
|
511
|
+
ht: [],
|
|
512
|
+
Ot: i?.from,
|
|
513
|
+
H: i?.fallback
|
|
429
514
|
};
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
return accessor(
|
|
515
|
+
const r = computed(updateRepeat.bind(n));
|
|
516
|
+
r.l &= ~CONFIG_AUTO_DISPOSE;
|
|
517
|
+
return accessor(r);
|
|
433
518
|
}
|
|
434
519
|
|
|
435
520
|
// Same staged-commit discipline as `updateKeyedMap` (#2903): the retained
|
|
@@ -441,60 +526,60 @@ function updateKeyedMap() {
|
|
|
441
526
|
// disjoint-window/front-clear/end-clear/shift special cases.
|
|
442
527
|
function updateRepeat() {
|
|
443
528
|
// As in updateKeyedMap: the node is the row callbacks' reader, per pass.
|
|
444
|
-
this.L.
|
|
445
|
-
const t = this.
|
|
446
|
-
const
|
|
529
|
+
this.L.Ye = getOwner();
|
|
530
|
+
const t = this.wt();
|
|
531
|
+
const e = this.Ot?.() || 0;
|
|
447
532
|
runWithOwner(this.L, () => {
|
|
448
533
|
if (t === 0) {
|
|
449
|
-
if (this.
|
|
534
|
+
if (this.it !== 0) {
|
|
450
535
|
this.L.dispose(false);
|
|
451
|
-
this.
|
|
452
|
-
this.
|
|
453
|
-
this.
|
|
536
|
+
this.tn = [];
|
|
537
|
+
this.ht = [];
|
|
538
|
+
this.it = 0;
|
|
454
539
|
// Reset offset to match the cleared data (#2767, repro 2).
|
|
455
|
-
this.
|
|
540
|
+
this.dt = 0;
|
|
456
541
|
}
|
|
457
|
-
if (this.
|
|
542
|
+
if (this.H && !this.ht.length) {
|
|
458
543
|
// an aborted fallback attempt leaves an owner without a mapping;
|
|
459
544
|
// dispose it before re-creating
|
|
460
|
-
this.
|
|
461
|
-
this.
|
|
545
|
+
this.tn[0]?.dispose();
|
|
546
|
+
this.ht[0] = runWithOwner(this.tn[0] = createOwner(), this.H);
|
|
462
547
|
}
|
|
463
548
|
return;
|
|
464
549
|
}
|
|
465
|
-
const
|
|
466
|
-
const
|
|
550
|
+
const i = e + t;
|
|
551
|
+
const s = this.dt + this.it;
|
|
467
552
|
// Retained overlap [keepStart, keepEnd) in global indexes; empty when the
|
|
468
553
|
// windows are disjoint or when coming from empty/fallback.
|
|
469
|
-
const
|
|
470
|
-
const
|
|
554
|
+
const n = Math.max(e, this.dt);
|
|
555
|
+
const r = Math.min(i, s);
|
|
471
556
|
const o = new Array(t);
|
|
472
|
-
const
|
|
473
|
-
for (let t =
|
|
474
|
-
|
|
475
|
-
o[t -
|
|
557
|
+
const f = new Array(t);
|
|
558
|
+
for (let t = n; t < r; t++) {
|
|
559
|
+
f[t - e] = this.tn[t - this.dt];
|
|
560
|
+
o[t - e] = this.ht[t - this.dt];
|
|
476
561
|
}
|
|
477
562
|
try {
|
|
478
|
-
for (let t =
|
|
479
|
-
if (t >=
|
|
480
|
-
o[t -
|
|
563
|
+
for (let t = e; t < i; t++) {
|
|
564
|
+
if (t >= n && t < r) continue;
|
|
565
|
+
o[t - e] = runWithOwner(f[t - e] = createOwner(), () => this.ft(t));
|
|
481
566
|
}
|
|
482
567
|
} catch (t) {
|
|
483
|
-
for (let t =
|
|
568
|
+
for (let t = e; t < i; t++) if ((t < n || t >= r) && f[t - e]) f[t - e].dispose();
|
|
484
569
|
throw t;
|
|
485
570
|
}
|
|
486
571
|
// commit: dispose the previous fallback or the rows leaving the window
|
|
487
|
-
if (this.
|
|
488
|
-
this.
|
|
489
|
-
this.
|
|
490
|
-
this.
|
|
491
|
-
this.
|
|
572
|
+
if (this.it === 0) this.tn[0]?.dispose(); else for (let t = this.dt; t < s; t++) if (t < e || t >= i) this.tn[t - this.dt].dispose();
|
|
573
|
+
this.ht = o;
|
|
574
|
+
this.tn = f;
|
|
575
|
+
this.dt = e;
|
|
576
|
+
this.it = t;
|
|
492
577
|
});
|
|
493
|
-
return this.
|
|
578
|
+
return this.ht;
|
|
494
579
|
}
|
|
495
580
|
|
|
496
|
-
function compare(t,
|
|
497
|
-
return t ? t(
|
|
581
|
+
function compare(t, e, i) {
|
|
582
|
+
return t ? t(e) === t(i) : true;
|
|
498
583
|
}
|
|
499
584
|
|
|
500
585
|
export { mapArray, repeat };
|