@bilig/core 0.1.33 → 0.1.35
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/engine/services/formula-binding-service.d.ts +2 -2
- package/dist/engine/services/formula-binding-service.js +33 -4
- package/dist/engine/services/formula-binding-service.js.map +1 -1
- package/dist/engine/services/formula-evaluation-service.js +244 -3
- package/dist/engine/services/formula-evaluation-service.js.map +1 -1
- package/dist/engine/services/lookup-service.d.ts +52 -0
- package/dist/engine/services/lookup-service.js +426 -4
- package/dist/engine/services/lookup-service.js.map +1 -1
- package/dist/engine/services/mutation-history-fast-path.d.ts +2 -1
- package/dist/engine/services/mutation-history-fast-path.js +10 -8
- package/dist/engine/services/mutation-history-fast-path.js.map +1 -1
- package/dist/engine/services/mutation-service.d.ts +8 -1
- package/dist/engine/services/mutation-service.js +48 -8
- package/dist/engine/services/mutation-service.js.map +1 -1
- package/dist/engine/services/operation-service.d.ts +1 -1
- package/dist/engine/services/operation-service.js +4 -4
- package/dist/engine/services/operation-service.js.map +1 -1
- package/dist/engine.d.ts +2 -0
- package/dist/engine.js +6 -4
- package/dist/engine.js.map +1 -1
- package/dist/literal-sheet-loader.d.ts +1 -1
- package/dist/literal-sheet-loader.js +9 -6
- package/dist/literal-sheet-loader.js.map +1 -1
- package/dist/scheduler.js +21 -0
- package/dist/scheduler.js.map +1 -1
- package/package.json +5 -5
|
@@ -29,6 +29,36 @@ export type ExactVectorMatchResult = {
|
|
|
29
29
|
position: number | undefined;
|
|
30
30
|
};
|
|
31
31
|
export type ApproximateVectorMatchResult = ExactVectorMatchResult;
|
|
32
|
+
export interface PreparedExactVectorLookup {
|
|
33
|
+
sheetName: string;
|
|
34
|
+
rowStart: number;
|
|
35
|
+
rowEnd: number;
|
|
36
|
+
col: number;
|
|
37
|
+
columnVersion: number;
|
|
38
|
+
comparableKind: "numeric" | "text" | "mixed";
|
|
39
|
+
uniformStart: number | undefined;
|
|
40
|
+
uniformStep: number | undefined;
|
|
41
|
+
firstPositions: Map<string, number>;
|
|
42
|
+
lastPositions: Map<string, number>;
|
|
43
|
+
firstNumericPositions: Map<number, number> | undefined;
|
|
44
|
+
lastNumericPositions: Map<number, number> | undefined;
|
|
45
|
+
firstTextPositions: Map<string, number> | undefined;
|
|
46
|
+
lastTextPositions: Map<string, number> | undefined;
|
|
47
|
+
}
|
|
48
|
+
export interface PreparedApproximateVectorLookup {
|
|
49
|
+
sheetName: string;
|
|
50
|
+
rowStart: number;
|
|
51
|
+
rowEnd: number;
|
|
52
|
+
col: number;
|
|
53
|
+
columnVersion: number;
|
|
54
|
+
comparableKind: "numeric" | "text" | undefined;
|
|
55
|
+
uniformStart: number | undefined;
|
|
56
|
+
uniformStep: number | undefined;
|
|
57
|
+
sortedAscending: boolean;
|
|
58
|
+
sortedDescending: boolean;
|
|
59
|
+
numericValues: Float64Array | undefined;
|
|
60
|
+
textValues: string[] | undefined;
|
|
61
|
+
}
|
|
32
62
|
export interface EngineLookupService {
|
|
33
63
|
readonly findExactVectorMatch: (request: ExactVectorMatchRequest) => ExactVectorMatchResult;
|
|
34
64
|
readonly findApproximateVectorMatch: (request: ApproximateVectorMatchRequest) => ApproximateVectorMatchResult;
|
|
@@ -44,6 +74,28 @@ export interface EngineLookupService {
|
|
|
44
74
|
rowEnd: number;
|
|
45
75
|
col: number;
|
|
46
76
|
}) => void;
|
|
77
|
+
readonly prepareExactVectorLookup: (request: {
|
|
78
|
+
sheetName: string;
|
|
79
|
+
rowStart: number;
|
|
80
|
+
rowEnd: number;
|
|
81
|
+
col: number;
|
|
82
|
+
}) => PreparedExactVectorLookup;
|
|
83
|
+
readonly findPreparedExactVectorMatch: (request: {
|
|
84
|
+
lookupValue: CellValue;
|
|
85
|
+
prepared: PreparedExactVectorLookup;
|
|
86
|
+
searchMode: 1 | -1;
|
|
87
|
+
}) => ExactVectorMatchResult;
|
|
88
|
+
readonly prepareApproximateVectorLookup: (request: {
|
|
89
|
+
sheetName: string;
|
|
90
|
+
rowStart: number;
|
|
91
|
+
rowEnd: number;
|
|
92
|
+
col: number;
|
|
93
|
+
}) => PreparedApproximateVectorLookup;
|
|
94
|
+
readonly findPreparedApproximateVectorMatch: (request: {
|
|
95
|
+
lookupValue: CellValue;
|
|
96
|
+
prepared: PreparedApproximateVectorLookup;
|
|
97
|
+
matchMode: 1 | -1;
|
|
98
|
+
}) => ApproximateVectorMatchResult;
|
|
47
99
|
}
|
|
48
100
|
export declare function createEngineLookupService(args: {
|
|
49
101
|
readonly state: Pick<EngineRuntimeState, "workbook" | "strings">;
|
|
@@ -34,6 +34,11 @@ function normalizeApproximateComparableValue(value, lookupString, stringId = 0)
|
|
|
34
34
|
return { kind: "invalid" };
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function normalizeLookupText(value, lookupString) {
|
|
38
|
+
return (value.stringId !== undefined && value.stringId !== 0
|
|
39
|
+
? lookupString(value.stringId)
|
|
40
|
+
: value.value).toUpperCase();
|
|
41
|
+
}
|
|
37
42
|
function compareApproximateNumeric(left, right) {
|
|
38
43
|
if (left === right) {
|
|
39
44
|
return 0;
|
|
@@ -46,6 +51,22 @@ function compareApproximateText(left, right) {
|
|
|
46
51
|
}
|
|
47
52
|
return left < right ? -1 : 1;
|
|
48
53
|
}
|
|
54
|
+
function detectUniformNumericStep(values) {
|
|
55
|
+
if (values.length < 2) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const start = values[0];
|
|
59
|
+
const step = values[1] - start;
|
|
60
|
+
if (!Number.isFinite(step) || step === 0) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
for (let index = 2; index < values.length; index += 1) {
|
|
64
|
+
if (values[index] - values[index - 1] !== step) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { start, step };
|
|
69
|
+
}
|
|
49
70
|
export function createEngineLookupService(args) {
|
|
50
71
|
const exactColumnIndices = new Map();
|
|
51
72
|
const approximateColumnIndices = new Map();
|
|
@@ -88,6 +109,14 @@ export function createEngineLookupService(args) {
|
|
|
88
109
|
const buildExactColumnIndex = (sheetName, col, rowStart, rowEnd) => {
|
|
89
110
|
const firstPositions = new Map();
|
|
90
111
|
const lastPositions = new Map();
|
|
112
|
+
const firstNumericPositions = new Map();
|
|
113
|
+
const lastNumericPositions = new Map();
|
|
114
|
+
const firstTextPositions = new Map();
|
|
115
|
+
const lastTextPositions = new Map();
|
|
116
|
+
const numericSequence = [];
|
|
117
|
+
let sawNumeric = false;
|
|
118
|
+
let sawText = false;
|
|
119
|
+
let sawOther = false;
|
|
91
120
|
for (let row = rowStart; row <= rowEnd; row += 1) {
|
|
92
121
|
const key = readNormalizedKeyAt(sheetName, row, col);
|
|
93
122
|
if (key === undefined) {
|
|
@@ -97,11 +126,48 @@ export function createEngineLookupService(args) {
|
|
|
97
126
|
firstPositions.set(key, row);
|
|
98
127
|
}
|
|
99
128
|
lastPositions.set(key, row);
|
|
129
|
+
if (key.startsWith("n:")) {
|
|
130
|
+
const numericValue = Number(key.slice(2));
|
|
131
|
+
if (!firstNumericPositions.has(numericValue)) {
|
|
132
|
+
firstNumericPositions.set(numericValue, row);
|
|
133
|
+
}
|
|
134
|
+
lastNumericPositions.set(numericValue, row);
|
|
135
|
+
numericSequence.push(numericValue);
|
|
136
|
+
sawNumeric = true;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (key.startsWith("s:")) {
|
|
140
|
+
const textValue = key.slice(2);
|
|
141
|
+
if (!firstTextPositions.has(textValue)) {
|
|
142
|
+
firstTextPositions.set(textValue, row);
|
|
143
|
+
}
|
|
144
|
+
lastTextPositions.set(textValue, row);
|
|
145
|
+
sawText = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
sawOther = true;
|
|
100
149
|
}
|
|
150
|
+
const comparableKind = sawOther || (sawNumeric && sawText)
|
|
151
|
+
? "mixed"
|
|
152
|
+
: sawNumeric
|
|
153
|
+
? "numeric"
|
|
154
|
+
: sawText
|
|
155
|
+
? "text"
|
|
156
|
+
: "mixed";
|
|
157
|
+
const uniformNumericStep = comparableKind === "numeric"
|
|
158
|
+
? detectUniformNumericStep(Float64Array.from(numericSequence))
|
|
159
|
+
: undefined;
|
|
101
160
|
return {
|
|
102
161
|
columnVersion: args.state.workbook.getSheetColumnVersion(sheetName, col),
|
|
162
|
+
comparableKind,
|
|
163
|
+
uniformStart: uniformNumericStep?.start,
|
|
164
|
+
uniformStep: uniformNumericStep?.step,
|
|
103
165
|
firstPositions,
|
|
104
166
|
lastPositions,
|
|
167
|
+
firstNumericPositions: comparableKind === "numeric" ? firstNumericPositions : undefined,
|
|
168
|
+
lastNumericPositions: comparableKind === "numeric" ? lastNumericPositions : undefined,
|
|
169
|
+
firstTextPositions: comparableKind === "text" ? firstTextPositions : undefined,
|
|
170
|
+
lastTextPositions: comparableKind === "text" ? lastTextPositions : undefined,
|
|
105
171
|
};
|
|
106
172
|
};
|
|
107
173
|
const buildApproximateColumnIndex = (sheetName, col, rowStart, rowEnd) => {
|
|
@@ -161,8 +227,12 @@ export function createEngineLookupService(args) {
|
|
|
161
227
|
return {
|
|
162
228
|
columnVersion: args.state.workbook.getSheetColumnVersion(sheetName, col),
|
|
163
229
|
comparableKind: undefined,
|
|
230
|
+
uniformStart: undefined,
|
|
231
|
+
uniformStep: undefined,
|
|
164
232
|
sortedAscending: false,
|
|
165
233
|
sortedDescending: false,
|
|
234
|
+
numericValues: undefined,
|
|
235
|
+
textValues: undefined,
|
|
166
236
|
};
|
|
167
237
|
}
|
|
168
238
|
if (hasText) {
|
|
@@ -181,8 +251,11 @@ export function createEngineLookupService(args) {
|
|
|
181
251
|
return {
|
|
182
252
|
columnVersion: args.state.workbook.getSheetColumnVersion(sheetName, col),
|
|
183
253
|
comparableKind: "text",
|
|
254
|
+
uniformStart: undefined,
|
|
255
|
+
uniformStep: undefined,
|
|
184
256
|
sortedAscending,
|
|
185
257
|
sortedDescending,
|
|
258
|
+
numericValues: undefined,
|
|
186
259
|
textValues,
|
|
187
260
|
};
|
|
188
261
|
}
|
|
@@ -198,12 +271,16 @@ export function createEngineLookupService(args) {
|
|
|
198
271
|
sortedDescending = false;
|
|
199
272
|
}
|
|
200
273
|
}
|
|
274
|
+
const uniformNumericStep = detectUniformNumericStep(numericValues);
|
|
201
275
|
return {
|
|
202
276
|
columnVersion: args.state.workbook.getSheetColumnVersion(sheetName, col),
|
|
203
277
|
comparableKind: "numeric",
|
|
278
|
+
uniformStart: uniformNumericStep?.start,
|
|
279
|
+
uniformStep: uniformNumericStep?.step,
|
|
204
280
|
sortedAscending,
|
|
205
281
|
sortedDescending,
|
|
206
282
|
numericValues,
|
|
283
|
+
textValues: undefined,
|
|
207
284
|
};
|
|
208
285
|
};
|
|
209
286
|
const resolveExactColumnBounds = (request) => {
|
|
@@ -250,6 +327,76 @@ export function createEngineLookupService(args) {
|
|
|
250
327
|
}
|
|
251
328
|
return entry;
|
|
252
329
|
};
|
|
330
|
+
const prepareExactVectorLookup = (request) => {
|
|
331
|
+
const entry = ensureExactColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
|
|
332
|
+
return {
|
|
333
|
+
sheetName: request.sheetName,
|
|
334
|
+
rowStart: request.rowStart,
|
|
335
|
+
rowEnd: request.rowEnd,
|
|
336
|
+
col: request.col,
|
|
337
|
+
columnVersion: entry.columnVersion,
|
|
338
|
+
comparableKind: entry.comparableKind,
|
|
339
|
+
uniformStart: entry.uniformStart,
|
|
340
|
+
uniformStep: entry.uniformStep,
|
|
341
|
+
firstPositions: entry.firstPositions,
|
|
342
|
+
lastPositions: entry.lastPositions,
|
|
343
|
+
firstNumericPositions: entry.firstNumericPositions,
|
|
344
|
+
lastNumericPositions: entry.lastNumericPositions,
|
|
345
|
+
firstTextPositions: entry.firstTextPositions,
|
|
346
|
+
lastTextPositions: entry.lastTextPositions,
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
const prepareApproximateVectorLookup = (request) => {
|
|
350
|
+
const entry = ensureApproximateColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
|
|
351
|
+
return {
|
|
352
|
+
sheetName: request.sheetName,
|
|
353
|
+
rowStart: request.rowStart,
|
|
354
|
+
rowEnd: request.rowEnd,
|
|
355
|
+
col: request.col,
|
|
356
|
+
columnVersion: entry.columnVersion,
|
|
357
|
+
comparableKind: entry.comparableKind,
|
|
358
|
+
uniformStart: entry.uniformStart,
|
|
359
|
+
uniformStep: entry.uniformStep,
|
|
360
|
+
sortedAscending: entry.sortedAscending,
|
|
361
|
+
sortedDescending: entry.sortedDescending,
|
|
362
|
+
numericValues: entry.numericValues,
|
|
363
|
+
textValues: entry.textValues,
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
const refreshPreparedExactVectorLookup = (prepared) => {
|
|
367
|
+
const columnVersion = args.state.workbook.getSheetColumnVersion(prepared.sheetName, prepared.col);
|
|
368
|
+
if (columnVersion === prepared.columnVersion) {
|
|
369
|
+
return prepared;
|
|
370
|
+
}
|
|
371
|
+
const refreshed = prepareExactVectorLookup(prepared);
|
|
372
|
+
prepared.columnVersion = refreshed.columnVersion;
|
|
373
|
+
prepared.comparableKind = refreshed.comparableKind;
|
|
374
|
+
prepared.uniformStart = refreshed.uniformStart;
|
|
375
|
+
prepared.uniformStep = refreshed.uniformStep;
|
|
376
|
+
prepared.firstPositions = refreshed.firstPositions;
|
|
377
|
+
prepared.lastPositions = refreshed.lastPositions;
|
|
378
|
+
prepared.firstNumericPositions = refreshed.firstNumericPositions;
|
|
379
|
+
prepared.lastNumericPositions = refreshed.lastNumericPositions;
|
|
380
|
+
prepared.firstTextPositions = refreshed.firstTextPositions;
|
|
381
|
+
prepared.lastTextPositions = refreshed.lastTextPositions;
|
|
382
|
+
return prepared;
|
|
383
|
+
};
|
|
384
|
+
const refreshPreparedApproximateVectorLookup = (prepared) => {
|
|
385
|
+
const columnVersion = args.state.workbook.getSheetColumnVersion(prepared.sheetName, prepared.col);
|
|
386
|
+
if (columnVersion === prepared.columnVersion) {
|
|
387
|
+
return prepared;
|
|
388
|
+
}
|
|
389
|
+
const refreshed = prepareApproximateVectorLookup(prepared);
|
|
390
|
+
prepared.columnVersion = refreshed.columnVersion;
|
|
391
|
+
prepared.comparableKind = refreshed.comparableKind;
|
|
392
|
+
prepared.uniformStart = refreshed.uniformStart;
|
|
393
|
+
prepared.uniformStep = refreshed.uniformStep;
|
|
394
|
+
prepared.sortedAscending = refreshed.sortedAscending;
|
|
395
|
+
prepared.sortedDescending = refreshed.sortedDescending;
|
|
396
|
+
prepared.numericValues = refreshed.numericValues;
|
|
397
|
+
prepared.textValues = refreshed.textValues;
|
|
398
|
+
return prepared;
|
|
399
|
+
};
|
|
253
400
|
return {
|
|
254
401
|
primeExactColumnIndex(request) {
|
|
255
402
|
ensureExactColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
|
|
@@ -257,6 +404,202 @@ export function createEngineLookupService(args) {
|
|
|
257
404
|
primeApproximateColumnIndex(request) {
|
|
258
405
|
ensureApproximateColumnIndex(request.sheetName, request.col, request.rowStart, request.rowEnd);
|
|
259
406
|
},
|
|
407
|
+
prepareExactVectorLookup(request) {
|
|
408
|
+
return prepareExactVectorLookup(request);
|
|
409
|
+
},
|
|
410
|
+
findPreparedExactVectorMatch(request) {
|
|
411
|
+
const prepared = refreshPreparedExactVectorLookup(request.prepared);
|
|
412
|
+
if (prepared.comparableKind === "numeric") {
|
|
413
|
+
if (request.lookupValue.tag === ValueTag.Error) {
|
|
414
|
+
return { handled: false };
|
|
415
|
+
}
|
|
416
|
+
if (request.lookupValue.tag !== ValueTag.Number) {
|
|
417
|
+
return { handled: true, position: undefined };
|
|
418
|
+
}
|
|
419
|
+
const numericValue = Object.is(request.lookupValue.value, -0)
|
|
420
|
+
? 0
|
|
421
|
+
: request.lookupValue.value;
|
|
422
|
+
if (prepared.uniformStart !== undefined && prepared.uniformStep !== undefined) {
|
|
423
|
+
const relative = (numericValue - prepared.uniformStart) / prepared.uniformStep;
|
|
424
|
+
const position = Number.isInteger(relative) ? relative + 1 : undefined;
|
|
425
|
+
return {
|
|
426
|
+
handled: true,
|
|
427
|
+
position: position !== undefined &&
|
|
428
|
+
position >= 1 &&
|
|
429
|
+
position <= prepared.rowEnd - prepared.rowStart + 1
|
|
430
|
+
? position
|
|
431
|
+
: undefined,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
const numericMap = request.searchMode === -1
|
|
435
|
+
? prepared.lastNumericPositions
|
|
436
|
+
: prepared.firstNumericPositions;
|
|
437
|
+
const row = numericMap?.get(numericValue);
|
|
438
|
+
return {
|
|
439
|
+
handled: true,
|
|
440
|
+
position: row === undefined ? undefined : row - prepared.rowStart + 1,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
if (prepared.comparableKind === "text") {
|
|
444
|
+
if (request.lookupValue.tag === ValueTag.Error) {
|
|
445
|
+
return { handled: false };
|
|
446
|
+
}
|
|
447
|
+
if (request.lookupValue.tag !== ValueTag.String) {
|
|
448
|
+
return { handled: true, position: undefined };
|
|
449
|
+
}
|
|
450
|
+
const textValue = normalizeLookupText(request.lookupValue, (id) => args.state.strings.get(id));
|
|
451
|
+
const textMap = request.searchMode === -1 ? prepared.lastTextPositions : prepared.firstTextPositions;
|
|
452
|
+
const row = textMap?.get(textValue);
|
|
453
|
+
return {
|
|
454
|
+
handled: true,
|
|
455
|
+
position: row === undefined ? undefined : row - prepared.rowStart + 1,
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
const normalizedLookupKey = normalizeExactLookupKey(request.lookupValue, (id) => args.state.strings.get(id));
|
|
459
|
+
if (normalizedLookupKey === undefined) {
|
|
460
|
+
return { handled: false };
|
|
461
|
+
}
|
|
462
|
+
const row = request.searchMode === -1
|
|
463
|
+
? prepared.lastPositions.get(normalizedLookupKey)
|
|
464
|
+
: prepared.firstPositions.get(normalizedLookupKey);
|
|
465
|
+
return {
|
|
466
|
+
handled: true,
|
|
467
|
+
position: row === undefined ? undefined : row - prepared.rowStart + 1,
|
|
468
|
+
};
|
|
469
|
+
},
|
|
470
|
+
prepareApproximateVectorLookup(request) {
|
|
471
|
+
return prepareApproximateVectorLookup(request);
|
|
472
|
+
},
|
|
473
|
+
findPreparedApproximateVectorMatch(request) {
|
|
474
|
+
const prepared = refreshPreparedApproximateVectorLookup(request.prepared);
|
|
475
|
+
if (prepared.comparableKind === undefined) {
|
|
476
|
+
return { handled: false };
|
|
477
|
+
}
|
|
478
|
+
if (request.matchMode === 1 && !prepared.sortedAscending) {
|
|
479
|
+
return { handled: false };
|
|
480
|
+
}
|
|
481
|
+
if (request.matchMode === -1 && !prepared.sortedDescending) {
|
|
482
|
+
return { handled: false };
|
|
483
|
+
}
|
|
484
|
+
if (prepared.comparableKind === "numeric") {
|
|
485
|
+
let lookupValue;
|
|
486
|
+
switch (request.lookupValue.tag) {
|
|
487
|
+
case ValueTag.Empty:
|
|
488
|
+
lookupValue = 0;
|
|
489
|
+
break;
|
|
490
|
+
case ValueTag.Number:
|
|
491
|
+
lookupValue = Object.is(request.lookupValue.value, -0) ? 0 : request.lookupValue.value;
|
|
492
|
+
break;
|
|
493
|
+
case ValueTag.Boolean:
|
|
494
|
+
lookupValue = request.lookupValue.value ? 1 : 0;
|
|
495
|
+
break;
|
|
496
|
+
case ValueTag.Error:
|
|
497
|
+
return { handled: false };
|
|
498
|
+
case ValueTag.String:
|
|
499
|
+
return { handled: false };
|
|
500
|
+
}
|
|
501
|
+
const values = prepared.numericValues;
|
|
502
|
+
if (!values) {
|
|
503
|
+
return { handled: false };
|
|
504
|
+
}
|
|
505
|
+
if (prepared.uniformStart !== undefined && prepared.uniformStep !== undefined) {
|
|
506
|
+
const { uniformStart, uniformStep } = prepared;
|
|
507
|
+
const lastValue = uniformStart + uniformStep * (values.length - 1);
|
|
508
|
+
if (request.matchMode === 1 && uniformStep > 0) {
|
|
509
|
+
if (lookupValue < uniformStart) {
|
|
510
|
+
return { handled: true, position: undefined };
|
|
511
|
+
}
|
|
512
|
+
if (lookupValue >= lastValue) {
|
|
513
|
+
return { handled: true, position: values.length };
|
|
514
|
+
}
|
|
515
|
+
const position = Math.floor((lookupValue - uniformStart) / uniformStep) + 1;
|
|
516
|
+
return { handled: true, position: Math.min(values.length, Math.max(1, position)) };
|
|
517
|
+
}
|
|
518
|
+
if (request.matchMode === -1 && uniformStep < 0) {
|
|
519
|
+
if (lookupValue > uniformStart) {
|
|
520
|
+
return { handled: true, position: undefined };
|
|
521
|
+
}
|
|
522
|
+
if (lookupValue <= lastValue) {
|
|
523
|
+
return { handled: true, position: values.length };
|
|
524
|
+
}
|
|
525
|
+
const position = Math.floor((uniformStart - lookupValue) / -uniformStep) + 1;
|
|
526
|
+
return { handled: true, position: Math.min(values.length, Math.max(1, position)) };
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
let low = 0;
|
|
530
|
+
let high = values.length - 1;
|
|
531
|
+
let best = -1;
|
|
532
|
+
while (low <= high) {
|
|
533
|
+
const mid = (low + high) >> 1;
|
|
534
|
+
const comparison = compareApproximateNumeric(values[mid], lookupValue);
|
|
535
|
+
if (request.matchMode === 1) {
|
|
536
|
+
if (comparison <= 0) {
|
|
537
|
+
best = mid;
|
|
538
|
+
low = mid + 1;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
high = mid - 1;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else if (comparison >= 0) {
|
|
545
|
+
best = mid;
|
|
546
|
+
low = mid + 1;
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
high = mid - 1;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return {
|
|
553
|
+
handled: true,
|
|
554
|
+
position: best === -1 ? undefined : best + 1,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
let lookupValue;
|
|
558
|
+
switch (request.lookupValue.tag) {
|
|
559
|
+
case ValueTag.Empty:
|
|
560
|
+
lookupValue = "";
|
|
561
|
+
break;
|
|
562
|
+
case ValueTag.String:
|
|
563
|
+
lookupValue = normalizeLookupText(request.lookupValue, (id) => args.state.strings.get(id));
|
|
564
|
+
break;
|
|
565
|
+
case ValueTag.Error:
|
|
566
|
+
return { handled: false };
|
|
567
|
+
case ValueTag.Number:
|
|
568
|
+
case ValueTag.Boolean:
|
|
569
|
+
return { handled: false };
|
|
570
|
+
}
|
|
571
|
+
const values = prepared.textValues;
|
|
572
|
+
if (!values) {
|
|
573
|
+
return { handled: false };
|
|
574
|
+
}
|
|
575
|
+
let low = 0;
|
|
576
|
+
let high = values.length - 1;
|
|
577
|
+
let best = -1;
|
|
578
|
+
while (low <= high) {
|
|
579
|
+
const mid = (low + high) >> 1;
|
|
580
|
+
const comparison = compareApproximateText(values[mid], lookupValue);
|
|
581
|
+
if (request.matchMode === 1) {
|
|
582
|
+
if (comparison <= 0) {
|
|
583
|
+
best = mid;
|
|
584
|
+
low = mid + 1;
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
high = mid - 1;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
else if (comparison >= 0) {
|
|
591
|
+
best = mid;
|
|
592
|
+
low = mid + 1;
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
high = mid - 1;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return {
|
|
599
|
+
handled: true,
|
|
600
|
+
position: best === -1 ? undefined : best + 1,
|
|
601
|
+
};
|
|
602
|
+
},
|
|
260
603
|
findExactVectorMatch(request) {
|
|
261
604
|
const normalizedLookupKey = normalizeExactLookupKey(request.lookupValue, (id) => args.state.strings.get(id));
|
|
262
605
|
if (normalizedLookupKey === undefined) {
|
|
@@ -267,6 +610,50 @@ export function createEngineLookupService(args) {
|
|
|
267
610
|
return { handled: false };
|
|
268
611
|
}
|
|
269
612
|
const entry = ensureExactColumnIndex(request.sheetName, bounds.col, bounds.rowStart, bounds.rowEnd);
|
|
613
|
+
if (entry.comparableKind === "numeric") {
|
|
614
|
+
if (request.lookupValue.tag === ValueTag.Error) {
|
|
615
|
+
return { handled: false };
|
|
616
|
+
}
|
|
617
|
+
if (request.lookupValue.tag !== ValueTag.Number) {
|
|
618
|
+
return { handled: true, position: undefined };
|
|
619
|
+
}
|
|
620
|
+
const numericValue = Object.is(request.lookupValue.value, -0)
|
|
621
|
+
? 0
|
|
622
|
+
: request.lookupValue.value;
|
|
623
|
+
if (entry.uniformStart !== undefined && entry.uniformStep !== undefined) {
|
|
624
|
+
const relative = (numericValue - entry.uniformStart) / entry.uniformStep;
|
|
625
|
+
const position = Number.isInteger(relative) ? relative + 1 : undefined;
|
|
626
|
+
return {
|
|
627
|
+
handled: true,
|
|
628
|
+
position: position !== undefined &&
|
|
629
|
+
position >= 1 &&
|
|
630
|
+
position <= bounds.rowEnd - bounds.rowStart + 1
|
|
631
|
+
? position
|
|
632
|
+
: undefined,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
const numericMap = request.searchMode === -1 ? entry.lastNumericPositions : entry.firstNumericPositions;
|
|
636
|
+
const row = numericMap?.get(numericValue);
|
|
637
|
+
return {
|
|
638
|
+
handled: true,
|
|
639
|
+
position: row === undefined ? undefined : row - bounds.rowStart + 1,
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
if (entry.comparableKind === "text") {
|
|
643
|
+
if (request.lookupValue.tag === ValueTag.Error) {
|
|
644
|
+
return { handled: false };
|
|
645
|
+
}
|
|
646
|
+
if (request.lookupValue.tag !== ValueTag.String) {
|
|
647
|
+
return { handled: true, position: undefined };
|
|
648
|
+
}
|
|
649
|
+
const textValue = normalizeLookupText(request.lookupValue, (id) => args.state.strings.get(id));
|
|
650
|
+
const textMap = request.searchMode === -1 ? entry.lastTextPositions : entry.firstTextPositions;
|
|
651
|
+
const row = textMap?.get(textValue);
|
|
652
|
+
return {
|
|
653
|
+
handled: true,
|
|
654
|
+
position: row === undefined ? undefined : row - bounds.rowStart + 1,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
270
657
|
const row = request.searchMode === -1
|
|
271
658
|
? entry.lastPositions.get(normalizedLookupKey)
|
|
272
659
|
: entry.firstPositions.get(normalizedLookupKey);
|
|
@@ -291,15 +678,50 @@ export function createEngineLookupService(args) {
|
|
|
291
678
|
return { handled: false };
|
|
292
679
|
}
|
|
293
680
|
if (entry.comparableKind === "numeric") {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
681
|
+
let lookupValue;
|
|
682
|
+
switch (request.lookupValue.tag) {
|
|
683
|
+
case ValueTag.Empty:
|
|
684
|
+
lookupValue = 0;
|
|
685
|
+
break;
|
|
686
|
+
case ValueTag.Number:
|
|
687
|
+
lookupValue = Object.is(request.lookupValue.value, -0) ? 0 : request.lookupValue.value;
|
|
688
|
+
break;
|
|
689
|
+
case ValueTag.Boolean:
|
|
690
|
+
lookupValue = request.lookupValue.value ? 1 : 0;
|
|
691
|
+
break;
|
|
692
|
+
case ValueTag.Error:
|
|
693
|
+
return { handled: false };
|
|
694
|
+
case ValueTag.String:
|
|
695
|
+
return { handled: false };
|
|
297
696
|
}
|
|
298
697
|
const values = entry.numericValues;
|
|
299
698
|
if (!values) {
|
|
300
699
|
return { handled: false };
|
|
301
700
|
}
|
|
302
|
-
|
|
701
|
+
if (entry.uniformStart !== undefined && entry.uniformStep !== undefined) {
|
|
702
|
+
const { uniformStart, uniformStep } = entry;
|
|
703
|
+
const lastValue = uniformStart + uniformStep * (values.length - 1);
|
|
704
|
+
if (request.matchMode === 1 && uniformStep > 0) {
|
|
705
|
+
if (lookupValue < uniformStart) {
|
|
706
|
+
return { handled: true, position: undefined };
|
|
707
|
+
}
|
|
708
|
+
if (lookupValue >= lastValue) {
|
|
709
|
+
return { handled: true, position: values.length };
|
|
710
|
+
}
|
|
711
|
+
const position = Math.floor((lookupValue - uniformStart) / uniformStep) + 1;
|
|
712
|
+
return { handled: true, position: Math.min(values.length, Math.max(1, position)) };
|
|
713
|
+
}
|
|
714
|
+
if (request.matchMode === -1 && uniformStep < 0) {
|
|
715
|
+
if (lookupValue > uniformStart) {
|
|
716
|
+
return { handled: true, position: undefined };
|
|
717
|
+
}
|
|
718
|
+
if (lookupValue <= lastValue) {
|
|
719
|
+
return { handled: true, position: values.length };
|
|
720
|
+
}
|
|
721
|
+
const position = Math.floor((uniformStart - lookupValue) / -uniformStep) + 1;
|
|
722
|
+
return { handled: true, position: Math.min(values.length, Math.max(1, position)) };
|
|
723
|
+
}
|
|
724
|
+
}
|
|
303
725
|
let low = 0;
|
|
304
726
|
let high = values.length - 1;
|
|
305
727
|
let best = -1;
|