qvdjs 2.2.2 → 2.2.4
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/README.md +14 -11
- package/dist/index.cjs +289 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +289 -3
- 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],
|