@solidjs/signals 2.0.0-beta.22 → 2.0.0-beta.24
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.js +199 -68
- package/dist/node.cjs +1138 -996
- package/dist/prod/core/async.js +27 -11
- package/dist/prod/core/core.js +33 -30
- package/dist/prod/core/effect.js +3 -3
- package/dist/prod/core/error.js +9 -0
- package/dist/prod/core/graph.js +7 -2
- package/dist/prod/core/heap.js +12 -12
- package/dist/prod/core/lanes.js +2 -2
- package/dist/prod/core/optimistic.js +5 -5
- package/dist/prod/core/owner.js +1 -1
- package/dist/prod/core/scheduler.js +11 -11
- package/dist/prod/core/verdict.js +30 -30
- package/dist/prod/map.js +53 -29
- package/dist/prod/store/optimistic.js +31 -29
- package/dist/prod/store/reconcile.js +92 -61
- package/dist/prod/store/store.js +143 -103
- package/dist/prod/store/utils.js +12 -0
- package/dist/types/core/error.d.ts +1 -1
- package/dist/types/store/reconcile.d.ts +17 -8
- package/dist/types-cjs/core/error.d.cts +1 -1
- package/dist/types-cjs/store/reconcile.d.cts +17 -8
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -1569,8 +1569,17 @@ function unlinkSubs(link) {
|
|
|
1569
1569
|
if (nextSub === null) {
|
|
1570
1570
|
dep._unobserved?.();
|
|
1571
1571
|
// No more subscribers; only tear down if CONFIG_AUTO_DISPOSE is set.
|
|
1572
|
+
// A pending node is exempt: its in-flight async work (or the
|
|
1573
|
+
// transition holding it) is an observer — tearing down would orphan
|
|
1574
|
+
// the work and re-execute it on the next read. The settle path runs
|
|
1575
|
+
// this same last-one-out check when that observer releases (the
|
|
1576
|
+
// untracked-read dispose in core.ts guards on pending identically).
|
|
1572
1577
|
const c = dep;
|
|
1573
|
-
c._fn &&
|
|
1578
|
+
c._fn &&
|
|
1579
|
+
c._config & CONFIG_AUTO_DISPOSE &&
|
|
1580
|
+
!(c._flags & REACTIVE_ZOMBIE) &&
|
|
1581
|
+
!(c._statusFlags & STATUS_PENDING) &&
|
|
1582
|
+
unobserved(c);
|
|
1574
1583
|
}
|
|
1575
1584
|
}
|
|
1576
1585
|
return nextDep;
|
|
@@ -1847,6 +1856,16 @@ function handleAsync(el, result, setter) {
|
|
|
1847
1856
|
flush();
|
|
1848
1857
|
then?.();
|
|
1849
1858
|
};
|
|
1859
|
+
// A pending node's in-flight promise is an observer: `unlinkSubs` skips
|
|
1860
|
+
// autodispose while STATUS_PENDING so subscriber churn can't orphan the
|
|
1861
|
+
// work (a lazy async memo would otherwise tear down and re-execute — one
|
|
1862
|
+
// fetch per suspended re-read). Settling is that observer's release, so
|
|
1863
|
+
// it runs the same last-one-out check the other release sites run.
|
|
1864
|
+
const settleAutodispose = () => {
|
|
1865
|
+
if (el._config & CONFIG_AUTO_DISPOSE && !el._subs && !(el._statusFlags & STATUS_PENDING)) {
|
|
1866
|
+
unobserved(el);
|
|
1867
|
+
}
|
|
1868
|
+
};
|
|
1850
1869
|
if (thenable) {
|
|
1851
1870
|
let resolved = false,
|
|
1852
1871
|
rejected = false,
|
|
@@ -1857,13 +1876,19 @@ function handleAsync(el, result, setter) {
|
|
|
1857
1876
|
if (isSync) {
|
|
1858
1877
|
syncValue = v;
|
|
1859
1878
|
resolved = true;
|
|
1860
|
-
} else
|
|
1879
|
+
} else {
|
|
1880
|
+
asyncWrite(v);
|
|
1881
|
+
settleAutodispose();
|
|
1882
|
+
}
|
|
1861
1883
|
},
|
|
1862
1884
|
e => {
|
|
1863
1885
|
if (isSync) {
|
|
1864
1886
|
syncError = e;
|
|
1865
1887
|
rejected = true;
|
|
1866
|
-
} else
|
|
1888
|
+
} else {
|
|
1889
|
+
handleError(e);
|
|
1890
|
+
settleAutodispose();
|
|
1891
|
+
}
|
|
1867
1892
|
}
|
|
1868
1893
|
);
|
|
1869
1894
|
isSync = false;
|
|
@@ -2113,7 +2138,10 @@ function clearSnapshots() {
|
|
|
2113
2138
|
if (snapshotSources) {
|
|
2114
2139
|
for (const source of snapshotSources) {
|
|
2115
2140
|
delete source._snapshotValue;
|
|
2116
|
-
|
|
2141
|
+
// StoreNode targets share one pre-initialized hidden class (see
|
|
2142
|
+
// createStoreProxy) — assign undefined instead of deleting, and only
|
|
2143
|
+
// when present so signal-node sources don't grow the field.
|
|
2144
|
+
if (source[STORE_SNAPSHOT_PROPS] !== undefined) source[STORE_SNAPSHOT_PROPS] = undefined;
|
|
2117
2145
|
}
|
|
2118
2146
|
snapshotSources = null;
|
|
2119
2147
|
}
|
|
@@ -4738,23 +4766,18 @@ function applyStateFast(next, target, keyFn) {
|
|
|
4738
4766
|
let tracked;
|
|
4739
4767
|
if (nodes) {
|
|
4740
4768
|
tracked = nodes[$TRACK];
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
(keyFn(previousValue) != null && keyFn(previousValue) !== keyFn(nextValue))
|
|
4754
|
-
) {
|
|
4755
|
-
tracked && setSignal(tracked, void 0);
|
|
4756
|
-
node && setSignal(node, isWrappable(nextValue) ? wrap(nextValue, target) : nextValue);
|
|
4757
|
-
} else applyState(nextValue, wrap(previousValue, target), keyFn);
|
|
4769
|
+
if (tracked || symbolKeyedRecords.has(nodes)) {
|
|
4770
|
+
const keys = tracked ? getAllKeys(previous, undefined, next) : nodeKeys(nodes);
|
|
4771
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
4772
|
+
diffNodeKey(keys[i], nodes, previous, next, target, tracked, keyFn);
|
|
4773
|
+
}
|
|
4774
|
+
} else {
|
|
4775
|
+
// Untracked, string-only node records (the overwhelmingly common case)
|
|
4776
|
+
// iterate in place — nodeKeys() allocated a fresh key array per object
|
|
4777
|
+
// per pass, which dominates allocation on large-graph reconciles.
|
|
4778
|
+
for (const key in nodes) {
|
|
4779
|
+
diffNodeKey(key, nodes, previous, next, target, tracked, keyFn);
|
|
4780
|
+
}
|
|
4758
4781
|
}
|
|
4759
4782
|
}
|
|
4760
4783
|
if (!tracked && target[STORE_DESC]) applyDescendants(previous, next, target, nodes, keyFn);
|
|
@@ -4767,6 +4790,24 @@ function applyStateFast(next, target, keyFn) {
|
|
|
4767
4790
|
}
|
|
4768
4791
|
}
|
|
4769
4792
|
}
|
|
4793
|
+
// One node-key step of the fast object diff — shared by the array-iterating
|
|
4794
|
+
// (tracked / symbol-keyed) and for-in (plain) loops in applyStateFast.
|
|
4795
|
+
function diffNodeKey(key, nodes, previous, next, target, tracked, keyFn) {
|
|
4796
|
+
const node = nodes[key];
|
|
4797
|
+
const previousValue = unwrap(previous[key]);
|
|
4798
|
+
let nextValue = unwrap(next[key]);
|
|
4799
|
+
if (previousValue === nextValue) return;
|
|
4800
|
+
if (
|
|
4801
|
+
!previousValue ||
|
|
4802
|
+
!isWrappable(previousValue) ||
|
|
4803
|
+
!isWrappable(nextValue) ||
|
|
4804
|
+
Array.isArray(previousValue) !== Array.isArray(nextValue) ||
|
|
4805
|
+
(keyFn(previousValue) != null && keyFn(previousValue) !== keyFn(nextValue))
|
|
4806
|
+
) {
|
|
4807
|
+
tracked && setSignal(tracked, void 0);
|
|
4808
|
+
node && setSignal(node, isWrappable(nextValue) ? wrap(nextValue, target) : nextValue);
|
|
4809
|
+
} else applyState(nextValue, wrap(previousValue, target), keyFn);
|
|
4810
|
+
}
|
|
4770
4811
|
function applyStateSlow(next, target, keyFn) {
|
|
4771
4812
|
const previous = target[STORE_VALUE];
|
|
4772
4813
|
const override = target[STORE_OVERRIDE];
|
|
@@ -4904,17 +4945,26 @@ function applyStateSlow(next, target, keyFn) {
|
|
|
4904
4945
|
}
|
|
4905
4946
|
}
|
|
4906
4947
|
}
|
|
4948
|
+
// No-key reconcile: every item reports "no key", which routes array diffs to
|
|
4949
|
+
// the positional branch and object descent to plain per-property merging.
|
|
4950
|
+
const NOKEY = () => null;
|
|
4907
4951
|
/**
|
|
4908
4952
|
* Returns a draft-mutating function that smart-merges `value` into a store,
|
|
4909
|
-
* preserving
|
|
4910
|
-
*
|
|
4911
|
-
*
|
|
4953
|
+
* preserving fine-grained reactivity: only changed leaves trigger updates.
|
|
4954
|
+
*
|
|
4955
|
+
* With a `key` (default `"id"`), array items whose key matches between old
|
|
4956
|
+
* and new states keep their identity (updated in place, moves and removals
|
|
4957
|
+
* update the corresponding signals) — the shape for keyed server payloads.
|
|
4958
|
+
* Items without the key field fall back to positional matching.
|
|
4912
4959
|
*
|
|
4913
|
-
*
|
|
4914
|
-
*
|
|
4960
|
+
* With `key: null`, matching is purely positional: index N of the new array
|
|
4961
|
+
* merges into index N of the old, and object properties merge recursively —
|
|
4962
|
+
* the classic pattern for fixed-shape data that churns in place (dashboards,
|
|
4963
|
+
* monitors), where no keyed diff pass is needed or wanted.
|
|
4915
4964
|
*
|
|
4916
4965
|
* @param value the next state to merge in
|
|
4917
|
-
* @param key property name (string) or extractor function for stable
|
|
4966
|
+
* @param key property name (string) or extractor function for stable
|
|
4967
|
+
* identity (default `"id"`); pass `null` for positional merging
|
|
4918
4968
|
*
|
|
4919
4969
|
* @example
|
|
4920
4970
|
* ```ts
|
|
@@ -4922,13 +4972,20 @@ function applyStateSlow(next, target, keyFn) {
|
|
|
4922
4972
|
*
|
|
4923
4973
|
* async function refresh() {
|
|
4924
4974
|
* const fresh = await api.getTodos();
|
|
4925
|
-
* setTodos(reconcile(fresh
|
|
4975
|
+
* setTodos(reconcile(fresh)); // diff-merge by `id`
|
|
4926
4976
|
* }
|
|
4977
|
+
*
|
|
4978
|
+
* // fixed-shape polling data — positional merge
|
|
4979
|
+
* setStats(reconcile(nextStats, null));
|
|
4927
4980
|
* ```
|
|
4928
4981
|
*/
|
|
4929
|
-
function reconcile(value, key) {
|
|
4982
|
+
function reconcile(value, key = "id") {
|
|
4930
4983
|
return state => {
|
|
4931
4984
|
if (state == null) throw new Error("Cannot reconcile null or undefined state");
|
|
4985
|
+
if (key === null) {
|
|
4986
|
+
applyState(value, state, NOKEY);
|
|
4987
|
+
return;
|
|
4988
|
+
}
|
|
4932
4989
|
const keyFn = typeof key === "string" ? item => item[key] : key;
|
|
4933
4990
|
const eq = keyFn(state);
|
|
4934
4991
|
if (eq !== undefined && keyFn(value) !== eq)
|
|
@@ -5131,13 +5188,37 @@ const STORE_VALUE = "v",
|
|
|
5131
5188
|
STORE_PARENT = "u",
|
|
5132
5189
|
STORE_DESC = "d";
|
|
5133
5190
|
const STORE_SELF_PENDING = Symbol("STORE_SELF_PENDING");
|
|
5191
|
+
// Every StoreNode field is initialized up front, in one fixed order, so all
|
|
5192
|
+
// targets share a single hidden class. The traps and reconcile read these
|
|
5193
|
+
// fields on their hottest paths; fields added lazily in varying orders made
|
|
5194
|
+
// those loads megamorphic across a large store graph (dictionary-mode probes
|
|
5195
|
+
// on every trap hit). Assignments elsewhere must never `delete` a field —
|
|
5196
|
+
// write `undefined` instead, or the shape degrades again.
|
|
5197
|
+
function initStoreFields(newTarget) {
|
|
5198
|
+
newTarget[STORE_OVERRIDE] = undefined;
|
|
5199
|
+
newTarget[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
5200
|
+
newTarget[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
5201
|
+
newTarget[STORE_NODE] = undefined;
|
|
5202
|
+
newTarget[STORE_HAS] = undefined;
|
|
5203
|
+
newTarget[STORE_CUSTOM_PROTO] = undefined;
|
|
5204
|
+
newTarget[STORE_WRAP] = undefined;
|
|
5205
|
+
newTarget[STORE_LOOKUP] = undefined;
|
|
5206
|
+
newTarget[STORE_FIREWALL] = undefined;
|
|
5207
|
+
newTarget[STORE_OPTIMISTIC] = undefined;
|
|
5208
|
+
newTarget[STORE_SNAPSHOT_PROPS] = undefined;
|
|
5209
|
+
newTarget[STORE_PARENT] = undefined;
|
|
5210
|
+
newTarget[STORE_DESC] = undefined;
|
|
5211
|
+
newTarget[$PROXY] = null;
|
|
5212
|
+
}
|
|
5134
5213
|
function createStoreProxy(value, traps = storeTraps, extend) {
|
|
5135
5214
|
let newTarget;
|
|
5136
5215
|
if (Array.isArray(value)) {
|
|
5137
5216
|
newTarget = [];
|
|
5138
|
-
newTarget
|
|
5217
|
+
newTarget[STORE_VALUE] = value;
|
|
5218
|
+
initStoreFields(newTarget);
|
|
5139
5219
|
} else {
|
|
5140
|
-
newTarget = {
|
|
5220
|
+
newTarget = { [STORE_VALUE]: value };
|
|
5221
|
+
initStoreFields(newTarget);
|
|
5141
5222
|
const unwrapped = value?.[$TARGET]?.[STORE_VALUE] ?? value;
|
|
5142
5223
|
const proto = Object.getPrototypeOf(unwrapped);
|
|
5143
5224
|
if (proto !== null && proto !== Object.prototype) {
|
|
@@ -5716,6 +5797,28 @@ const storeTraps = {
|
|
|
5716
5797
|
trackSelf(target);
|
|
5717
5798
|
return receiver;
|
|
5718
5799
|
}
|
|
5800
|
+
// Hot path: an existing node on a plain target — no firewall (so neither
|
|
5801
|
+
// selfRead nor the uninitialized guard can apply), no override layers,
|
|
5802
|
+
// no write scope, and a raw (non-proxy) source. This is the shape of
|
|
5803
|
+
// every effect re-read of a settled store; it pays one node read and the
|
|
5804
|
+
// wrap check, nothing else. Any exotic bit falls through to the full
|
|
5805
|
+
// resolution below, and dev strictRead keeps its warning path.
|
|
5806
|
+
if (
|
|
5807
|
+
!strictRead &&
|
|
5808
|
+
target[STORE_FIREWALL] === undefined &&
|
|
5809
|
+
target[STORE_OVERRIDE] === undefined &&
|
|
5810
|
+
target[STORE_OPTIMISTIC_OVERRIDE] === undefined &&
|
|
5811
|
+
!writeOverride &&
|
|
5812
|
+
(Writing === null || !Writing.has(receiver))
|
|
5813
|
+
) {
|
|
5814
|
+
const nodes = target[STORE_NODE];
|
|
5815
|
+
const node = nodes && nodes[property];
|
|
5816
|
+
if (node !== undefined && target[STORE_VALUE][$TARGET] === undefined) {
|
|
5817
|
+
let value = read(node);
|
|
5818
|
+
if (value === $DELETED) value = undefined;
|
|
5819
|
+
return isWrappable(value) ? wrap(value, target) : value;
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5719
5822
|
const selfRead = getObserver() === target[STORE_FIREWALL];
|
|
5720
5823
|
const nodes = getNodes(target, STORE_NODE);
|
|
5721
5824
|
const tracked = selfRead ? undefined : nodes[property];
|
|
@@ -6305,8 +6408,10 @@ function clearOptimisticOverride(target, completing) {
|
|
|
6305
6408
|
}
|
|
6306
6409
|
}
|
|
6307
6410
|
if (!remaining) {
|
|
6308
|
-
delete
|
|
6309
|
-
delete
|
|
6411
|
+
// Assignment, not delete: StoreNode targets share one pre-initialized
|
|
6412
|
+
// hidden class (see createStoreProxy) and a delete would demote it.
|
|
6413
|
+
target[STORE_OPTIMISTIC_OVERRIDE] = undefined;
|
|
6414
|
+
target[STORE_OPTIMISTIC_OWNERS] = undefined;
|
|
6310
6415
|
}
|
|
6311
6416
|
// Notify $TRACK
|
|
6312
6417
|
if (cleared && nodes?.[$TRACK]) {
|
|
@@ -6499,6 +6604,18 @@ function snapshotImpl(item, track, map, lookup) {
|
|
|
6499
6604
|
if (pendingCheckActive) witnessAffectsMark(target);
|
|
6500
6605
|
}
|
|
6501
6606
|
override = mergedOverlay(target);
|
|
6607
|
+
// A derived store's STORE_VALUE is the inner store's live proxy
|
|
6608
|
+
// (store-in-store: createOptimisticStore/createProjection over a store).
|
|
6609
|
+
// Without an overlay of its own, the fast path below would map to — and
|
|
6610
|
+
// could return — that proxy verbatim. Recurse instead so the
|
|
6611
|
+
// inner store's own target branch unwraps it (chains of any depth).
|
|
6612
|
+
// With an overlay, a fresh `result` is always built, so the walk over the
|
|
6613
|
+
// inner proxy already copies plain values.
|
|
6614
|
+
if (!override && target[STORE_VALUE][$TARGET]) {
|
|
6615
|
+
unwrapped = snapshotImpl(target[STORE_VALUE], track, map, lookup);
|
|
6616
|
+
map.set(item, unwrapped);
|
|
6617
|
+
return unwrapped;
|
|
6618
|
+
}
|
|
6502
6619
|
isArray = Array.isArray(target[STORE_VALUE]);
|
|
6503
6620
|
map.set(
|
|
6504
6621
|
item,
|
|
@@ -6912,19 +7029,7 @@ function updateKeyedMap() {
|
|
|
6912
7029
|
this._items = newItems.slice(0);
|
|
6913
7030
|
this._len = newLen;
|
|
6914
7031
|
} else {
|
|
6915
|
-
let start,
|
|
6916
|
-
end,
|
|
6917
|
-
newEnd,
|
|
6918
|
-
item,
|
|
6919
|
-
key,
|
|
6920
|
-
newIndices,
|
|
6921
|
-
newIndicesNext,
|
|
6922
|
-
removed,
|
|
6923
|
-
created,
|
|
6924
|
-
temp = new Array(newLen),
|
|
6925
|
-
tempNodes = new Array(newLen);
|
|
6926
|
-
rows = this._rows ? new Array(newLen) : undefined;
|
|
6927
|
-
indexes = this._indexes ? new Array(newLen) : undefined;
|
|
7032
|
+
let start, end, newEnd, item, key, newIndices, newIndicesNext, removed, created;
|
|
6928
7033
|
// skip common prefix
|
|
6929
7034
|
for (
|
|
6930
7035
|
start = 0, end = Math.min(this._len, newLen);
|
|
@@ -6935,7 +7040,8 @@ function updateKeyedMap() {
|
|
|
6935
7040
|
) {
|
|
6936
7041
|
if (this._rows) setSignal(this._rows[start], newItems[start]);
|
|
6937
7042
|
}
|
|
6938
|
-
// common suffix
|
|
7043
|
+
// skip common suffix — counted only; retained entries land in one pass
|
|
7044
|
+
// at commit instead of being staged and copied twice
|
|
6939
7045
|
for (
|
|
6940
7046
|
end = this._len - 1, newEnd = newLen - 1;
|
|
6941
7047
|
end >= start &&
|
|
@@ -6943,13 +7049,21 @@ function updateKeyedMap() {
|
|
|
6943
7049
|
(this._items[end] === newItems[newEnd] ||
|
|
6944
7050
|
(this._rows && compare(this._key, this._items[end], newItems[newEnd])));
|
|
6945
7051
|
end--, newEnd--
|
|
6946
|
-
)
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
7052
|
+
);
|
|
7053
|
+
// no structural change (every position matched in place at equal
|
|
7054
|
+
// length — the common post-reconcile shape): keep the same mapped
|
|
7055
|
+
// array identity so downstream consumers don't re-run at all
|
|
7056
|
+
if (start === newLen && this._len === newLen) {
|
|
7057
|
+
this._items = newItems.slice(0);
|
|
7058
|
+
return;
|
|
6951
7059
|
}
|
|
6952
|
-
|
|
7060
|
+
const dif = newLen - this._len;
|
|
7061
|
+
const temp = new Array(newLen);
|
|
7062
|
+
const tempNodes = new Array(newLen);
|
|
7063
|
+
rows = this._rows ? new Array(newLen) : undefined;
|
|
7064
|
+
indexes = this._indexes ? new Array(newLen) : undefined;
|
|
7065
|
+
// 0) prepare a map of all indices in the changed window of newItems,
|
|
7066
|
+
// scanning backwards so we encounter them in natural order
|
|
6953
7067
|
newIndices = new Map();
|
|
6954
7068
|
newIndicesNext = new Array(newEnd + 1);
|
|
6955
7069
|
for (j = newEnd; j >= start; j--) {
|
|
@@ -6959,7 +7073,9 @@ function updateKeyedMap() {
|
|
|
6959
7073
|
newIndicesNext[j] = i === undefined ? -1 : i;
|
|
6960
7074
|
newIndices.set(key, j);
|
|
6961
7075
|
}
|
|
6962
|
-
// 1) step through
|
|
7076
|
+
// 1) step through the old changed window and see if items can be found
|
|
7077
|
+
// in the new set; if so, stage them at their new positions; if not,
|
|
7078
|
+
// queue them for disposal at commit
|
|
6963
7079
|
for (i = start; i <= end; i++) {
|
|
6964
7080
|
item = this._items[i];
|
|
6965
7081
|
key = this._key ? this._key(item) : item;
|
|
@@ -6975,8 +7091,8 @@ function updateKeyedMap() {
|
|
|
6975
7091
|
}
|
|
6976
7092
|
// 2) create new rows into the temp arrays; an abort disposes only these
|
|
6977
7093
|
try {
|
|
6978
|
-
for (j = start; j
|
|
6979
|
-
if (j
|
|
7094
|
+
for (j = start; j <= newEnd; j++) {
|
|
7095
|
+
if (tempNodes[j] !== undefined) continue;
|
|
6980
7096
|
(created ??= []).push((tempNodes[j] = createOwner()));
|
|
6981
7097
|
temp[j] = runWithOwner(tempNodes[j], mapper);
|
|
6982
7098
|
}
|
|
@@ -6984,24 +7100,39 @@ function updateKeyedMap() {
|
|
|
6984
7100
|
if (created) for (i = 0; i < created.length; i++) created[i].dispose();
|
|
6985
7101
|
throw err;
|
|
6986
7102
|
}
|
|
6987
|
-
// 3) commit: land
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
7103
|
+
// 3) commit: land the retained prefix and suffix plus the staged window
|
|
7104
|
+
// into the fresh arrays, swap them in (new identity for downstream
|
|
7105
|
+
// change propagation), then dispose exited rows
|
|
7106
|
+
for (i = 0; i < start; i++) {
|
|
7107
|
+
temp[i] = this._mappings[i];
|
|
7108
|
+
tempNodes[i] = this._nodes[i];
|
|
7109
|
+
rows && (rows[i] = this._rows[i]);
|
|
7110
|
+
indexes && (indexes[i] = this._indexes[i]);
|
|
7111
|
+
}
|
|
7112
|
+
for (j = start; j <= newEnd; j++) {
|
|
7113
|
+
if (rows) setSignal(rows[j], newItems[j]);
|
|
7114
|
+
if (indexes) setSignal(indexes[j], j);
|
|
7115
|
+
}
|
|
7116
|
+
for (j = newEnd + 1; j < newLen; j++) {
|
|
7117
|
+
temp[j] = this._mappings[j - dif];
|
|
7118
|
+
tempNodes[j] = this._nodes[j - dif];
|
|
6991
7119
|
if (rows) {
|
|
6992
|
-
|
|
6993
|
-
setSignal(
|
|
7120
|
+
rows[j] = this._rows[j - dif];
|
|
7121
|
+
setSignal(rows[j], newItems[j]);
|
|
6994
7122
|
}
|
|
6995
7123
|
if (indexes) {
|
|
6996
|
-
|
|
6997
|
-
setSignal(
|
|
7124
|
+
indexes[j] = this._indexes[j - dif];
|
|
7125
|
+
if (dif !== 0) setSignal(indexes[j], j);
|
|
6998
7126
|
}
|
|
6999
7127
|
}
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7128
|
+
this._mappings = temp;
|
|
7129
|
+
this._nodes = tempNodes;
|
|
7130
|
+
rows && (this._rows = rows);
|
|
7131
|
+
indexes && (this._indexes = indexes);
|
|
7132
|
+
this._len = newLen;
|
|
7133
|
+
// save a copy of the mapped items for the next update
|
|
7004
7134
|
this._items = newItems.slice(0);
|
|
7135
|
+
if (removed) for (i = 0; i < removed.length; i++) removed[i].dispose();
|
|
7005
7136
|
}
|
|
7006
7137
|
});
|
|
7007
7138
|
return this._mappings;
|