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.cjs
CHANGED
|
@@ -1201,6 +1201,212 @@ var init_bitUtils = __esm({
|
|
|
1201
1201
|
}
|
|
1202
1202
|
});
|
|
1203
1203
|
|
|
1204
|
+
// src/util/seenNumbers.js
|
|
1205
|
+
function firstJudgementRow(rows) {
|
|
1206
|
+
return Math.min(WINDOW_ROWS, Math.max(MIN_JUDGED_LOOKUPS, Math.floor(rows / 2)));
|
|
1207
|
+
}
|
|
1208
|
+
function slotOf(value, mask) {
|
|
1209
|
+
const product = value * MULTIPLIER;
|
|
1210
|
+
return product < EXACT && product > -EXACT ? product & mask : ((product | 0) ^ (product * UPPER_HALF | 0)) & mask;
|
|
1211
|
+
}
|
|
1212
|
+
function slotsFor(count, most) {
|
|
1213
|
+
let slots = MIN_SLOTS;
|
|
1214
|
+
while (slots < count && slots < most) {
|
|
1215
|
+
slots *= 2;
|
|
1216
|
+
}
|
|
1217
|
+
return slots;
|
|
1218
|
+
}
|
|
1219
|
+
function shareOf(columns) {
|
|
1220
|
+
let slots = MAX_SLOTS;
|
|
1221
|
+
while (slots > MIN_SLOTS && slots * columns > TOTAL_SLOTS) {
|
|
1222
|
+
slots /= 2;
|
|
1223
|
+
}
|
|
1224
|
+
return slots;
|
|
1225
|
+
}
|
|
1226
|
+
function symbolPassTable(rows, pool) {
|
|
1227
|
+
return pool.take(MIN_SLOTS) ? new SeenNumbers(MIN_SLOTS, slotsFor(rows, MAX_SLOTS), SYMBOL_PASS_MISS_LIMIT, pool) : null;
|
|
1228
|
+
}
|
|
1229
|
+
function numericCellsAfter(data, column, stopped, numbers) {
|
|
1230
|
+
const most = stopped.cells + data.length - stopped.row;
|
|
1231
|
+
if (!indexPassWants(numbers, most)) {
|
|
1232
|
+
return most;
|
|
1233
|
+
}
|
|
1234
|
+
let cells = stopped.cells;
|
|
1235
|
+
for (let row = stopped.row; row < data.length; row++) {
|
|
1236
|
+
if (typeof data[row]?.[column] === "number") {
|
|
1237
|
+
cells++;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return cells;
|
|
1241
|
+
}
|
|
1242
|
+
function numbersIn(map) {
|
|
1243
|
+
let numbers = 0;
|
|
1244
|
+
for (const key of map.keys()) {
|
|
1245
|
+
if (typeof key === "number") {
|
|
1246
|
+
numbers++;
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
return numbers;
|
|
1250
|
+
}
|
|
1251
|
+
function indexPassWants(numbers, cells) {
|
|
1252
|
+
return numbers > 0 && numbers <= INDEX_PASS_MISS_LIMIT * cells;
|
|
1253
|
+
}
|
|
1254
|
+
function indexPassTable(numbers, cells, symbols, share, pool) {
|
|
1255
|
+
const slots = Math.min(slotsFor(numbers * SLOTS_PER_NUMBER, share), slotsFor(cells, share));
|
|
1256
|
+
return pool.take(slots) ? new SeenNumbers(slots, slots, INDEX_PASS_MISS_LIMIT - numbers / cells, pool, symbols) : null;
|
|
1257
|
+
}
|
|
1258
|
+
function endWindow(tables, row = 0, stopped = null) {
|
|
1259
|
+
for (let column = 0; column < tables.length; column++) {
|
|
1260
|
+
const table = tables[column];
|
|
1261
|
+
if (table === null || table === NO_TABLE_YET) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
const lookups = table.cells - table.judgedCells;
|
|
1265
|
+
if (lookups < MIN_JUDGED_LOOKUPS) {
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (table.misses > (table.judged ? table.limit : FIRST_WINDOW_MISS_LIMIT) * lookups) {
|
|
1269
|
+
tables[column] = null;
|
|
1270
|
+
table.pool.give(table.values.length);
|
|
1271
|
+
if (stopped !== null) {
|
|
1272
|
+
stopped[column] = { row, cells: table.cells };
|
|
1273
|
+
}
|
|
1274
|
+
} else {
|
|
1275
|
+
table.judgedCells = table.cells;
|
|
1276
|
+
table.misses = 0;
|
|
1277
|
+
table.judged = true;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
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;
|
|
1282
|
+
var init_seenNumbers = __esm({
|
|
1283
|
+
"src/util/seenNumbers.js"() {
|
|
1284
|
+
MULTIPLIER = 2654435761;
|
|
1285
|
+
EXACT = 2 ** 53;
|
|
1286
|
+
UPPER_HALF = 2 ** -32;
|
|
1287
|
+
WINDOW_ROWS = 16384;
|
|
1288
|
+
MIN_JUDGED_LOOKUPS = 1024;
|
|
1289
|
+
__name(firstJudgementRow, "firstJudgementRow");
|
|
1290
|
+
MIN_SLOTS = 64;
|
|
1291
|
+
MAX_SLOTS = 65536;
|
|
1292
|
+
TOTAL_SLOTS = 2 ** 21;
|
|
1293
|
+
SLOTS_PER_NUMBER = 8;
|
|
1294
|
+
FIRST_WINDOW_MISS_LIMIT = 0.9;
|
|
1295
|
+
SYMBOL_PASS_MISS_LIMIT = 0.3;
|
|
1296
|
+
INDEX_PASS_MISS_LIMIT = 0.75;
|
|
1297
|
+
__name(slotOf, "slotOf");
|
|
1298
|
+
__name(slotsFor, "slotsFor");
|
|
1299
|
+
__name(shareOf, "shareOf");
|
|
1300
|
+
SlotPool = class {
|
|
1301
|
+
static {
|
|
1302
|
+
__name(this, "SlotPool");
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* @param {number} [slots] How many there are to give.
|
|
1306
|
+
*/
|
|
1307
|
+
constructor(slots = TOTAL_SLOTS) {
|
|
1308
|
+
this.left = slots;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Takes slots, if there are that many left.
|
|
1312
|
+
*
|
|
1313
|
+
* @param {number} slots How many.
|
|
1314
|
+
* @return {boolean} Whether they were taken.
|
|
1315
|
+
*/
|
|
1316
|
+
take(slots) {
|
|
1317
|
+
if (slots > this.left) {
|
|
1318
|
+
return false;
|
|
1319
|
+
}
|
|
1320
|
+
this.left -= slots;
|
|
1321
|
+
return true;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Gives slots back.
|
|
1325
|
+
*
|
|
1326
|
+
* @param {number} slots How many.
|
|
1327
|
+
*/
|
|
1328
|
+
give(slots) {
|
|
1329
|
+
this.left += slots;
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
SeenNumbers = class _SeenNumbers {
|
|
1333
|
+
static {
|
|
1334
|
+
__name(this, "SeenNumbers");
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* @param {number} slots How many slots: a power of two from `MIN_SLOTS` to `MAX_SLOTS`, already taken from
|
|
1338
|
+
* `pool`.
|
|
1339
|
+
* @param {number} maxSlots The most it may grow to, in the symbol table pass.
|
|
1340
|
+
* @param {number} limit The share of its lookups a judged window may miss.
|
|
1341
|
+
* @param {SlotPool} pool Where its slots came from, and where they go back when it is switched off.
|
|
1342
|
+
* @param {number} [symbols] In the index table pass, the column's symbols, one bit each. -1, the default, in
|
|
1343
|
+
* the symbol table pass.
|
|
1344
|
+
*/
|
|
1345
|
+
constructor(slots, maxSlots, limit, pool, symbols = -1) {
|
|
1346
|
+
this.values = new Float64Array(slots).fill(NaN);
|
|
1347
|
+
this.indices = new Int32Array(symbols >= 0 ? slots : 0);
|
|
1348
|
+
this.met = new Uint32Array(symbols >= 0 ? Math.ceil(symbols / 32) : 0);
|
|
1349
|
+
this.mask = slots - 1;
|
|
1350
|
+
this.maxSlots = maxSlots;
|
|
1351
|
+
this.limit = limit;
|
|
1352
|
+
this.pool = pool;
|
|
1353
|
+
this.cells = 0;
|
|
1354
|
+
this.judgedCells = 0;
|
|
1355
|
+
this.misses = 0;
|
|
1356
|
+
this.judged = symbols >= 0;
|
|
1357
|
+
this.inserted = 0;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Remembers a number the symbol table pass has just put in the map, growing the table instead once more
|
|
1361
|
+
* than an eighth of its slots would hold distinct numbers - if its pool has the slots. A table the pool
|
|
1362
|
+
* cannot grow stops trying, and keeps remembering in the slots it has.
|
|
1363
|
+
*
|
|
1364
|
+
* @param {number} slot The number's slot, from `slotOf`.
|
|
1365
|
+
* @param {number} value The number.
|
|
1366
|
+
* @return {SeenNumbers} The table to use from now on: this one, or a larger, empty one.
|
|
1367
|
+
*/
|
|
1368
|
+
remember(slot, value) {
|
|
1369
|
+
this.inserted++;
|
|
1370
|
+
if (this.inserted * SLOTS_PER_NUMBER > this.values.length && this.values.length < this.maxSlots) {
|
|
1371
|
+
const slots = Math.min(this.values.length * 4, this.maxSlots);
|
|
1372
|
+
if (this.pool.take(slots - this.values.length)) {
|
|
1373
|
+
const grown = new _SeenNumbers(slots, this.maxSlots, this.limit, this.pool);
|
|
1374
|
+
grown.inserted = this.inserted;
|
|
1375
|
+
grown.cells = this.cells;
|
|
1376
|
+
grown.judgedCells = this.judgedCells;
|
|
1377
|
+
grown.misses = this.misses;
|
|
1378
|
+
grown.judged = this.judged;
|
|
1379
|
+
return grown;
|
|
1380
|
+
}
|
|
1381
|
+
this.maxSlots = this.values.length;
|
|
1382
|
+
}
|
|
1383
|
+
this.values[slot] = value;
|
|
1384
|
+
return this;
|
|
1385
|
+
}
|
|
1386
|
+
/**
|
|
1387
|
+
* Marks a symbol met through this table, in the index table pass.
|
|
1388
|
+
*
|
|
1389
|
+
* @param {number} index The symbol the map answered.
|
|
1390
|
+
* @return {boolean} Whether it had been met before; false for a first sight.
|
|
1391
|
+
*/
|
|
1392
|
+
metBefore(index) {
|
|
1393
|
+
const word = index >>> 5;
|
|
1394
|
+
const bit = 1 << (index & 31);
|
|
1395
|
+
const before = (this.met[word] & bit) !== 0;
|
|
1396
|
+
this.met[word] |= bit;
|
|
1397
|
+
return before;
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
NO_TABLE_YET = new SeenNumbers(1, 1, 0, new SlotPool(1));
|
|
1401
|
+
__name(symbolPassTable, "symbolPassTable");
|
|
1402
|
+
__name(numericCellsAfter, "numericCellsAfter");
|
|
1403
|
+
__name(numbersIn, "numbersIn");
|
|
1404
|
+
__name(indexPassWants, "indexPassWants");
|
|
1405
|
+
__name(indexPassTable, "indexPassTable");
|
|
1406
|
+
__name(endWindow, "endWindow");
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1204
1410
|
// src/QvdFileWriter.js
|
|
1205
1411
|
var QvdFileWriter_exports = {};
|
|
1206
1412
|
__export(QvdFileWriter_exports, {
|
|
@@ -1488,6 +1694,7 @@ var init_QvdFileWriter = __esm({
|
|
|
1488
1694
|
init_cellRules();
|
|
1489
1695
|
init_symbolBytes();
|
|
1490
1696
|
init_storedSymbols();
|
|
1697
|
+
init_seenNumbers();
|
|
1491
1698
|
__name(notXmlIndex, "notXmlIndex");
|
|
1492
1699
|
__name(checkHeaderText, "checkHeaderText");
|
|
1493
1700
|
__name(checkHeaderTexts, "checkHeaderTexts");
|
|
@@ -1950,7 +2157,14 @@ var init_QvdFileWriter = __esm({
|
|
|
1950
2157
|
const byCells = state.map((column) => column.byCell);
|
|
1951
2158
|
const byObjects = state.map((column) => column.byObject);
|
|
1952
2159
|
const containsNull = columns.map(() => false);
|
|
2160
|
+
const pool = new SlotPool();
|
|
2161
|
+
const seen = columns.map(() => NO_TABLE_YET);
|
|
2162
|
+
const firstJudgement = firstJudgementRow(numRows);
|
|
2163
|
+
const stopped = columns.map(() => null);
|
|
1953
2164
|
for (let row = 0; row < numRows; row++) {
|
|
2165
|
+
if (row % WINDOW_ROWS === 0 && row !== 0 || row === firstJudgement) {
|
|
2166
|
+
endWindow(seen, row, stopped);
|
|
2167
|
+
}
|
|
1954
2168
|
const values = data[row];
|
|
1955
2169
|
if (values !== null && values !== void 0 && !Array.isArray(values)) {
|
|
1956
2170
|
throw new exports.QvdValidationError("Each row must be an array of values", {
|
|
@@ -1981,7 +2195,34 @@ var init_QvdFileWriter = __esm({
|
|
|
1981
2195
|
}
|
|
1982
2196
|
continue;
|
|
1983
2197
|
}
|
|
2198
|
+
let table = null;
|
|
2199
|
+
let slot = 0;
|
|
2200
|
+
if (typeof value === "number") {
|
|
2201
|
+
table = seen[column];
|
|
2202
|
+
if (table !== null) {
|
|
2203
|
+
table.cells++;
|
|
2204
|
+
slot = slotOf(value, table.mask);
|
|
2205
|
+
if (table.values[slot] === value) {
|
|
2206
|
+
continue;
|
|
2207
|
+
}
|
|
2208
|
+
table.misses++;
|
|
2209
|
+
if (table === NO_TABLE_YET) {
|
|
2210
|
+
table = symbolPassTable(numRows, pool);
|
|
2211
|
+
seen[column] = table;
|
|
2212
|
+
if (table === null) {
|
|
2213
|
+
stopped[column] = { row, cells: 0 };
|
|
2214
|
+
} else {
|
|
2215
|
+
table.cells = 1;
|
|
2216
|
+
table.misses = 1;
|
|
2217
|
+
slot = slotOf(value, table.mask);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
1984
2222
|
if (byCells[column].has(value)) {
|
|
2223
|
+
if (table !== null) {
|
|
2224
|
+
table.values[slot] = value;
|
|
2225
|
+
}
|
|
1985
2226
|
continue;
|
|
1986
2227
|
}
|
|
1987
2228
|
if (typeof value === "number") {
|
|
@@ -2001,6 +2242,9 @@ var init_QvdFileWriter = __esm({
|
|
|
2001
2242
|
refuseCell(value, columns[column], row, this._path);
|
|
2002
2243
|
}
|
|
2003
2244
|
byCells[column].set(value, slotForCell(state[column], value, row, this._path));
|
|
2245
|
+
if (table !== null && typeof value === "number") {
|
|
2246
|
+
seen[column] = table.remember(slot, value);
|
|
2247
|
+
}
|
|
2004
2248
|
}
|
|
2005
2249
|
}
|
|
2006
2250
|
const columnBuffers = [];
|
|
@@ -2009,10 +2253,12 @@ var init_QvdFileWriter = __esm({
|
|
|
2009
2253
|
const { keys, texts } = state[column];
|
|
2010
2254
|
const kinds = new Uint8Array(keys.length);
|
|
2011
2255
|
let byteLength = 0;
|
|
2256
|
+
let numberKeys = 0;
|
|
2012
2257
|
for (let slot = 0; slot < keys.length; slot++) {
|
|
2013
2258
|
const key = keys[slot];
|
|
2014
2259
|
const text = texts[slot];
|
|
2015
2260
|
if (typeof key === "number") {
|
|
2261
|
+
numberKeys++;
|
|
2016
2262
|
if (numberProblem(key) !== null) {
|
|
2017
2263
|
checkNumber(key, null, { column: columns[column], file: this._path, stage: "buildSymbolTable" });
|
|
2018
2264
|
}
|
|
@@ -2041,10 +2287,20 @@ var init_QvdFileWriter = __esm({
|
|
|
2041
2287
|
this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);
|
|
2042
2288
|
this._symbolCounts?.push(keys.length);
|
|
2043
2289
|
this._symbolFacts?.push(state[column].facts);
|
|
2290
|
+
const numbers = state[column].byCell === state[column].byKey ? numberKeys : numbersIn(state[column].byCell);
|
|
2291
|
+
const table = seen[column];
|
|
2044
2292
|
this._symbolIndexByValue?.push({
|
|
2045
2293
|
byCell: state[column].byCell,
|
|
2046
2294
|
byKey: state[column].byKey,
|
|
2047
|
-
byObject: state[column].byObject
|
|
2295
|
+
byObject: state[column].byObject,
|
|
2296
|
+
numbers,
|
|
2297
|
+
cells: table === NO_TABLE_YET ? 0 : table !== null ? table.cells : numericCellsAfter(
|
|
2298
|
+
data,
|
|
2299
|
+
column,
|
|
2300
|
+
/** @type {{row: number, cells: number}} */
|
|
2301
|
+
stopped[column],
|
|
2302
|
+
numbers
|
|
2303
|
+
)
|
|
2048
2304
|
});
|
|
2049
2305
|
symbolsOffset += byteLength;
|
|
2050
2306
|
this._emitProgress("symbol-table", column + 1, numColumns);
|
|
@@ -2094,7 +2350,7 @@ var init_QvdFileWriter = __esm({
|
|
|
2094
2350
|
const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;
|
|
2095
2351
|
const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);
|
|
2096
2352
|
const lookup = this._symbolIndexByValue[column];
|
|
2097
|
-
const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] :
|
|
2353
|
+
const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] : [lookup.byCell, lookup.byKey, lookup.byObject];
|
|
2098
2354
|
for (const map of maps) {
|
|
2099
2355
|
for (const index of map.values()) {
|
|
2100
2356
|
if (index + nullShift > maxStoredIndex) {
|
|
@@ -2120,14 +2376,44 @@ var init_QvdFileWriter = __esm({
|
|
|
2120
2376
|
const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);
|
|
2121
2377
|
const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);
|
|
2122
2378
|
const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);
|
|
2379
|
+
const symbolCounts = this._symbolCounts;
|
|
2380
|
+
const wanted = this._symbolIndexByValue.map((lookup) => indexPassWants(lookup.numbers, lookup.cells));
|
|
2381
|
+
const share = shareOf(wanted.filter(Boolean).length);
|
|
2382
|
+
const pool = new SlotPool();
|
|
2383
|
+
const seen = this._symbolIndexByValue.map(
|
|
2384
|
+
(lookup, column) => wanted[column] ? indexPassTable(lookup.numbers, lookup.cells, symbolCounts[column], share, pool) : null
|
|
2385
|
+
);
|
|
2386
|
+
const firstJudgement = firstJudgementRow(numRows);
|
|
2123
2387
|
for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {
|
|
2388
|
+
if (row % WINDOW_ROWS === 0 && row !== 0 || row === firstJudgement) {
|
|
2389
|
+
endWindow(seen);
|
|
2390
|
+
}
|
|
2124
2391
|
const values = data[row];
|
|
2125
2392
|
for (let column = 0; column < numColumns; column++) {
|
|
2126
2393
|
const value = values?.[column];
|
|
2127
2394
|
if (value === null || value === void 0) {
|
|
2128
2395
|
continue;
|
|
2129
2396
|
}
|
|
2130
|
-
const
|
|
2397
|
+
const table = typeof value === "number" ? seen[column] : null;
|
|
2398
|
+
let index;
|
|
2399
|
+
if (table !== null) {
|
|
2400
|
+
table.cells++;
|
|
2401
|
+
const slot = slotOf(value, table.mask);
|
|
2402
|
+
if (table.values[slot] === value) {
|
|
2403
|
+
index = table.indices[slot];
|
|
2404
|
+
} else {
|
|
2405
|
+
index = byCells[column].get(value);
|
|
2406
|
+
if (index !== void 0) {
|
|
2407
|
+
table.values[slot] = value;
|
|
2408
|
+
table.indices[slot] = index;
|
|
2409
|
+
if (table.metBefore(index)) {
|
|
2410
|
+
table.misses++;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
} else {
|
|
2415
|
+
index = typeof value === "object" ? byObjects[column].get(value) ?? byKeys[column].get(value.number) : byCells[column].get(value);
|
|
2416
|
+
}
|
|
2131
2417
|
if (index === void 0) {
|
|
2132
2418
|
throw new exports.QvdValidationError("A value is missing from the symbol table", {
|
|
2133
2419
|
field: columns[column],
|
|
@@ -5141,12 +5427,14 @@ var init_QvdFileReader = __esm({
|
|
|
5141
5427
|
* viewer scrolls to - and the header is already in hand. `parseHeaderOnly` has to have run.
|
|
5142
5428
|
*
|
|
5143
5429
|
* @param {QvdRowWindow} window The rows the read would cover, normalised.
|
|
5144
|
-
* @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean
|
|
5145
|
-
* `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask
|
|
5146
|
-
* one this reader was built for, which is what a `QvdFile` does per call
|
|
5430
|
+
* @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean,
|
|
5431
|
+
* paging?: boolean}} [options] `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask
|
|
5432
|
+
* about a read other than the one this reader was built for, which is what a `QvdFile` does per call;
|
|
5433
|
+
* `paging` to say whether the read being asked about is a paging read, which defaults to whether this
|
|
5434
|
+
* reader is one.
|
|
5147
5435
|
* @return {any} The answer - see `checkMemory`.
|
|
5148
5436
|
*/
|
|
5149
|
-
checkParsed(window, { chunkSize = null, fields = void 0, materialisesRows = void 0 } = {}) {
|
|
5437
|
+
checkParsed(window, { chunkSize = null, fields = void 0, materialisesRows = void 0, paging = this._symbolCache !== null } = {}) {
|
|
5150
5438
|
assert4__default.default(this._header && this._allFields, "The QVD file header has not been parsed.");
|
|
5151
5439
|
const header = this._header["QvdTableHeader"];
|
|
5152
5440
|
const totalRows = headerInteger(header["NoOfRecords"]);
|
|
@@ -5157,15 +5445,13 @@ var init_QvdFileReader = __esm({
|
|
|
5157
5445
|
const resolved = resolveWindow(window, totalRows);
|
|
5158
5446
|
const windowRows = resolved.limit;
|
|
5159
5447
|
const liveRows = chunkSize === null ? null : { rows: chunkSize * 2, perChunk: 2 };
|
|
5160
|
-
const analysisAhead = this.
|
|
5448
|
+
const analysisAhead = paging ? false : this._analysisWouldRun(window, resolved, totalRows, symbolTableLength);
|
|
5161
5449
|
const measured = getMemoryBudget();
|
|
5162
5450
|
const ask = /* @__PURE__ */ __name((asked, rows) => {
|
|
5163
|
-
const
|
|
5164
|
-
const
|
|
5165
|
-
const
|
|
5166
|
-
|
|
5167
|
-
symbolTableLength
|
|
5168
|
-
);
|
|
5451
|
+
const held = paging ? this._fieldsHeldAfter(asked, this._allFields) : asked;
|
|
5452
|
+
const bytes = symbolBytesOf(held, symbolTableLength);
|
|
5453
|
+
const read = symbolBytesOf(paging ? this._fieldsReadBy(asked) : asked, symbolTableLength);
|
|
5454
|
+
const retained = paging ? symbolBytesOf(held.slice(asked.length), symbolTableLength) : 0;
|
|
5169
5455
|
return checkMemory({
|
|
5170
5456
|
measured,
|
|
5171
5457
|
symbolTableSize: bytes,
|
|
@@ -5176,7 +5462,7 @@ var init_QvdFileReader = __esm({
|
|
|
5176
5462
|
materialisesRows: builds,
|
|
5177
5463
|
live: liveRows,
|
|
5178
5464
|
// A paging read keeps whole columns, so it is charged for whole columns - see `estimateMemoryUsage`.
|
|
5179
|
-
wholeSymbols:
|
|
5465
|
+
wholeSymbols: paging,
|
|
5180
5466
|
retainedBytes: retained,
|
|
5181
5467
|
bytesHeld: this._bytesHeld(read, rows, recordSize, liveRows, analysisAhead, bytes - retained),
|
|
5182
5468
|
// What it reads from the file, which is not what it holds: the symbol areas it has still to read,
|
|
@@ -5511,12 +5797,16 @@ var init_QvdFile = __esm({
|
|
|
5511
5797
|
/**
|
|
5512
5798
|
* What a read of this file would cost, and whether it fits - with no I/O at all.
|
|
5513
5799
|
*
|
|
5514
|
-
*
|
|
5515
|
-
*
|
|
5800
|
+
* Without `chunkSize` it asks about a page, and answers for the page this file would read next: the
|
|
5801
|
+
* columns it names plus the ones earlier pages decoded and kept, since those are part of what the page
|
|
5802
|
+
* costs. With `chunkSize` it asks about an `iterate()` of the file instead - which this object cannot
|
|
5803
|
+
* make, but a caller holding it may want to weigh - and answers exactly as `QvdDataFrame.checkRead()`
|
|
5804
|
+
* would, from the header this file already holds rather than by reading it again.
|
|
5516
5805
|
*
|
|
5517
5806
|
* @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,
|
|
5518
5807
|
* as?: 'rows'|'columns', chunkSize?: number|null}} [options] The read being asked about - the same
|
|
5519
|
-
* bag `rows()` takes, plus `as`
|
|
5808
|
+
* bag `rows()` takes, plus `as` to say which shape of page, and `chunkSize` to ask about an
|
|
5809
|
+
* `iterate()` of the file rather than a page.
|
|
5520
5810
|
* @return {any} The answer - `fits`, `reason`, `estimate`, `budget`, `exact`, `suggestions`.
|
|
5521
5811
|
* @throws {QvdValidationError} If the file is closed, or an option's value is not valid.
|
|
5522
5812
|
*/
|
|
@@ -5535,7 +5825,7 @@ var init_QvdFile = __esm({
|
|
|
5535
5825
|
if (chunkSize !== null) {
|
|
5536
5826
|
requireChunkSize(chunkSize, this._options.path);
|
|
5537
5827
|
}
|
|
5538
|
-
const reader = this._readers[as] ?? this._reader;
|
|
5828
|
+
const reader = chunkSize !== null ? this._reader : this._readers[as] ?? this._reader;
|
|
5539
5829
|
return reader.checkParsed(normaliseWindow(windowFrom(options), this._options.path), {
|
|
5540
5830
|
chunkSize,
|
|
5541
5831
|
// Resolved here rather than left to the reader, exactly as `_page` resolves it. A warm reader is
|
|
@@ -5544,7 +5834,12 @@ var init_QvdFile = __esm({
|
|
|
5544
5834
|
// file after a page naming one of them, it reported 27,490 bytes for a read that costs 108,160:
|
|
5545
5835
|
// understating, which is the direction that approves a read the read then refuses.
|
|
5546
5836
|
fields: options.fields === void 0 ? this._options.fields ?? null : options.fields,
|
|
5547
|
-
materialisesRows: as === "rows"
|
|
5837
|
+
materialisesRows: as === "rows",
|
|
5838
|
+
// Said outright rather than read off the reader. The header reader has paging on, because a check
|
|
5839
|
+
// made before the first page has to be priced as that page will be - so it cannot tell an `iterate()`
|
|
5840
|
+
// question from a page one by its own mode, and routing to it alone still priced the iterate as a
|
|
5841
|
+
// page wherever a bounded window would have been filtered.
|
|
5842
|
+
...chunkSize === null ? {} : { paging: false }
|
|
5548
5843
|
});
|
|
5549
5844
|
}
|
|
5550
5845
|
/**
|