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/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] : Object.values(lookup);
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 index = typeof value === "object" ? byObjects[column].get(value) ?? byKeys[column].get(value.number) : byCells[column].get(value);
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],