qvdjs 2.2.1 → 2.2.3
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/index.cjs +315 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +315 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1189,6 +1189,212 @@ var init_bitUtils = __esm({
|
|
|
1189
1189
|
}
|
|
1190
1190
|
});
|
|
1191
1191
|
|
|
1192
|
+
// src/util/seenNumbers.js
|
|
1193
|
+
function firstJudgementRow(rows) {
|
|
1194
|
+
return Math.min(WINDOW_ROWS, Math.max(MIN_JUDGED_LOOKUPS, Math.floor(rows / 2)));
|
|
1195
|
+
}
|
|
1196
|
+
function slotOf(value, mask) {
|
|
1197
|
+
const product = value * MULTIPLIER;
|
|
1198
|
+
return product < EXACT && product > -EXACT ? product & mask : ((product | 0) ^ (product * UPPER_HALF | 0)) & mask;
|
|
1199
|
+
}
|
|
1200
|
+
function slotsFor(count, most) {
|
|
1201
|
+
let slots = MIN_SLOTS;
|
|
1202
|
+
while (slots < count && slots < most) {
|
|
1203
|
+
slots *= 2;
|
|
1204
|
+
}
|
|
1205
|
+
return slots;
|
|
1206
|
+
}
|
|
1207
|
+
function shareOf(columns) {
|
|
1208
|
+
let slots = MAX_SLOTS;
|
|
1209
|
+
while (slots > MIN_SLOTS && slots * columns > TOTAL_SLOTS) {
|
|
1210
|
+
slots /= 2;
|
|
1211
|
+
}
|
|
1212
|
+
return slots;
|
|
1213
|
+
}
|
|
1214
|
+
function symbolPassTable(rows, pool) {
|
|
1215
|
+
return pool.take(MIN_SLOTS) ? new SeenNumbers(MIN_SLOTS, slotsFor(rows, MAX_SLOTS), SYMBOL_PASS_MISS_LIMIT, pool) : null;
|
|
1216
|
+
}
|
|
1217
|
+
function numericCellsAfter(data, column, stopped, numbers) {
|
|
1218
|
+
const most = stopped.cells + data.length - stopped.row;
|
|
1219
|
+
if (!indexPassWants(numbers, most)) {
|
|
1220
|
+
return most;
|
|
1221
|
+
}
|
|
1222
|
+
let cells = stopped.cells;
|
|
1223
|
+
for (let row = stopped.row; row < data.length; row++) {
|
|
1224
|
+
if (typeof data[row]?.[column] === "number") {
|
|
1225
|
+
cells++;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
return cells;
|
|
1229
|
+
}
|
|
1230
|
+
function numbersIn(map) {
|
|
1231
|
+
let numbers = 0;
|
|
1232
|
+
for (const key of map.keys()) {
|
|
1233
|
+
if (typeof key === "number") {
|
|
1234
|
+
numbers++;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
return numbers;
|
|
1238
|
+
}
|
|
1239
|
+
function indexPassWants(numbers, cells) {
|
|
1240
|
+
return numbers > 0 && numbers <= INDEX_PASS_MISS_LIMIT * cells;
|
|
1241
|
+
}
|
|
1242
|
+
function indexPassTable(numbers, cells, symbols, share, pool) {
|
|
1243
|
+
const slots = Math.min(slotsFor(numbers * SLOTS_PER_NUMBER, share), slotsFor(cells, share));
|
|
1244
|
+
return pool.take(slots) ? new SeenNumbers(slots, slots, INDEX_PASS_MISS_LIMIT - numbers / cells, pool, symbols) : null;
|
|
1245
|
+
}
|
|
1246
|
+
function endWindow(tables, row = 0, stopped = null) {
|
|
1247
|
+
for (let column = 0; column < tables.length; column++) {
|
|
1248
|
+
const table = tables[column];
|
|
1249
|
+
if (table === null || table === NO_TABLE_YET) {
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
const lookups = table.cells - table.judgedCells;
|
|
1253
|
+
if (lookups < MIN_JUDGED_LOOKUPS) {
|
|
1254
|
+
continue;
|
|
1255
|
+
}
|
|
1256
|
+
if (table.misses > (table.judged ? table.limit : FIRST_WINDOW_MISS_LIMIT) * lookups) {
|
|
1257
|
+
tables[column] = null;
|
|
1258
|
+
table.pool.give(table.values.length);
|
|
1259
|
+
if (stopped !== null) {
|
|
1260
|
+
stopped[column] = { row, cells: table.cells };
|
|
1261
|
+
}
|
|
1262
|
+
} else {
|
|
1263
|
+
table.judgedCells = table.cells;
|
|
1264
|
+
table.misses = 0;
|
|
1265
|
+
table.judged = true;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
var MULTIPLIER, EXACT, UPPER_HALF, WINDOW_ROWS, MIN_JUDGED_LOOKUPS, MIN_SLOTS, MAX_SLOTS, TOTAL_SLOTS, SLOTS_PER_NUMBER, FIRST_WINDOW_MISS_LIMIT, SYMBOL_PASS_MISS_LIMIT, INDEX_PASS_MISS_LIMIT, SlotPool, SeenNumbers, NO_TABLE_YET;
|
|
1270
|
+
var init_seenNumbers = __esm({
|
|
1271
|
+
"src/util/seenNumbers.js"() {
|
|
1272
|
+
MULTIPLIER = 2654435761;
|
|
1273
|
+
EXACT = 2 ** 53;
|
|
1274
|
+
UPPER_HALF = 2 ** -32;
|
|
1275
|
+
WINDOW_ROWS = 16384;
|
|
1276
|
+
MIN_JUDGED_LOOKUPS = 1024;
|
|
1277
|
+
__name(firstJudgementRow, "firstJudgementRow");
|
|
1278
|
+
MIN_SLOTS = 64;
|
|
1279
|
+
MAX_SLOTS = 65536;
|
|
1280
|
+
TOTAL_SLOTS = 2 ** 21;
|
|
1281
|
+
SLOTS_PER_NUMBER = 8;
|
|
1282
|
+
FIRST_WINDOW_MISS_LIMIT = 0.9;
|
|
1283
|
+
SYMBOL_PASS_MISS_LIMIT = 0.3;
|
|
1284
|
+
INDEX_PASS_MISS_LIMIT = 0.75;
|
|
1285
|
+
__name(slotOf, "slotOf");
|
|
1286
|
+
__name(slotsFor, "slotsFor");
|
|
1287
|
+
__name(shareOf, "shareOf");
|
|
1288
|
+
SlotPool = class {
|
|
1289
|
+
static {
|
|
1290
|
+
__name(this, "SlotPool");
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* @param {number} [slots] How many there are to give.
|
|
1294
|
+
*/
|
|
1295
|
+
constructor(slots = TOTAL_SLOTS) {
|
|
1296
|
+
this.left = slots;
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Takes slots, if there are that many left.
|
|
1300
|
+
*
|
|
1301
|
+
* @param {number} slots How many.
|
|
1302
|
+
* @return {boolean} Whether they were taken.
|
|
1303
|
+
*/
|
|
1304
|
+
take(slots) {
|
|
1305
|
+
if (slots > this.left) {
|
|
1306
|
+
return false;
|
|
1307
|
+
}
|
|
1308
|
+
this.left -= slots;
|
|
1309
|
+
return true;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Gives slots back.
|
|
1313
|
+
*
|
|
1314
|
+
* @param {number} slots How many.
|
|
1315
|
+
*/
|
|
1316
|
+
give(slots) {
|
|
1317
|
+
this.left += slots;
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
SeenNumbers = class _SeenNumbers {
|
|
1321
|
+
static {
|
|
1322
|
+
__name(this, "SeenNumbers");
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* @param {number} slots How many slots: a power of two from `MIN_SLOTS` to `MAX_SLOTS`, already taken from
|
|
1326
|
+
* `pool`.
|
|
1327
|
+
* @param {number} maxSlots The most it may grow to, in the symbol table pass.
|
|
1328
|
+
* @param {number} limit The share of its lookups a judged window may miss.
|
|
1329
|
+
* @param {SlotPool} pool Where its slots came from, and where they go back when it is switched off.
|
|
1330
|
+
* @param {number} [symbols] In the index table pass, the column's symbols, one bit each. -1, the default, in
|
|
1331
|
+
* the symbol table pass.
|
|
1332
|
+
*/
|
|
1333
|
+
constructor(slots, maxSlots, limit, pool, symbols = -1) {
|
|
1334
|
+
this.values = new Float64Array(slots).fill(NaN);
|
|
1335
|
+
this.indices = new Int32Array(symbols >= 0 ? slots : 0);
|
|
1336
|
+
this.met = new Uint32Array(symbols >= 0 ? Math.ceil(symbols / 32) : 0);
|
|
1337
|
+
this.mask = slots - 1;
|
|
1338
|
+
this.maxSlots = maxSlots;
|
|
1339
|
+
this.limit = limit;
|
|
1340
|
+
this.pool = pool;
|
|
1341
|
+
this.cells = 0;
|
|
1342
|
+
this.judgedCells = 0;
|
|
1343
|
+
this.misses = 0;
|
|
1344
|
+
this.judged = symbols >= 0;
|
|
1345
|
+
this.inserted = 0;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Remembers a number the symbol table pass has just put in the map, growing the table instead once more
|
|
1349
|
+
* than an eighth of its slots would hold distinct numbers - if its pool has the slots. A table the pool
|
|
1350
|
+
* cannot grow stops trying, and keeps remembering in the slots it has.
|
|
1351
|
+
*
|
|
1352
|
+
* @param {number} slot The number's slot, from `slotOf`.
|
|
1353
|
+
* @param {number} value The number.
|
|
1354
|
+
* @return {SeenNumbers} The table to use from now on: this one, or a larger, empty one.
|
|
1355
|
+
*/
|
|
1356
|
+
remember(slot, value) {
|
|
1357
|
+
this.inserted++;
|
|
1358
|
+
if (this.inserted * SLOTS_PER_NUMBER > this.values.length && this.values.length < this.maxSlots) {
|
|
1359
|
+
const slots = Math.min(this.values.length * 4, this.maxSlots);
|
|
1360
|
+
if (this.pool.take(slots - this.values.length)) {
|
|
1361
|
+
const grown = new _SeenNumbers(slots, this.maxSlots, this.limit, this.pool);
|
|
1362
|
+
grown.inserted = this.inserted;
|
|
1363
|
+
grown.cells = this.cells;
|
|
1364
|
+
grown.judgedCells = this.judgedCells;
|
|
1365
|
+
grown.misses = this.misses;
|
|
1366
|
+
grown.judged = this.judged;
|
|
1367
|
+
return grown;
|
|
1368
|
+
}
|
|
1369
|
+
this.maxSlots = this.values.length;
|
|
1370
|
+
}
|
|
1371
|
+
this.values[slot] = value;
|
|
1372
|
+
return this;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Marks a symbol met through this table, in the index table pass.
|
|
1376
|
+
*
|
|
1377
|
+
* @param {number} index The symbol the map answered.
|
|
1378
|
+
* @return {boolean} Whether it had been met before; false for a first sight.
|
|
1379
|
+
*/
|
|
1380
|
+
metBefore(index) {
|
|
1381
|
+
const word = index >>> 5;
|
|
1382
|
+
const bit = 1 << (index & 31);
|
|
1383
|
+
const before = (this.met[word] & bit) !== 0;
|
|
1384
|
+
this.met[word] |= bit;
|
|
1385
|
+
return before;
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
NO_TABLE_YET = new SeenNumbers(1, 1, 0, new SlotPool(1));
|
|
1389
|
+
__name(symbolPassTable, "symbolPassTable");
|
|
1390
|
+
__name(numericCellsAfter, "numericCellsAfter");
|
|
1391
|
+
__name(numbersIn, "numbersIn");
|
|
1392
|
+
__name(indexPassWants, "indexPassWants");
|
|
1393
|
+
__name(indexPassTable, "indexPassTable");
|
|
1394
|
+
__name(endWindow, "endWindow");
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1192
1398
|
// src/QvdFileWriter.js
|
|
1193
1399
|
var QvdFileWriter_exports = {};
|
|
1194
1400
|
__export(QvdFileWriter_exports, {
|
|
@@ -1476,6 +1682,7 @@ var init_QvdFileWriter = __esm({
|
|
|
1476
1682
|
init_cellRules();
|
|
1477
1683
|
init_symbolBytes();
|
|
1478
1684
|
init_storedSymbols();
|
|
1685
|
+
init_seenNumbers();
|
|
1479
1686
|
__name(notXmlIndex, "notXmlIndex");
|
|
1480
1687
|
__name(checkHeaderText, "checkHeaderText");
|
|
1481
1688
|
__name(checkHeaderTexts, "checkHeaderTexts");
|
|
@@ -1938,7 +2145,14 @@ var init_QvdFileWriter = __esm({
|
|
|
1938
2145
|
const byCells = state.map((column) => column.byCell);
|
|
1939
2146
|
const byObjects = state.map((column) => column.byObject);
|
|
1940
2147
|
const containsNull = columns.map(() => false);
|
|
2148
|
+
const pool = new SlotPool();
|
|
2149
|
+
const seen = columns.map(() => NO_TABLE_YET);
|
|
2150
|
+
const firstJudgement = firstJudgementRow(numRows);
|
|
2151
|
+
const stopped = columns.map(() => null);
|
|
1941
2152
|
for (let row = 0; row < numRows; row++) {
|
|
2153
|
+
if (row % WINDOW_ROWS === 0 && row !== 0 || row === firstJudgement) {
|
|
2154
|
+
endWindow(seen, row, stopped);
|
|
2155
|
+
}
|
|
1942
2156
|
const values = data[row];
|
|
1943
2157
|
if (values !== null && values !== void 0 && !Array.isArray(values)) {
|
|
1944
2158
|
throw new QvdValidationError("Each row must be an array of values", {
|
|
@@ -1969,7 +2183,34 @@ var init_QvdFileWriter = __esm({
|
|
|
1969
2183
|
}
|
|
1970
2184
|
continue;
|
|
1971
2185
|
}
|
|
2186
|
+
let table = null;
|
|
2187
|
+
let slot = 0;
|
|
2188
|
+
if (typeof value === "number") {
|
|
2189
|
+
table = seen[column];
|
|
2190
|
+
if (table !== null) {
|
|
2191
|
+
table.cells++;
|
|
2192
|
+
slot = slotOf(value, table.mask);
|
|
2193
|
+
if (table.values[slot] === value) {
|
|
2194
|
+
continue;
|
|
2195
|
+
}
|
|
2196
|
+
table.misses++;
|
|
2197
|
+
if (table === NO_TABLE_YET) {
|
|
2198
|
+
table = symbolPassTable(numRows, pool);
|
|
2199
|
+
seen[column] = table;
|
|
2200
|
+
if (table === null) {
|
|
2201
|
+
stopped[column] = { row, cells: 0 };
|
|
2202
|
+
} else {
|
|
2203
|
+
table.cells = 1;
|
|
2204
|
+
table.misses = 1;
|
|
2205
|
+
slot = slotOf(value, table.mask);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
1972
2210
|
if (byCells[column].has(value)) {
|
|
2211
|
+
if (table !== null) {
|
|
2212
|
+
table.values[slot] = value;
|
|
2213
|
+
}
|
|
1973
2214
|
continue;
|
|
1974
2215
|
}
|
|
1975
2216
|
if (typeof value === "number") {
|
|
@@ -1989,6 +2230,9 @@ var init_QvdFileWriter = __esm({
|
|
|
1989
2230
|
refuseCell(value, columns[column], row, this._path);
|
|
1990
2231
|
}
|
|
1991
2232
|
byCells[column].set(value, slotForCell(state[column], value, row, this._path));
|
|
2233
|
+
if (table !== null && typeof value === "number") {
|
|
2234
|
+
seen[column] = table.remember(slot, value);
|
|
2235
|
+
}
|
|
1992
2236
|
}
|
|
1993
2237
|
}
|
|
1994
2238
|
const columnBuffers = [];
|
|
@@ -1997,10 +2241,12 @@ var init_QvdFileWriter = __esm({
|
|
|
1997
2241
|
const { keys, texts } = state[column];
|
|
1998
2242
|
const kinds = new Uint8Array(keys.length);
|
|
1999
2243
|
let byteLength = 0;
|
|
2244
|
+
let numberKeys = 0;
|
|
2000
2245
|
for (let slot = 0; slot < keys.length; slot++) {
|
|
2001
2246
|
const key = keys[slot];
|
|
2002
2247
|
const text = texts[slot];
|
|
2003
2248
|
if (typeof key === "number") {
|
|
2249
|
+
numberKeys++;
|
|
2004
2250
|
if (numberProblem(key) !== null) {
|
|
2005
2251
|
checkNumber(key, null, { column: columns[column], file: this._path, stage: "buildSymbolTable" });
|
|
2006
2252
|
}
|
|
@@ -2029,10 +2275,20 @@ var init_QvdFileWriter = __esm({
|
|
|
2029
2275
|
this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);
|
|
2030
2276
|
this._symbolCounts?.push(keys.length);
|
|
2031
2277
|
this._symbolFacts?.push(state[column].facts);
|
|
2278
|
+
const numbers = state[column].byCell === state[column].byKey ? numberKeys : numbersIn(state[column].byCell);
|
|
2279
|
+
const table = seen[column];
|
|
2032
2280
|
this._symbolIndexByValue?.push({
|
|
2033
2281
|
byCell: state[column].byCell,
|
|
2034
2282
|
byKey: state[column].byKey,
|
|
2035
|
-
byObject: state[column].byObject
|
|
2283
|
+
byObject: state[column].byObject,
|
|
2284
|
+
numbers,
|
|
2285
|
+
cells: table === NO_TABLE_YET ? 0 : table !== null ? table.cells : numericCellsAfter(
|
|
2286
|
+
data,
|
|
2287
|
+
column,
|
|
2288
|
+
/** @type {{row: number, cells: number}} */
|
|
2289
|
+
stopped[column],
|
|
2290
|
+
numbers
|
|
2291
|
+
)
|
|
2036
2292
|
});
|
|
2037
2293
|
symbolsOffset += byteLength;
|
|
2038
2294
|
this._emitProgress("symbol-table", column + 1, numColumns);
|
|
@@ -2082,7 +2338,7 @@ var init_QvdFileWriter = __esm({
|
|
|
2082
2338
|
const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;
|
|
2083
2339
|
const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);
|
|
2084
2340
|
const lookup = this._symbolIndexByValue[column];
|
|
2085
|
-
const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] :
|
|
2341
|
+
const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] : [lookup.byCell, lookup.byKey, lookup.byObject];
|
|
2086
2342
|
for (const map of maps) {
|
|
2087
2343
|
for (const index of map.values()) {
|
|
2088
2344
|
if (index + nullShift > maxStoredIndex) {
|
|
@@ -2108,14 +2364,44 @@ var init_QvdFileWriter = __esm({
|
|
|
2108
2364
|
const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);
|
|
2109
2365
|
const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);
|
|
2110
2366
|
const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);
|
|
2367
|
+
const symbolCounts = this._symbolCounts;
|
|
2368
|
+
const wanted = this._symbolIndexByValue.map((lookup) => indexPassWants(lookup.numbers, lookup.cells));
|
|
2369
|
+
const share = shareOf(wanted.filter(Boolean).length);
|
|
2370
|
+
const pool = new SlotPool();
|
|
2371
|
+
const seen = this._symbolIndexByValue.map(
|
|
2372
|
+
(lookup, column) => wanted[column] ? indexPassTable(lookup.numbers, lookup.cells, symbolCounts[column], share, pool) : null
|
|
2373
|
+
);
|
|
2374
|
+
const firstJudgement = firstJudgementRow(numRows);
|
|
2111
2375
|
for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {
|
|
2376
|
+
if (row % WINDOW_ROWS === 0 && row !== 0 || row === firstJudgement) {
|
|
2377
|
+
endWindow(seen);
|
|
2378
|
+
}
|
|
2112
2379
|
const values = data[row];
|
|
2113
2380
|
for (let column = 0; column < numColumns; column++) {
|
|
2114
2381
|
const value = values?.[column];
|
|
2115
2382
|
if (value === null || value === void 0) {
|
|
2116
2383
|
continue;
|
|
2117
2384
|
}
|
|
2118
|
-
const
|
|
2385
|
+
const table = typeof value === "number" ? seen[column] : null;
|
|
2386
|
+
let index;
|
|
2387
|
+
if (table !== null) {
|
|
2388
|
+
table.cells++;
|
|
2389
|
+
const slot = slotOf(value, table.mask);
|
|
2390
|
+
if (table.values[slot] === value) {
|
|
2391
|
+
index = table.indices[slot];
|
|
2392
|
+
} else {
|
|
2393
|
+
index = byCells[column].get(value);
|
|
2394
|
+
if (index !== void 0) {
|
|
2395
|
+
table.values[slot] = value;
|
|
2396
|
+
table.indices[slot] = index;
|
|
2397
|
+
if (table.metBefore(index)) {
|
|
2398
|
+
table.misses++;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
} else {
|
|
2403
|
+
index = typeof value === "object" ? byObjects[column].get(value) ?? byKeys[column].get(value.number) : byCells[column].get(value);
|
|
2404
|
+
}
|
|
2119
2405
|
if (index === void 0) {
|
|
2120
2406
|
throw new QvdValidationError("A value is missing from the symbol table", {
|
|
2121
2407
|
field: columns[column],
|
|
@@ -5129,12 +5415,14 @@ var init_QvdFileReader = __esm({
|
|
|
5129
5415
|
* viewer scrolls to - and the header is already in hand. `parseHeaderOnly` has to have run.
|
|
5130
5416
|
*
|
|
5131
5417
|
* @param {QvdRowWindow} window The rows the read would cover, normalised.
|
|
5132
|
-
* @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean
|
|
5133
|
-
* `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask
|
|
5134
|
-
* one this reader was built for, which is what a `QvdFile` does per call
|
|
5418
|
+
* @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean,
|
|
5419
|
+
* paging?: boolean}} [options] `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask
|
|
5420
|
+
* about a read other than the one this reader was built for, which is what a `QvdFile` does per call;
|
|
5421
|
+
* `paging` to say whether the read being asked about is a paging read, which defaults to whether this
|
|
5422
|
+
* reader is one.
|
|
5135
5423
|
* @return {any} The answer - see `checkMemory`.
|
|
5136
5424
|
*/
|
|
5137
|
-
checkParsed(window, { chunkSize = null, fields = void 0, materialisesRows = void 0 } = {}) {
|
|
5425
|
+
checkParsed(window, { chunkSize = null, fields = void 0, materialisesRows = void 0, paging = this._symbolCache !== null } = {}) {
|
|
5138
5426
|
assert4(this._header && this._allFields, "The QVD file header has not been parsed.");
|
|
5139
5427
|
const header = this._header["QvdTableHeader"];
|
|
5140
5428
|
const totalRows = headerInteger(header["NoOfRecords"]);
|
|
@@ -5145,15 +5433,13 @@ var init_QvdFileReader = __esm({
|
|
|
5145
5433
|
const resolved = resolveWindow(window, totalRows);
|
|
5146
5434
|
const windowRows = resolved.limit;
|
|
5147
5435
|
const liveRows = chunkSize === null ? null : { rows: chunkSize * 2, perChunk: 2 };
|
|
5148
|
-
const analysisAhead = this.
|
|
5436
|
+
const analysisAhead = paging ? false : this._analysisWouldRun(window, resolved, totalRows, symbolTableLength);
|
|
5149
5437
|
const measured = getMemoryBudget();
|
|
5150
5438
|
const ask = /* @__PURE__ */ __name((asked, rows) => {
|
|
5151
|
-
const
|
|
5152
|
-
const
|
|
5153
|
-
const
|
|
5154
|
-
|
|
5155
|
-
symbolTableLength
|
|
5156
|
-
);
|
|
5439
|
+
const held = paging ? this._fieldsHeldAfter(asked, this._allFields) : asked;
|
|
5440
|
+
const bytes = symbolBytesOf(held, symbolTableLength);
|
|
5441
|
+
const read = symbolBytesOf(paging ? this._fieldsReadBy(asked) : asked, symbolTableLength);
|
|
5442
|
+
const retained = paging ? symbolBytesOf(held.slice(asked.length), symbolTableLength) : 0;
|
|
5157
5443
|
return checkMemory({
|
|
5158
5444
|
measured,
|
|
5159
5445
|
symbolTableSize: bytes,
|
|
@@ -5164,7 +5450,7 @@ var init_QvdFileReader = __esm({
|
|
|
5164
5450
|
materialisesRows: builds,
|
|
5165
5451
|
live: liveRows,
|
|
5166
5452
|
// A paging read keeps whole columns, so it is charged for whole columns - see `estimateMemoryUsage`.
|
|
5167
|
-
wholeSymbols:
|
|
5453
|
+
wholeSymbols: paging,
|
|
5168
5454
|
retainedBytes: retained,
|
|
5169
5455
|
bytesHeld: this._bytesHeld(read, rows, recordSize, liveRows, analysisAhead, bytes - retained),
|
|
5170
5456
|
// What it reads from the file, which is not what it holds: the symbol areas it has still to read,
|
|
@@ -5499,12 +5785,16 @@ var init_QvdFile = __esm({
|
|
|
5499
5785
|
/**
|
|
5500
5786
|
* What a read of this file would cost, and whether it fits - with no I/O at all.
|
|
5501
5787
|
*
|
|
5502
|
-
*
|
|
5503
|
-
*
|
|
5788
|
+
* Without `chunkSize` it asks about a page, and answers for the page this file would read next: the
|
|
5789
|
+
* columns it names plus the ones earlier pages decoded and kept, since those are part of what the page
|
|
5790
|
+
* costs. With `chunkSize` it asks about an `iterate()` of the file instead - which this object cannot
|
|
5791
|
+
* make, but a caller holding it may want to weigh - and answers exactly as `QvdDataFrame.checkRead()`
|
|
5792
|
+
* would, from the header this file already holds rather than by reading it again.
|
|
5504
5793
|
*
|
|
5505
5794
|
* @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,
|
|
5506
5795
|
* as?: 'rows'|'columns', chunkSize?: number|null}} [options] The read being asked about - the same
|
|
5507
|
-
* bag `rows()` takes, plus `as`
|
|
5796
|
+
* bag `rows()` takes, plus `as` to say which shape of page, and `chunkSize` to ask about an
|
|
5797
|
+
* `iterate()` of the file rather than a page.
|
|
5508
5798
|
* @return {any} The answer - `fits`, `reason`, `estimate`, `budget`, `exact`, `suggestions`.
|
|
5509
5799
|
* @throws {QvdValidationError} If the file is closed, or an option's value is not valid.
|
|
5510
5800
|
*/
|
|
@@ -5523,7 +5813,7 @@ var init_QvdFile = __esm({
|
|
|
5523
5813
|
if (chunkSize !== null) {
|
|
5524
5814
|
requireChunkSize(chunkSize, this._options.path);
|
|
5525
5815
|
}
|
|
5526
|
-
const reader = this._readers[as] ?? this._reader;
|
|
5816
|
+
const reader = chunkSize !== null ? this._reader : this._readers[as] ?? this._reader;
|
|
5527
5817
|
return reader.checkParsed(normaliseWindow(windowFrom(options), this._options.path), {
|
|
5528
5818
|
chunkSize,
|
|
5529
5819
|
// Resolved here rather than left to the reader, exactly as `_page` resolves it. A warm reader is
|
|
@@ -5532,7 +5822,12 @@ var init_QvdFile = __esm({
|
|
|
5532
5822
|
// file after a page naming one of them, it reported 27,490 bytes for a read that costs 108,160:
|
|
5533
5823
|
// understating, which is the direction that approves a read the read then refuses.
|
|
5534
5824
|
fields: options.fields === void 0 ? this._options.fields ?? null : options.fields,
|
|
5535
|
-
materialisesRows: as === "rows"
|
|
5825
|
+
materialisesRows: as === "rows",
|
|
5826
|
+
// Said outright rather than read off the reader. The header reader has paging on, because a check
|
|
5827
|
+
// made before the first page has to be priced as that page will be - so it cannot tell an `iterate()`
|
|
5828
|
+
// question from a page one by its own mode, and routing to it alone still priced the iterate as a
|
|
5829
|
+
// page wherever a bounded window would have been filtered.
|
|
5830
|
+
...chunkSize === null ? {} : { paging: false }
|
|
5536
5831
|
});
|
|
5537
5832
|
}
|
|
5538
5833
|
/**
|