@univerjs-pro/engine-formula 0.22.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/facade.js +1 -1
- package/lib/cjs/index.js +1 -1
- package/lib/es/facade.js +1 -1
- package/lib/es/index.js +1 -1
- package/lib/facade.js +1 -1
- package/lib/index.js +1 -1
- package/lib/types/engine/dependency-engine/cell-codec.d.ts +39 -0
- package/lib/types/engine/dependency-engine/dependency-engine.d.ts +341 -0
- package/lib/types/engine/dependency-engine/formula-cell-index.d.ts +23 -0
- package/lib/types/engine/dependency-engine/helpers.d.ts +32 -0
- package/lib/types/engine/dependency-engine/node-helpers.d.ts +7 -0
- package/lib/types/engine/dependency-engine/point-subscription-index.d.ts +24 -0
- package/lib/types/engine/dependency-engine/range-index.d.ts +66 -0
- package/lib/types/engine/dependency-engine/types.d.ts +220 -0
- package/lib/types/engine/dependency-engine.d.ts +8 -0
- package/lib/types/engine/formula-dependency.d.ts +85 -23
- package/lib/types/engine/shared-formula-group-analyzer.d.ts +45 -0
- package/lib/types/index.d.ts +0 -1
- package/lib/types/plugin.d.ts +0 -2
- package/lib/types/services/calculate-formula.service.d.ts +18 -1
- package/lib/types/services/dependency-manager.service.d.ts +39 -14
- package/lib/umd/facade.js +1 -1
- package/lib/umd/index.js +1 -1
- package/package.json +5 -5
- package/lib/types/engine/lexer-tree-builder.d.ts +0 -25
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import type { CalcNodeIndex, CellId, DepList, ExternalNodeId, ICalcNodeDeps, ICalcNodeRef, ICalculationOrderResult, ICompressedSharedFormulaGroup, IDecodedCell, IDecodedFeatureCalculationId, IDecodedOtherFormulaId, IDependencyEngineOptions, IDynamicResolver, IRefRange, ISetNodeResult } from './types';
|
|
2
|
+
import { CellCodec } from './cell-codec';
|
|
3
|
+
import { RangeIndex } from './range-index';
|
|
4
|
+
/**
|
|
5
|
+
* Incremental dependency cache for formula calculation.
|
|
6
|
+
*
|
|
7
|
+
* The public API accepts direct cells, ranges, and explicit calc-node
|
|
8
|
+
* dependencies. Internally the graph direction is always
|
|
9
|
+
* `precedent -> dependent`, which makes dirty propagation and topological
|
|
10
|
+
* sorting cheap after changes.
|
|
11
|
+
*/
|
|
12
|
+
export declare class DependencyEngine {
|
|
13
|
+
readonly codec: CellCodec;
|
|
14
|
+
private readonly _maxIndexedSpan;
|
|
15
|
+
private readonly _pointScanCellLimit;
|
|
16
|
+
private readonly _initialNodeCapacity;
|
|
17
|
+
private readonly _initialRangeCapacity;
|
|
18
|
+
/**
|
|
19
|
+
* Direct cell precedent -> dependent calculation nodes.
|
|
20
|
+
*/
|
|
21
|
+
directDeps: Map<CellId, DepList>;
|
|
22
|
+
/**
|
|
23
|
+
* Explicit calc-node precedent -> dependent calculation nodes.
|
|
24
|
+
*/
|
|
25
|
+
nodeDeps: Map<CalcNodeIndex, DepList>;
|
|
26
|
+
rangeIndex: RangeIndex;
|
|
27
|
+
/**
|
|
28
|
+
* CellFormula id -> internal node index.
|
|
29
|
+
*/
|
|
30
|
+
cellFormulaToIndex: Map<CellId, CalcNodeIndex>;
|
|
31
|
+
/**
|
|
32
|
+
* OtherFormula id -> internal node index.
|
|
33
|
+
*/
|
|
34
|
+
otherFormulaToIndex: Map<ExternalNodeId, CalcNodeIndex>;
|
|
35
|
+
/**
|
|
36
|
+
* FeatureCalculation id -> internal node index.
|
|
37
|
+
*/
|
|
38
|
+
featureCalculationToIndex: Map<ExternalNodeId, CalcNodeIndex>;
|
|
39
|
+
/**
|
|
40
|
+
* Internal node index -> raw external id.
|
|
41
|
+
*/
|
|
42
|
+
indexToNodeId: ExternalNodeId[];
|
|
43
|
+
dirty: Uint8Array;
|
|
44
|
+
inQueue: Uint8Array;
|
|
45
|
+
private _indexToNodeType;
|
|
46
|
+
private _cellPrecedents;
|
|
47
|
+
private _rangePrecedents;
|
|
48
|
+
private _nodePrecedents;
|
|
49
|
+
private _dynamicDeps;
|
|
50
|
+
private _dynamicSignature;
|
|
51
|
+
private _runtimeDirectDeps;
|
|
52
|
+
private _runtimeNodeDeps;
|
|
53
|
+
private _runtimeRangeIndex;
|
|
54
|
+
private _runtimeCellPrecedents;
|
|
55
|
+
private _runtimeRangePrecedents;
|
|
56
|
+
private _runtimeNodePrecedents;
|
|
57
|
+
private _activeNode;
|
|
58
|
+
private _seenNodeEpoch;
|
|
59
|
+
private _visitNodeEpoch;
|
|
60
|
+
private _edgeSeenEpoch;
|
|
61
|
+
private _tarjanSeenEpoch;
|
|
62
|
+
private _tarjanIndexArr;
|
|
63
|
+
private _tarjanLowArr;
|
|
64
|
+
private _tarjanOnStack;
|
|
65
|
+
private _emitEpoch;
|
|
66
|
+
private _visitEpoch;
|
|
67
|
+
private _edgeEpoch;
|
|
68
|
+
private _tarjanEpoch;
|
|
69
|
+
private readonly _propQueue;
|
|
70
|
+
private readonly _dirtyList;
|
|
71
|
+
private _activeNodeCount;
|
|
72
|
+
private _dirtyNodeCount;
|
|
73
|
+
private _directPointIndex;
|
|
74
|
+
private _runtimeDirectPointIndex;
|
|
75
|
+
private _formulaCellIndex;
|
|
76
|
+
private _sharedFormulaGroups;
|
|
77
|
+
private _sharedFormulaGroupIndexById;
|
|
78
|
+
private _sharedFormulaMembershipByNode;
|
|
79
|
+
private _sharedFormulaSourceEntries;
|
|
80
|
+
private _sharedFormulaSourceRangeIndex;
|
|
81
|
+
constructor(options: IDependencyEngineOptions);
|
|
82
|
+
/**
|
|
83
|
+
* Clears all graph data and recreates large internal storage at the initial
|
|
84
|
+
* capacity so old arrays, maps, and indexes can be reclaimed by GC.
|
|
85
|
+
*/
|
|
86
|
+
reset(): void;
|
|
87
|
+
encodeCell(unitId: string, sheetId: string, row: number, col: number): CellId;
|
|
88
|
+
decodeCell(cell: CellId): IDecodedCell;
|
|
89
|
+
encodeFeatureCalculationId(unitId: string, sheetId: string, formulaId: string): string;
|
|
90
|
+
decodeFeatureCalculationId(id: ExternalNodeId): IDecodedFeatureCalculationId;
|
|
91
|
+
encodeOtherFormulaId(unitId: string, sheetId: string, formulaId: string, refOffsetX: number, refOffsetY: number): string;
|
|
92
|
+
decodeOtherFormulaId(id: ExternalNodeId): IDecodedOtherFormulaId;
|
|
93
|
+
setCellFormulaDeps(cell: CellId, deps: ICalcNodeDeps, options?: {
|
|
94
|
+
checkCycle?: boolean;
|
|
95
|
+
markDirty?: boolean;
|
|
96
|
+
mode?: 'replace' | 'merge';
|
|
97
|
+
}): ISetNodeResult;
|
|
98
|
+
setOtherFormulaDeps(id: ExternalNodeId, deps: ICalcNodeDeps, options?: {
|
|
99
|
+
checkCycle?: boolean;
|
|
100
|
+
markDirty?: boolean;
|
|
101
|
+
mode?: 'replace' | 'merge';
|
|
102
|
+
}): ISetNodeResult;
|
|
103
|
+
setFeatureCalculationDeps(id: ExternalNodeId, deps: ICalcNodeDeps, options?: {
|
|
104
|
+
checkCycle?: boolean;
|
|
105
|
+
markDirty?: boolean;
|
|
106
|
+
mode?: 'replace' | 'merge';
|
|
107
|
+
}): ISetNodeResult;
|
|
108
|
+
/**
|
|
109
|
+
* Adds or replaces dependencies for any calculation node type.
|
|
110
|
+
*/
|
|
111
|
+
setCalcNodeDeps(node: ICalcNodeRef, deps: ICalcNodeDeps, options?: {
|
|
112
|
+
checkCycle?: boolean;
|
|
113
|
+
markDirty?: boolean;
|
|
114
|
+
mode?: 'replace' | 'merge';
|
|
115
|
+
}): ISetNodeResult;
|
|
116
|
+
registerCompressedSharedFormulaGroup(groupInput: ICompressedSharedFormulaGroup): void;
|
|
117
|
+
unregisterCompressedSharedFormulaGroup(groupId: string): void;
|
|
118
|
+
clearCompressedSharedFormulaGroups(unitId?: string, sheetId?: string): void;
|
|
119
|
+
private _setCalcNodeDepsByType;
|
|
120
|
+
setManyCalcNodeDeps(changes: Array<{
|
|
121
|
+
node: ICalcNodeRef;
|
|
122
|
+
deps: ICalcNodeDeps;
|
|
123
|
+
}>, options?: {
|
|
124
|
+
checkCycle?: boolean;
|
|
125
|
+
markDirty?: boolean;
|
|
126
|
+
mode?: 'replace' | 'merge';
|
|
127
|
+
}): ISetNodeResult[];
|
|
128
|
+
setManyCellFormulaDeps(changes: Array<{
|
|
129
|
+
cell: CellId;
|
|
130
|
+
deps: ICalcNodeDeps;
|
|
131
|
+
}>, options?: {
|
|
132
|
+
checkCycle?: boolean;
|
|
133
|
+
markDirty?: boolean;
|
|
134
|
+
mode?: 'replace' | 'merge';
|
|
135
|
+
}): ISetNodeResult[];
|
|
136
|
+
setManyOtherFormulaDeps(changes: Array<{
|
|
137
|
+
id: ExternalNodeId;
|
|
138
|
+
deps: ICalcNodeDeps;
|
|
139
|
+
}>, options?: {
|
|
140
|
+
checkCycle?: boolean;
|
|
141
|
+
markDirty?: boolean;
|
|
142
|
+
mode?: 'replace' | 'merge';
|
|
143
|
+
}): ISetNodeResult[];
|
|
144
|
+
setManyFeatureCalculationDeps(changes: Array<{
|
|
145
|
+
id: ExternalNodeId;
|
|
146
|
+
deps: ICalcNodeDeps;
|
|
147
|
+
}>, options?: {
|
|
148
|
+
checkCycle?: boolean;
|
|
149
|
+
markDirty?: boolean;
|
|
150
|
+
mode?: 'replace' | 'merge';
|
|
151
|
+
}): ISetNodeResult[];
|
|
152
|
+
removeCellFormula(cell: CellId, options?: {
|
|
153
|
+
markDependentsDirty?: boolean;
|
|
154
|
+
}): void;
|
|
155
|
+
removeOtherFormula(id: ExternalNodeId, options?: {
|
|
156
|
+
markDependentsDirty?: boolean;
|
|
157
|
+
}): void;
|
|
158
|
+
removeFeatureCalculation(id: ExternalNodeId, options?: {
|
|
159
|
+
markDependentsDirty?: boolean;
|
|
160
|
+
detachDependents?: boolean;
|
|
161
|
+
}): void;
|
|
162
|
+
removeCellFormulas(cells: CellId[], options?: {
|
|
163
|
+
markDependentsDirty?: boolean;
|
|
164
|
+
}): void;
|
|
165
|
+
removeOtherFormulas(ids: ExternalNodeId[], options?: {
|
|
166
|
+
markDependentsDirty?: boolean;
|
|
167
|
+
}): void;
|
|
168
|
+
removeFeatureCalculations(ids: ExternalNodeId[], options?: {
|
|
169
|
+
markDependentsDirty?: boolean;
|
|
170
|
+
detachDependents?: boolean;
|
|
171
|
+
}): void;
|
|
172
|
+
removeCalcNodes(nodes: ICalcNodeRef[], options?: {
|
|
173
|
+
markDependentsDirty?: boolean;
|
|
174
|
+
detachDependents?: boolean;
|
|
175
|
+
}): void;
|
|
176
|
+
clearCellFormulas(unitId: string, sheetId?: string, options?: {
|
|
177
|
+
markDependentsDirty?: boolean;
|
|
178
|
+
}): void;
|
|
179
|
+
clearOtherFormulas(unitId: string, sheetId?: string, formulaIds?: string[], refOffsetX?: number, refOffsetY?: number, options?: {
|
|
180
|
+
markDependentsDirty?: boolean;
|
|
181
|
+
}): void;
|
|
182
|
+
private _includesFormulaId;
|
|
183
|
+
clearFeatureCalculations(unitId: string, sheetId?: string, options?: {
|
|
184
|
+
markDependentsDirty?: boolean;
|
|
185
|
+
detachDependents?: boolean;
|
|
186
|
+
}): void;
|
|
187
|
+
private _tryDecodeFeatureCalculationId;
|
|
188
|
+
private _tryDecodeOtherFormulaId;
|
|
189
|
+
private _removeCalcNodeIds;
|
|
190
|
+
private _removeCalcNodeIndices;
|
|
191
|
+
removeCalcNode(node: ICalcNodeRef, options?: {
|
|
192
|
+
markDependentsDirty?: boolean;
|
|
193
|
+
detachDependents?: boolean;
|
|
194
|
+
}): void;
|
|
195
|
+
private _removeCalcNodeByType;
|
|
196
|
+
private _removeCalcNodeByIndex;
|
|
197
|
+
/**
|
|
198
|
+
* Marks dependents of a changed value cell dirty. The changed cell itself
|
|
199
|
+
* is not marked unless it is reached as a dependent.
|
|
200
|
+
*/
|
|
201
|
+
markCellChanged(cell: CellId): void;
|
|
202
|
+
markCellsChanged(cells: Iterable<CellId>): void;
|
|
203
|
+
/**
|
|
204
|
+
* Marks dependents of a changed range dirty without expanding all cells.
|
|
205
|
+
*/
|
|
206
|
+
markRangeChanged(rangeInput: IRefRange, options?: {
|
|
207
|
+
includeFormulaCells?: boolean;
|
|
208
|
+
coalesce?: boolean;
|
|
209
|
+
}): void;
|
|
210
|
+
/**
|
|
211
|
+
* Batch range-change entry point for paste, fill, clear, and import.
|
|
212
|
+
*/
|
|
213
|
+
markRangesChanged(rangeInputs: IRefRange[], options?: {
|
|
214
|
+
includeFormulaCells?: boolean;
|
|
215
|
+
coalesce?: boolean;
|
|
216
|
+
}): void;
|
|
217
|
+
markCellFormulaChanged(cell: CellId): void;
|
|
218
|
+
markOtherFormulaChanged(id: ExternalNodeId): void;
|
|
219
|
+
markOtherFormulasChanged(unitId: string, sheetId?: string, formulaIds?: string[]): void;
|
|
220
|
+
markFeatureCalculationChanged(id: ExternalNodeId): void;
|
|
221
|
+
markCalcNodeChanged(node: ICalcNodeRef): void;
|
|
222
|
+
private _markCalcNodeChangedByType;
|
|
223
|
+
markCalcNodesChanged(nodes: ICalcNodeRef[]): void;
|
|
224
|
+
markAllDirty(): void;
|
|
225
|
+
hasDynamicDeps(node: ICalcNodeRef): boolean;
|
|
226
|
+
refreshDynamicDeps(node: ICalcNodeRef, resolver: IDynamicResolver): boolean;
|
|
227
|
+
prepareDynamicDependencies(resolver: IDynamicResolver): boolean;
|
|
228
|
+
/**
|
|
229
|
+
* Returns the current dirty-node calculation order without clearing dirty.
|
|
230
|
+
*/
|
|
231
|
+
getCalculationOrder(options?: {
|
|
232
|
+
detectCycles?: boolean;
|
|
233
|
+
}): ICalculationOrderResult;
|
|
234
|
+
clearCalculatedDirty(indices: CalcNodeIndex[]): void;
|
|
235
|
+
private _compactDirtyList;
|
|
236
|
+
clearAllDirty(): void;
|
|
237
|
+
getDirtyNodeIndices(): CalcNodeIndex[];
|
|
238
|
+
getDirtyNodes(): ICalcNodeRef[];
|
|
239
|
+
forEachDependentByCell(cell: CellId, cb: (node: ICalcNodeRef, nodeIndex: CalcNodeIndex) => void): void;
|
|
240
|
+
forEachDependentByRange(range: IRefRange, cb: (node: ICalcNodeRef, nodeIndex: CalcNodeIndex) => void): void;
|
|
241
|
+
forEachDependentByNode(node: ICalcNodeRef, cb: (dependentNode: ICalcNodeRef, dependentIndex: CalcNodeIndex) => void): void;
|
|
242
|
+
forEachDependentByIndex(nodeIndex: CalcNodeIndex, cb: (dependentNode: ICalcNodeRef, dependentIndex: CalcNodeIndex) => void): void;
|
|
243
|
+
/**
|
|
244
|
+
* Diagnostic query for precedent calculation nodes of one node.
|
|
245
|
+
*/
|
|
246
|
+
forEachPrecedentNode(node: ICalcNodeRef, cb: (precedentNode: ICalcNodeRef, precedentIndex: CalcNodeIndex) => void): void;
|
|
247
|
+
forEachPrecedentNodeByIndex(nodeIndex: CalcNodeIndex, cb: (precedentNode: ICalcNodeRef, precedentIndex: CalcNodeIndex) => void): void;
|
|
248
|
+
hasUncalculatedDirtyPrecedentByIndex(nodeIndex: CalcNodeIndex, calculatedNodeIndices: ReadonlySet<CalcNodeIndex>): boolean;
|
|
249
|
+
wouldCreateCycle(node: ICalcNodeRef, deps: ICalcNodeDeps): boolean;
|
|
250
|
+
private _normalizeCalcNodeDeps;
|
|
251
|
+
private _collectStaticDeps;
|
|
252
|
+
private _mergeDynamicDeps;
|
|
253
|
+
private _setNodeDynamicDeps;
|
|
254
|
+
private _isSameDynamicDeps;
|
|
255
|
+
private _normalizeRangeDeps;
|
|
256
|
+
private _mergeSortedUniqueNumbers;
|
|
257
|
+
private _mergeRangeDeps;
|
|
258
|
+
private _containsRange;
|
|
259
|
+
private _isSameRange;
|
|
260
|
+
/**
|
|
261
|
+
* Checks reachability through the dependent graph.
|
|
262
|
+
*/
|
|
263
|
+
canReachNode(startNode: ICalcNodeRef, targetNode: ICalcNodeRef): boolean;
|
|
264
|
+
hasCellFormula(cell: CellId): boolean;
|
|
265
|
+
hasOtherFormula(id: ExternalNodeId): boolean;
|
|
266
|
+
hasFeatureCalculation(id: ExternalNodeId): boolean;
|
|
267
|
+
getNodeIndex(node: ICalcNodeRef): CalcNodeIndex | undefined;
|
|
268
|
+
private _getNodeIndexByType;
|
|
269
|
+
getNodeRefByIndex(nodeIndex: CalcNodeIndex): ICalcNodeRef;
|
|
270
|
+
markCalcNodeIndicesChanged(indices: CalcNodeIndex[], options?: {
|
|
271
|
+
onlySelf?: boolean;
|
|
272
|
+
}): void;
|
|
273
|
+
private _markCalcNodeIndicesChanged;
|
|
274
|
+
private _getOrCreateNodeIndex;
|
|
275
|
+
private _getOrCreateNodeIndexByType;
|
|
276
|
+
private _ensureNodeCapacity;
|
|
277
|
+
private _growIntThirtyTwoArray;
|
|
278
|
+
private _resolveExplicitNodeDeps;
|
|
279
|
+
private _isEmptyCalcNodeDeps;
|
|
280
|
+
private _unregisterCompressedSharedFormulaGroupByNode;
|
|
281
|
+
private _markCompressedSharedFormulaMembership;
|
|
282
|
+
private _clearCompressedSharedFormulaMembership;
|
|
283
|
+
private _getCompressedSharedSourceCoverage;
|
|
284
|
+
private _forEachCompressedSharedDependentByRange;
|
|
285
|
+
private _forEachActiveCellFormulaInRange;
|
|
286
|
+
private _reverseMapCompressedSharedPattern;
|
|
287
|
+
private _intersectRanges;
|
|
288
|
+
private _forEachCompressedSharedPrecedent;
|
|
289
|
+
private _getCompressedSharedPrecedentCell;
|
|
290
|
+
private _getCompressedSharedPrecedentRange;
|
|
291
|
+
private _addNodeDepsOnly;
|
|
292
|
+
private _removeNodeDepsOnly;
|
|
293
|
+
private _collectDynamicResolveResult;
|
|
294
|
+
private _addRuntimeDepsOnly;
|
|
295
|
+
private _removeRuntimeDepsOnly;
|
|
296
|
+
private _detachDependentsFromNode;
|
|
297
|
+
private _detachPrecedentFromDependent;
|
|
298
|
+
private _detachRuntimePrecedentFromDependent;
|
|
299
|
+
private _addDirectEdge;
|
|
300
|
+
private _removeDirectEdge;
|
|
301
|
+
private _addRuntimeDirectEdge;
|
|
302
|
+
private _removeRuntimeDirectEdge;
|
|
303
|
+
private _addExplicitNodeEdge;
|
|
304
|
+
private _removeExplicitNodeEdge;
|
|
305
|
+
private _addRuntimeExplicitNodeEdge;
|
|
306
|
+
private _removeRuntimeExplicitNodeEdge;
|
|
307
|
+
private _forEachDependentIndexByCellRaw;
|
|
308
|
+
private _forEachDependentOfNodeRaw;
|
|
309
|
+
private _markNodeIndexDirty;
|
|
310
|
+
private _isEveryActiveNodeDirty;
|
|
311
|
+
private _propagateDirtyQueue;
|
|
312
|
+
private _getDirtyNodeIndicesSnapshot;
|
|
313
|
+
private _forEachDependentOfNodeDeduped;
|
|
314
|
+
private _forEachPrecedentNodeIndex;
|
|
315
|
+
private _wouldCreateCycleForNewDeps;
|
|
316
|
+
private _canReachNodeIndex;
|
|
317
|
+
private _buildDirtyCalculationGraph;
|
|
318
|
+
private _tryBuildAcyclicDirtyCalculationGraph;
|
|
319
|
+
private _addAcyclicExactPrecedentEdges;
|
|
320
|
+
private _addAcyclicRangePrecedentGroups;
|
|
321
|
+
private _getOrCreateAcyclicRangeGroup;
|
|
322
|
+
private _appendAcyclicCalculationNode;
|
|
323
|
+
private _getCurrentDirtyOrdinal;
|
|
324
|
+
private _buildDirtyCalculationGraphWithScc;
|
|
325
|
+
private _toposortComponents;
|
|
326
|
+
private _insertComponentByRank;
|
|
327
|
+
private _buildCalculationForest;
|
|
328
|
+
private _appendCalculationNodePlanItem;
|
|
329
|
+
private _findCalculationForestRoot;
|
|
330
|
+
private _unionCalculationForestComponents;
|
|
331
|
+
private _createCalculationPlanItem;
|
|
332
|
+
private _getDirtySccEnd;
|
|
333
|
+
private _findDirtySccs;
|
|
334
|
+
private _hasSelfLoop;
|
|
335
|
+
private _nextEmitEpoch;
|
|
336
|
+
private _emitNodeOnce;
|
|
337
|
+
private _emitNodeOnceAndMarkDirty;
|
|
338
|
+
private _nextVisitEpoch;
|
|
339
|
+
private _nextEdgeEpoch;
|
|
340
|
+
private _nextTarjanEpoch;
|
|
341
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CellCodec } from './cell-codec';
|
|
2
|
+
import type { CalcNodeIndex, ExternalNodeId, IRefRange } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Spatial index for active `CellFormula` nodes.
|
|
5
|
+
*
|
|
6
|
+
* Range precedents use this index to discover formula cells inside a range
|
|
7
|
+
* for topological ordering, cycle checks, and `includeFormulaCells` dirty
|
|
8
|
+
* marking.
|
|
9
|
+
*/
|
|
10
|
+
export declare class FormulaCellIndex {
|
|
11
|
+
private readonly _codec;
|
|
12
|
+
private readonly _indexToNodeId;
|
|
13
|
+
private readonly _rowBuckets;
|
|
14
|
+
private readonly _colBuckets;
|
|
15
|
+
constructor(_codec: CellCodec, _indexToNodeId: ExternalNodeId[]);
|
|
16
|
+
addFormulaCell(formulaCell: number, nodeIndex: CalcNodeIndex): void;
|
|
17
|
+
removeFormulaCell(formulaCell: number, nodeIndex: CalcNodeIndex): void;
|
|
18
|
+
forEachFormulaInRange(rangeInput: IRefRange, cb: (nodeIndex: CalcNodeIndex) => boolean | void): boolean;
|
|
19
|
+
private _scanRows;
|
|
20
|
+
private _scanCols;
|
|
21
|
+
private _scanRowBucket;
|
|
22
|
+
private _scanColBucket;
|
|
23
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CalcNodeIndex, DepList, ExternalNodeId, ICalcNodeRef, IDecodedCell, IRefRange } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Shared low-level helpers for dependency storage.
|
|
4
|
+
*
|
|
5
|
+
* These utilities are intentionally small and allocation-aware because the
|
|
6
|
+
* dependency engine calls them in hot paths such as paste, fill, and dirty
|
|
7
|
+
* propagation.
|
|
8
|
+
*/
|
|
9
|
+
export declare function assertCellNodeId(id: ExternalNodeId): asserts id is number;
|
|
10
|
+
export declare function normalizeRange(r: IRefRange): IRefRange;
|
|
11
|
+
export declare function rangeRowCount(r: IRefRange): number;
|
|
12
|
+
export declare function rangeColCount(r: IRefRange): number;
|
|
13
|
+
export declare function rangeContainsCell(r: IRefRange, d: IDecodedCell): boolean;
|
|
14
|
+
export declare function uniqueSortedNumbers(values: readonly number[] | undefined): number[];
|
|
15
|
+
export declare function pushToArrayMap<K>(map: Map<K, number[]>, key: K, value: number): void;
|
|
16
|
+
export declare function removeFromArraySwap(arr: number[], value: number): boolean;
|
|
17
|
+
export declare function removeFromArrayMap<K>(map: Map<K, number[]>, key: K, value: number): void;
|
|
18
|
+
export declare function depListAdd(list: DepList | undefined, value: CalcNodeIndex): DepList;
|
|
19
|
+
export declare function depListRemove(list: DepList | undefined, value: CalcNodeIndex): DepList | undefined;
|
|
20
|
+
export declare function forEachDepList(list: DepList | undefined, cb: (nodeIndex: CalcNodeIndex) => void): void;
|
|
21
|
+
export declare function addToDepMap<K>(map: Map<K, DepList>, key: K, nodeIndex: CalcNodeIndex): void;
|
|
22
|
+
export declare function removeFromDepMap<K>(map: Map<K, DepList>, key: K, nodeIndex: CalcNodeIndex): void;
|
|
23
|
+
export declare function growUintEightArray(oldArr: Uint8Array, minCapacity: number): Uint8Array;
|
|
24
|
+
export declare function growUintThirtyTwoArray(oldArr: Uint32Array, minCapacity: number): Uint32Array;
|
|
25
|
+
export declare function uniqueNodeRefs(values: readonly ICalcNodeRef[] | undefined): ICalcNodeRef[];
|
|
26
|
+
/**
|
|
27
|
+
* Coalesce only ranges with the same row span or the same column span.
|
|
28
|
+
*
|
|
29
|
+
* We do not merge L-shaped areas into a larger rectangle because that would
|
|
30
|
+
* create too many false-positive dependents.
|
|
31
|
+
*/
|
|
32
|
+
export declare function coalesceAlignedRanges(rangeInputs: IRefRange[]): IRefRange[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CellId, ExternalNodeId, ICalcNodeRef } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Public helpers for creating calculation node references.
|
|
4
|
+
*/
|
|
5
|
+
export declare function cellFormulaNode(cell: CellId): ICalcNodeRef;
|
|
6
|
+
export declare function otherFormulaNode(id: ExternalNodeId): ICalcNodeRef;
|
|
7
|
+
export declare function featureCalculationNode(id: ExternalNodeId): ICalcNodeRef;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CellCodec } from './cell-codec';
|
|
2
|
+
import type { CellId, IRefRange } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Index of direct precedent cells subscribed by formula dependencies.
|
|
5
|
+
*
|
|
6
|
+
* It is used when a changed range needs to find only the direct precedent
|
|
7
|
+
* cells that are actually subscribed, without keeping a full sheet-sized cell
|
|
8
|
+
* index.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PointSubscriptionIndex {
|
|
11
|
+
private readonly _codec;
|
|
12
|
+
private readonly _pointScanCellLimit;
|
|
13
|
+
private readonly _rowCells;
|
|
14
|
+
private readonly _colCells;
|
|
15
|
+
constructor(_codec: CellCodec, _pointScanCellLimit: number);
|
|
16
|
+
add(cell: CellId): void;
|
|
17
|
+
remove(cell: CellId): void;
|
|
18
|
+
forEachCellInRange(rangeInput: IRefRange, cb: (cell: CellId) => void): void;
|
|
19
|
+
private _isSmallArea;
|
|
20
|
+
private _scanRows;
|
|
21
|
+
private _scanCols;
|
|
22
|
+
private _scanRowBucket;
|
|
23
|
+
private _scanColBucket;
|
|
24
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { CellCodec } from './cell-codec';
|
|
2
|
+
import type { CalcNodeIndex, IRefRange } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Reverse index from precedent ranges to dependent calculation nodes.
|
|
5
|
+
*
|
|
6
|
+
* The index does not expand ranges into cells. Whole rows / columns / sheets
|
|
7
|
+
* are stored in dedicated maps, normal ranges are indexed by their shorter
|
|
8
|
+
* side, and very large ranges use a fallback list.
|
|
9
|
+
*/
|
|
10
|
+
export declare class RangeIndex {
|
|
11
|
+
private readonly _codec;
|
|
12
|
+
private readonly _maxIndexedSpan;
|
|
13
|
+
private readonly _wholeSheet;
|
|
14
|
+
private readonly _wholeCol;
|
|
15
|
+
private readonly _wholeRow;
|
|
16
|
+
/**
|
|
17
|
+
* Normal ranges enter either row buckets or column buckets, never both.
|
|
18
|
+
*/
|
|
19
|
+
private readonly _rowBuckets;
|
|
20
|
+
private readonly _colBuckets;
|
|
21
|
+
private readonly _largeRangeIds;
|
|
22
|
+
private _sheetArr;
|
|
23
|
+
private _startRowArr;
|
|
24
|
+
private _endRowArr;
|
|
25
|
+
private _startColArr;
|
|
26
|
+
private _endColArr;
|
|
27
|
+
private _nodeArr;
|
|
28
|
+
private _kindArr;
|
|
29
|
+
private _activeArr;
|
|
30
|
+
private _rangeSeenEpochArr;
|
|
31
|
+
private _rangeEpoch;
|
|
32
|
+
private _nextRangeId;
|
|
33
|
+
private readonly _freeRangeIds;
|
|
34
|
+
private readonly _nodeToRangeIds;
|
|
35
|
+
private readonly _nodeToWholeSheetKeys;
|
|
36
|
+
private readonly _nodeToWholeColKeys;
|
|
37
|
+
private readonly _nodeToWholeRowKeys;
|
|
38
|
+
constructor(_codec: CellCodec, initialCapacity: number, _maxIndexedSpan: number);
|
|
39
|
+
addRange(nodeIndex: CalcNodeIndex, rangeInput: IRefRange): void;
|
|
40
|
+
removeNode(nodeIndex: CalcNodeIndex): void;
|
|
41
|
+
/**
|
|
42
|
+
* Finds range-dependent nodes when one cell changes.
|
|
43
|
+
*/
|
|
44
|
+
forEachPoint(unitId: string, sheetId: string, row: number, col: number, cb: (nodeIndex: CalcNodeIndex) => void): void;
|
|
45
|
+
forEachRangeIntersecting(changedInput: IRefRange, cb: (nodeIndex: CalcNodeIndex) => void): void;
|
|
46
|
+
/**
|
|
47
|
+
* Finds range-dependent nodes intersecting a batch of changed ranges.
|
|
48
|
+
*
|
|
49
|
+
* A single range epoch deduplicates normal range IDs across the batch.
|
|
50
|
+
*/
|
|
51
|
+
forEachRangesIntersecting(changedInputs: IRefRange[], cb: (nodeIndex: CalcNodeIndex) => void): void;
|
|
52
|
+
private _allocRangeId;
|
|
53
|
+
private _ensureRangeCapacity;
|
|
54
|
+
private _setRangeMeta;
|
|
55
|
+
private _removeRangeId;
|
|
56
|
+
private _nextRangeEpoch;
|
|
57
|
+
private _wasRangeSeen;
|
|
58
|
+
private _markRangeSeen;
|
|
59
|
+
private _scanWholeCols;
|
|
60
|
+
private _scanWholeRows;
|
|
61
|
+
private _scanRowIndexedRanges;
|
|
62
|
+
private _scanColIndexedRanges;
|
|
63
|
+
private _scanRangeIdBucket;
|
|
64
|
+
private _rangeContainsPoint;
|
|
65
|
+
private _rangeIntersectsInput;
|
|
66
|
+
}
|